From 092430b102b75b65146af0e2887ad8eef90f4b04 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 30 Jul 2020 09:59:13 -0400 Subject: [PATCH 001/130] 6639 refactor to allow for artifact type filters --- .../AbstractDiscoveryFilterPanel.java | 6 +- .../autopsy/discovery/AbstractFilter.java | 62 +++++++++++++ .../discovery/AbstractFiltersPanel.java | 16 +++- .../autopsy/discovery/ArtifactSearchData.java | 82 +++++++++++++++++ .../discovery/Bundle.properties-MERGED | 2 + .../discovery/DataSourceFilterPanel.java | 4 +- .../autopsy/discovery/DiscoveryDialog.java | 2 +- .../discovery/DiscoveryEventUtils.java | 12 +-- .../discovery/DiscoveryTopComponent.java | 3 +- .../discovery/DocumentFilterPanel.java | 5 + .../autopsy/discovery/DomainFilterPanel.form | 28 ++++++ .../autopsy/discovery/DomainFilterPanel.java | 58 ++++++++++++ .../autopsy/discovery/FileSearch.java | 16 ++-- .../autopsy/discovery/FileSearchData.java | 21 ++--- .../autopsy/discovery/GroupListPanel.java | 2 +- .../autopsy/discovery/HashSetFilterPanel.java | 4 +- .../autopsy/discovery/ImageFilterPanel.java | 5 + .../InterestingItemsFilterPanel.java | 4 +- .../discovery/ObjectDetectedFilterPanel.java | 4 +- .../autopsy/discovery/PageWorker.java | 4 +- .../discovery/ParentFolderFilterPanel.java | 14 +-- .../discovery/PastOccurrencesFilterPanel.java | 4 +- .../autopsy/discovery/ResultsPanel.java | 2 +- .../autopsy/discovery/SearchData.java | 19 ++++ ...rchFiltering.java => SearchFiltering.java} | 91 ++++--------------- .../autopsy/discovery/SearchWorker.java | 4 +- .../autopsy/discovery/SizeFilterPanel.java | 4 +- .../discovery/UserCreatedFilterPanel.java | 4 +- .../autopsy/discovery/VideoFilterPanel.java | 5 + 29 files changed, 353 insertions(+), 134 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/AbstractFilter.java create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/ArtifactSearchData.java create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.form create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/SearchData.java rename Core/src/org/sleuthkit/autopsy/discovery/{FileSearchFiltering.java => SearchFiltering.java} (91%) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/AbstractDiscoveryFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/AbstractDiscoveryFilterPanel.java index 24d8a8e946..36e0318a75 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/AbstractDiscoveryFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/AbstractDiscoveryFilterPanel.java @@ -90,12 +90,12 @@ abstract class AbstractDiscoveryFilterPanel extends javax.swing.JPanel { } /** - * Get the FileFilter which is represented by this Panel. + * Get the AbstractFilter which is represented by this Panel. * - * @return The FileFilter for the selected settings, null if the settings + * @return The AbstractFilter for the selected settings, null if the settings * are not in use. */ - abstract FileSearchFiltering.FileFilter getFilter(); + abstract AbstractFilter getFilter(); /** * Remove listeners from the checkbox and the list if they exist. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/AbstractFilter.java b/Core/src/org/sleuthkit/autopsy/discovery/AbstractFilter.java new file mode 100644 index 0000000000..39826ca36a --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/AbstractFilter.java @@ -0,0 +1,62 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.discovery; + +import java.util.ArrayList; +import java.util.List; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.datamodel.SleuthkitCase; + +/** + * Base class for the filters. + */ +abstract class AbstractFilter { + + /** + * Returns part of a query on the tsk_files table that can be AND-ed with + * other pieces + * + * @return the SQL query or an empty string if there is no SQL query for + * this filter. + */ + abstract String getWhereClause(); + + /** + * Indicates whether this filter needs to use the secondary, non-SQL method + * applyAlternateFilter(). + * + * @return false by default + */ + boolean useAlternateFilter() { + return false; + } + + /** + * Run a secondary filter that does not operate on tsk_files. + * + * @param currentResults The current list of matching files; empty if no + * filters have yet been run. + * @param caseDb The case database + * @param centralRepoDb The central repo database. Can be null if the + * filter does not require it. + * + * @return The list of files that match this filter (and any that came + * before it) + * + * @throws FileSearchException + */ + List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, + CentralRepository centralRepoDb) throws FileSearchException { + return new ArrayList<>(); + } + + /** + * Get a description of the selected filter. + * + * @return A description of the filter + */ + abstract String getDesc(); +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java index 2f718c3aa5..e36963feac 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java @@ -61,6 +61,8 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li secondColumnPanel.setLayout(new GridBagLayout()); } + abstract SearchData.ResultType getResultType(); + /** * Get the type of results this filters panel is for. * @@ -242,12 +244,18 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li * * @return The list of filters selected by the user. */ - synchronized List getFilters() { - List filtersToUse = new ArrayList<>(); - filtersToUse.add(new FileSearchFiltering.FileTypeFilter(getFileType())); + synchronized List getFilters() { + + List filtersToUse = new ArrayList<>(); + if (getResultType().equals(SearchData.ResultType.FILE)) { + filtersToUse.add(new SearchFiltering.FileTypeFilter(getFileType())); + } else if (getResultType().equals(SearchData.ResultType.ARTIFACT)){ + + } + for (AbstractDiscoveryFilterPanel filterPanel : filters) { if (filterPanel.getCheckbox().isSelected()) { - FileSearchFiltering.FileFilter filter = filterPanel.getFilter(); + AbstractFilter filter = filterPanel.getFilter(); if (filter != null) { filtersToUse.add(filter); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ArtifactSearchData.java b/Core/src/org/sleuthkit/autopsy/discovery/ArtifactSearchData.java new file mode 100644 index 0000000000..a4e84b3242 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/ArtifactSearchData.java @@ -0,0 +1,82 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.discovery; + +import org.openide.util.NbBundle; +import org.sleuthkit.datamodel.BlackboardArtifact; + +/** + * Utility enums for searches made for artifacts with Discovery. + */ +public class ArtifactSearchData extends SearchData { + + + @Override + ResultType getResultType(){ + return ResultType.ARTIFACT; + } + + + /** + * Enum representing the file type. We don't simply use + * FileTypeUtils.FileTypeCategory because: - Some file types categories + * overlap - It is convenient to have the "OTHER" option for files that + * don't match the given types + */ + @NbBundle.Messages({ + "ArtifactSearchData.ArtifactType.Domain.displayName=Domain", + "ArtifactSearchData.ArtifactType.Other.displayName=Other"}) + enum ArtifactType { + + DOMAIN(0, Bundle.ArtifactSearchData_ArtifactType_Domain_displayName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK), + OTHER(1, Bundle.ArtifactSearchData_ArtifactType_Other_displayName(), null); + + private final int ranking; // For ordering in the UI + private final String displayName; + private final BlackboardArtifact.ARTIFACT_TYPE artifactType; + + ArtifactType(int value, String displayName, BlackboardArtifact.ARTIFACT_TYPE type) { + this.ranking = value; + this.displayName = displayName; + this.artifactType = type; + } + + /** + * Get the MIME types matching this category. + * + * @return Collection of MIME type strings + */ + BlackboardArtifact.ARTIFACT_TYPE getMediaTypes() { + return artifactType; + } + + @Override + public String toString() { + return displayName; + } + + /** + * Get the rank for sorting. + * + * @return the rank (lower should be displayed first) + */ + int getRanking() { + return ranking; + } + + + static ArtifactType fromBlackboardArtifact(final BlackboardArtifact.ARTIFACT_TYPE type) { + switch (type) { + case TSK_WEB_BOOKMARK: + return DOMAIN; + default: + return OTHER; + } + } + + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED index a964a1826e..74512110fe 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED @@ -1,3 +1,5 @@ +ArtifactSearchData.ArtifactType.Domain.displayName=Domain +ArtifactSearchData.ArtifactType.Other.displayName=Other CTL_OpenDiscoveryAction=Discovery # {0} - dataSourceName DataSourceModuleWrapper.exifModule.text=Exif Parser module was not run on data source: {0}\n diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DataSourceFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DataSourceFilterPanel.java index a2a2cf4de9..7ecd859e52 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DataSourceFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DataSourceFilterPanel.java @@ -194,10 +194,10 @@ final class DataSourceFilterPanel extends AbstractDiscoveryFilterPanel { } @Override - FileSearchFiltering.FileFilter getFilter() { + AbstractFilter getFilter() { if (dataSourceCheckbox.isSelected()) { List dataSources = dataSourceList.getSelectedValuesList().stream().map(t -> t.getDataSource()).collect(Collectors.toList()); - return new FileSearchFiltering.DataSourceFilter(dataSources); + return new SearchFiltering.DataSourceFilter(dataSources); } return null; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java index 4a2713ba94..8c080e2b18 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java @@ -503,7 +503,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { tc.open(); } tc.resetTopComponent(); - List filters; + List filters; if (videosButton.isSelected()) { filters = videoFilterPanel.getFilters(); } else if (documentsButton.isSelected()) { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java index ea5fca6676..9fb97bc088 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java @@ -116,7 +116,7 @@ final class DiscoveryEventUtils { static final class SearchCompleteEvent { private final Map groupMap; - private final List searchFilters; + private final List searchFilters; private final FileSearch.AttributeType groupingAttribute; private final FileGroup.GroupSortingAlgorithm groupSort; private final FileSorter.SortingMethod fileSortMethod; @@ -132,7 +132,7 @@ final class DiscoveryEventUtils { * @param groupSort The sorting algorithm used for groups. * @param fileSortMethod The sorting method used for files. */ - SearchCompleteEvent(Map groupMap, List searchfilters, + SearchCompleteEvent(Map groupMap, List searchfilters, FileSearch.AttributeType groupingAttribute, FileGroup.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod) { this.groupMap = groupMap; @@ -156,7 +156,7 @@ final class DiscoveryEventUtils { * * @return The search filters which were used by the search. */ - List getFilters() { + List getFilters() { return Collections.unmodifiableList(searchFilters); } @@ -275,7 +275,7 @@ final class DiscoveryEventUtils { private final FileType resultType; private final GroupKey groupKey; private final int groupSize; - private final List searchfilters; + private final List searchfilters; private final FileSearch.AttributeType groupingAttribute; private final FileGroup.GroupSortingAlgorithm groupSort; private final FileSorter.SortingMethod fileSortMethod; @@ -294,7 +294,7 @@ final class DiscoveryEventUtils { * selected. * @param resultType The type of files which exist in the group. */ - GroupSelectedEvent(List searchfilters, + GroupSelectedEvent(List searchfilters, FileSearch.AttributeType groupingAttribute, FileGroup.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod, GroupKey groupKey, int groupSize, FileType resultType) { this.searchfilters = searchfilters; @@ -358,7 +358,7 @@ final class DiscoveryEventUtils { * * @return The search filters which were used by the search. */ - List getFilters() { + List getFilters() { return Collections.unmodifiableList(searchfilters); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java index 633bf5c612..caef97f838 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java @@ -36,7 +36,6 @@ import org.openide.windows.RetainLocation; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.coreutils.ThreadConfined; -import org.sleuthkit.autopsy.discovery.FileSearchFiltering.FileFilter; /** * Create a dialog for displaying the Discovery results. @@ -299,7 +298,7 @@ public final class DiscoveryTopComponent extends TopComponent { void handleSearchCompleteEvent(DiscoveryEventUtils.SearchCompleteEvent searchCompleteEvent) { newSearchButton.setText(Bundle.DiscoveryTopComponent_newSearch_text()); progressMessageTextArea.setForeground(Color.black); - progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchComplete_text(searchCompleteEvent.getFilters().stream().map(FileFilter::getDesc).collect(Collectors.joining("; ")))); + progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchComplete_text(searchCompleteEvent.getFilters().stream().map(AbstractFilter::getDesc).collect(Collectors.joining("; ")))); progressMessageTextArea.setCaretPosition(0); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java index fcd26fed08..015e14e2ab 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java @@ -98,4 +98,9 @@ final class DocumentFilterPanel extends AbstractFiltersPanel { private javax.swing.JSplitPane documentsFiltersSplitPane; // End of variables declaration//GEN-END:variables + @Override + SearchData.ResultType getResultType() { + return SearchData.ResultType.FILE; + } + } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.form new file mode 100644 index 0000000000..4f9abb50dc --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.form @@ -0,0 +1,28 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java new file mode 100644 index 0000000000..f25324f43f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java @@ -0,0 +1,58 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.discovery; + +/** + * + * @author wschaefer + */ +public class DomainFilterPanel extends AbstractFiltersPanel { + + private static final long serialVersionUID = 1L; + private static final ArtifactSearchData.ArtifactType ARTIFACT_TYPE = ArtifactSearchData.ArtifactType.DOMAIN; + + /** + * Creates new form DomainFilterPanel + */ + public DomainFilterPanel() { + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 400, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 300, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + + @Override + FileSearchData.FileType getFileType() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + SearchData.ResultType getResultType() { + return SearchData.ResultType.ARTIFACT; + } + + + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/FileSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/FileSearch.java index 0590351793..a2fad07be3 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/FileSearch.java @@ -122,7 +122,7 @@ class FileSearch { * @throws FileSearchException */ static SearchResults runFileSearchDebug(String userName, - List filters, + List filters, AttributeType groupAttributeType, FileGroup.GroupSortingAlgorithm groupSortingType, FileSorter.SortingMethod fileSortingMethod, @@ -136,7 +136,7 @@ class FileSearch { attributesNeededForGroupingOrSorting.addAll(fileSortingMethod.getRequiredAttributes()); // Run the queries for each filter - List resultFiles = FileSearchFiltering.runQueries(filters, caseDb, centralRepoDb); + List resultFiles = SearchFiltering.runQueries(filters, caseDb, centralRepoDb); // Add the data to resultFiles for any attributes needed for sorting and grouping addAttributes(attributesNeededForGroupingOrSorting, resultFiles, caseDb, centralRepoDb); @@ -174,7 +174,7 @@ class FileSearch { * @throws FileSearchException */ static Map getGroupSizes(String userName, - List filters, + List filters, AttributeType groupAttributeType, FileGroup.GroupSortingAlgorithm groupSortingType, FileSorter.SortingMethod fileSortingMethod, @@ -211,7 +211,7 @@ class FileSearch { * @throws FileSearchException */ static List getFilesInGroup(String userName, - List filters, + List filters, AttributeType groupAttributeType, FileGroup.GroupSortingAlgorithm groupSortingType, FileSorter.SortingMethod fileSortingMethod, @@ -483,7 +483,7 @@ class FileSearch { * @throws FileSearchException */ private static Map> runFileSearch(String userName, - List filters, + List filters, AttributeType groupAttributeType, FileGroup.GroupSortingAlgorithm groupSortingType, FileSorter.SortingMethod fileSortingMethod, @@ -498,7 +498,7 @@ class FileSearch { attributesNeededForGroupingOrSorting.addAll(fileSortingMethod.getRequiredAttributes()); // Run the queries for each filter - List resultFiles = FileSearchFiltering.runQueries(filters, caseDb, centralRepoDb); + List resultFiles = SearchFiltering.runQueries(filters, caseDb, centralRepoDb); // Add the data to resultFiles for any attributes needed for sorting and grouping addAttributes(attributesNeededForGroupingOrSorting, resultFiles, caseDb, centralRepoDb); @@ -2077,13 +2077,13 @@ class FileSearch { * @param groupSortingType The algorithm to sort the groups by. * @param fileSortingMethod The method to sort the files by. */ - SearchKey(String userName, List filters, + SearchKey(String userName, List filters, AttributeType groupAttributeType, FileGroup.GroupSortingAlgorithm groupSortingType, FileSorter.SortingMethod fileSortingMethod) { StringBuilder searchStringBuilder = new StringBuilder(); searchStringBuilder.append(userName); - for (FileSearchFiltering.FileFilter filter : filters) { + for (AbstractFilter filter : filters) { searchStringBuilder.append(filter.toString()); } searchStringBuilder.append(groupAttributeType).append(groupSortingType).append(fileSortingMethod); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/FileSearchData.java b/Core/src/org/sleuthkit/autopsy/discovery/FileSearchData.java index 81bb2ca641..a672930966 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/FileSearchData.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/FileSearchData.java @@ -28,12 +28,17 @@ import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.FileTypeUtils; /** - * Utility enums for FileSearch. + * Utility enums for searches made for files with Discovery. */ -final class FileSearchData { +final class FileSearchData extends SearchData { private final static long BYTES_PER_MB = 1000000; + @Override + ResultType getResultType() { + return ResultType.FILE; + } + /** * Enum representing how often the file occurs in the Central Repository. */ @@ -256,8 +261,8 @@ final class FileSearchData { public String toString() { return sizeGroup + displaySize; } - - String getSizeGroup(){ + + String getSizeGroup() { return sizeGroup; } @@ -384,14 +389,6 @@ final class FileSearchData { return OTHER; } - /** - * Get the list of enums that are valid for filtering. - * - * @return enums that can be used to filter - */ - static List getOptionsForFiltering() { - return Arrays.asList(IMAGE, VIDEO); - } } /** diff --git a/Core/src/org/sleuthkit/autopsy/discovery/GroupListPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/GroupListPanel.java index a71876e88d..2fa91c2380 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/GroupListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/GroupListPanel.java @@ -39,7 +39,7 @@ final class GroupListPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; private FileType resultType = null; private Map groupMap = null; - private List searchfilters; + private List searchfilters; private FileSearch.AttributeType groupingAttribute; private FileGroup.GroupSortingAlgorithm groupSort; private FileSorter.SortingMethod fileSortMethod; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/HashSetFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/HashSetFilterPanel.java index eaad0f06f2..17673cfece 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/HashSetFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/HashSetFilterPanel.java @@ -161,9 +161,9 @@ final class HashSetFilterPanel extends AbstractDiscoveryFilterPanel { } @Override - FileSearchFiltering.FileFilter getFilter() { + AbstractFilter getFilter() { if (hashSetCheckbox.isSelected()) { - return new FileSearchFiltering.HashSetFilter(hashSetList.getSelectedValuesList()); + return new SearchFiltering.HashSetFilter(hashSetList.getSelectedValuesList()); } return null; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.java index dfe8a9de31..fc22e7af8f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.java @@ -103,4 +103,9 @@ final class ImageFilterPanel extends AbstractFiltersPanel { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JSplitPane imageFiltersSplitPane; // End of variables declaration//GEN-END:variables + + @Override + SearchData.ResultType getResultType() { + return SearchData.ResultType.FILE; + } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/InterestingItemsFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/InterestingItemsFilterPanel.java index a073d6b928..1eea4a020b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/InterestingItemsFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/InterestingItemsFilterPanel.java @@ -163,9 +163,9 @@ final class InterestingItemsFilterPanel extends AbstractDiscoveryFilterPanel { } @Override - FileSearchFiltering.FileFilter getFilter() { + AbstractFilter getFilter() { if (interestingItemsCheckbox.isSelected()) { - return new FileSearchFiltering.InterestingFileSetFilter(interestingItemsList.getSelectedValuesList()); + return new SearchFiltering.InterestingFileSetFilter(interestingItemsList.getSelectedValuesList()); } return null; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ObjectDetectedFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ObjectDetectedFilterPanel.java index 335ca8af43..a87c826f33 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ObjectDetectedFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ObjectDetectedFilterPanel.java @@ -167,9 +167,9 @@ final class ObjectDetectedFilterPanel extends AbstractDiscoveryFilterPanel { } @Override - FileSearchFiltering.FileFilter getFilter() { + AbstractFilter getFilter() { if (objectsCheckbox.isSelected()) { - return new FileSearchFiltering.ObjectDetectionFilter(objectsList.getSelectedValuesList()); + return new SearchFiltering.ObjectDetectionFilter(objectsList.getSelectedValuesList()); } return null; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/PageWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/PageWorker.java index 6eda6c6c3a..52418bef11 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/PageWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/PageWorker.java @@ -34,7 +34,7 @@ final class PageWorker extends SwingWorker { private final static Logger logger = Logger.getLogger(PageWorker.class.getName()); private static final String USER_NAME_PROPERTY = "user.name"; //NON-NLS - private final List searchfilters; + private final List searchfilters; private final FileSearch.AttributeType groupingAttribute; private final FileGroup.GroupSortingAlgorithm groupSort; private final FileSorter.SortingMethod fileSortMethod; @@ -61,7 +61,7 @@ final class PageWorker extends SwingWorker { * @param resultType The type of files which exist in the group. * @param centralRepo The central repository to be used. */ - PageWorker(List searchfilters, FileSearch.AttributeType groupingAttribute, + PageWorker(List searchfilters, FileSearch.AttributeType groupingAttribute, FileGroup.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod, GroupKey groupKey, int startingEntry, int pageSize, FileSearchData.FileType resultType, CentralRepository centralRepo) { this.searchfilters = searchfilters; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.java index 7f10b38692..3df211b2d0 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.java @@ -24,7 +24,7 @@ import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; -import org.sleuthkit.autopsy.discovery.FileSearchFiltering.ParentSearchTerm; +import org.sleuthkit.autopsy.discovery.SearchFiltering.ParentSearchTerm; /** * Panel to allow configuration of the Parent Folder filter. @@ -32,7 +32,7 @@ import org.sleuthkit.autopsy.discovery.FileSearchFiltering.ParentSearchTerm; final class ParentFolderFilterPanel extends AbstractDiscoveryFilterPanel { private static final long serialVersionUID = 1L; - private DefaultListModel parentListModel; + private DefaultListModel parentListModel; private static final String[] DEFAULT_IGNORED_PATHS = {"/Windows/", "/Program Files/"}; //NON-NLS /** @@ -49,7 +49,7 @@ final class ParentFolderFilterPanel extends AbstractDiscoveryFilterPanel { private void setUpParentPathFilter() { fullRadioButton.setSelected(true); includeRadioButton.setSelected(true); - parentListModel = (DefaultListModel) parentList.getModel(); + parentListModel = (DefaultListModel) parentList.getModel(); for (String ignorePath : DEFAULT_IGNORED_PATHS) { parentListModel.add(parentListModel.size(), new ParentSearchTerm(ignorePath, false, false)); } @@ -291,8 +291,8 @@ final class ParentFolderFilterPanel extends AbstractDiscoveryFilterPanel { * * @return The list of entered ParentSearchTerm objects */ - private List getParentPaths() { - List results = new ArrayList<>(); + private List getParentPaths() { + List results = new ArrayList<>(); for (int i = 0; i < parentListModel.getSize(); i++) { results.add(parentListModel.get(i)); } @@ -305,9 +305,9 @@ final class ParentFolderFilterPanel extends AbstractDiscoveryFilterPanel { } @Override - FileSearchFiltering.FileFilter getFilter() { + AbstractFilter getFilter() { if (parentCheckbox.isSelected()) { - return new FileSearchFiltering.ParentFilter(getParentPaths()); + return new SearchFiltering.ParentFilter(getParentPaths()); } return null; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java index f80bfbfad5..a6d3d2b841 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java @@ -154,9 +154,9 @@ final class PastOccurrencesFilterPanel extends AbstractDiscoveryFilterPanel { } @Override - FileSearchFiltering.FileFilter getFilter() { + AbstractFilter getFilter() { if (pastOccurrencesCheckbox.isSelected()) { - return new FileSearchFiltering.FrequencyFilter(crFrequencyList.getSelectedValuesList()); + return new SearchFiltering.FrequencyFilter(crFrequencyList.getSelectedValuesList()); } return null; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.java index fc86f7a963..eb844a7a73 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.java @@ -51,7 +51,7 @@ final class ResultsPanel extends javax.swing.JPanel { private final VideoThumbnailViewer videoThumbnailViewer; private final ImageThumbnailViewer imageThumbnailViewer; private final DocumentPreviewViewer documentPreviewViewer; - private List searchFilters; + private List searchFilters; private FileSearch.AttributeType groupingAttribute; private FileGroup.GroupSortingAlgorithm groupSort; private FileSorter.SortingMethod fileSortMethod; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/SearchData.java b/Core/src/org/sleuthkit/autopsy/discovery/SearchData.java new file mode 100644 index 0000000000..c6700c5a16 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/SearchData.java @@ -0,0 +1,19 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.discovery; + + +abstract class SearchData { + + enum ResultType { + FILE, + ARTIFACT; + } + + abstract ResultType getResultType(); + + +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/FileSearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/SearchFiltering.java similarity index 91% rename from Core/src/org/sleuthkit/autopsy/discovery/FileSearchFiltering.java rename to Core/src/org/sleuthkit/autopsy/discovery/SearchFiltering.java index adf301537a..a21b11fd1e 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/FileSearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/SearchFiltering.java @@ -42,7 +42,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; /** * Run various filters to return a subset of files from the current case. */ -class FileSearchFiltering { +class SearchFiltering { /** * Run the given filters to get a list of matching files. @@ -54,13 +54,13 @@ class FileSearchFiltering { * * @return */ - static List runQueries(List filters, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws FileSearchException { + static List runQueries(List filters, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws FileSearchException { if (caseDb == null) { throw new FileSearchException("Case DB parameter is null"); // NON-NLS } // Combine all the SQL queries from the filters into one query String combinedQuery = ""; - for (FileFilter filter : filters) { + for (AbstractFilter filter : filters) { if (!filter.getWhereClause().isEmpty()) { if (!combinedQuery.isEmpty()) { combinedQuery += " AND "; // NON-NLS @@ -94,7 +94,7 @@ class FileSearchFiltering { * @throws TskCoreException * @throws FileSearchException */ - private static List getResultList(List filters, String combinedQuery, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws TskCoreException, FileSearchException { + private static List getResultList(List filters, String combinedQuery, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws TskCoreException, FileSearchException { // Get all matching abstract files List resultList = new ArrayList<>(); List sqlResults = caseDb.findAllFilesWhere(combinedQuery); @@ -110,7 +110,7 @@ class FileSearchFiltering { } // Now run any non-SQL filters. - for (FileFilter filter : filters) { + for (AbstractFilter filter : filters) { if (filter.useAlternateFilter()) { resultList = filter.applyAlternateFilter(resultList, caseDb, centralRepoDb); } @@ -122,61 +122,10 @@ class FileSearchFiltering { return resultList; } - /** - * Base class for the filters. - */ - static abstract class FileFilter { - - /** - * Returns part of a query on the tsk_files table that can be AND-ed - * with other pieces - * - * @return the SQL query or an empty string if there is no SQL query for - * this filter. - */ - abstract String getWhereClause(); - - /** - * Indicates whether this filter needs to use the secondary, non-SQL - * method applyAlternateFilter(). - * - * @return false by default - */ - boolean useAlternateFilter() { - return false; - } - - /** - * Run a secondary filter that does not operate on tsk_files. - * - * @param currentResults The current list of matching files; empty if no - * filters have yet been run. - * @param caseDb The case database - * @param centralRepoDb The central repo database. Can be null if the - * filter does not require it. - * - * @return The list of files that match this filter (and any that came - * before it) - * - * @throws FileSearchException - */ - List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws FileSearchException { - return new ArrayList<>(); - } - - /** - * Get a description of the selected filter. - * - * @return A description of the filter - */ - abstract String getDesc(); - } - /** * A filter for specifying the file size */ - static class SizeFilter extends FileFilter { + static class SizeFilter extends AbstractFilter { private final List fileSizes; @@ -316,7 +265,7 @@ class FileSearchFiltering { /** * A filter for specifying parent path (either full path or substring) */ - static class ParentFilter extends FileFilter { + static class ParentFilter extends AbstractFilter { private final List parentSearchTerms; @@ -393,7 +342,7 @@ class FileSearchFiltering { /** * A filter for specifying data sources */ - static class DataSourceFilter extends FileFilter { + static class DataSourceFilter extends AbstractFilter { private final List dataSources; @@ -444,7 +393,7 @@ class FileSearchFiltering { * A filter for specifying keyword list names. A file must contain a keyword * from one of the given lists to pass. */ - static class KeywordListFilter extends FileFilter { + static class KeywordListFilter extends AbstractFilter { private final List listNames; @@ -480,7 +429,7 @@ class FileSearchFiltering { /** * A filter for specifying file types. */ - static class FileTypeFilter extends FileFilter { + static class FileTypeFilter extends AbstractFilter { private final List categories; @@ -539,7 +488,7 @@ class FileSearchFiltering { /** * A filter for specifying frequency in the central repository. */ - static class FrequencyFilter extends FileFilter { + static class FrequencyFilter extends AbstractFilter { private final List frequencies; @@ -609,7 +558,7 @@ class FileSearchFiltering { * A filter for specifying hash set names. A file must match one of the * given sets to pass. */ - static class HashSetFilter extends FileFilter { + static class HashSetFilter extends AbstractFilter { private final List setNames; @@ -647,7 +596,7 @@ class FileSearchFiltering { * A filter for specifying interesting file set names. A file must match one * of the given sets to pass. */ - static class InterestingFileSetFilter extends FileFilter { + static class InterestingFileSetFilter extends AbstractFilter { private final List setNames; @@ -685,7 +634,7 @@ class FileSearchFiltering { * A filter for specifying object types detected. A file must match one of * the given types to pass. */ - static class ObjectDetectionFilter extends FileFilter { + static class ObjectDetectionFilter extends AbstractFilter { private final List typeNames; @@ -723,7 +672,7 @@ class FileSearchFiltering { * A filter for specifying the score. A file must have one of the given * scores to pass */ - static class ScoreFilter extends FileFilter { + static class ScoreFilter extends AbstractFilter { private final List scores; @@ -800,7 +749,7 @@ class FileSearchFiltering { * A filter for specifying tag names. A file must contain one of the given * tags to pass. */ - static class TagsFilter extends FileFilter { + static class TagsFilter extends AbstractFilter { private final List tagNames; @@ -849,7 +798,7 @@ class FileSearchFiltering { * A filter for specifying that the file must have user content suspected * data. */ - static class UserCreatedFilter extends FileFilter { + static class UserCreatedFilter extends AbstractFilter { /** * Create the ExifFilter @@ -877,7 +826,7 @@ class FileSearchFiltering { * A filter for specifying that the file must have been marked as notable in * the CR. */ - static class NotableFilter extends FileFilter { + static class NotableFilter extends AbstractFilter { /** * Create the NotableFilter @@ -945,7 +894,7 @@ class FileSearchFiltering { /** * A filter for specifying if known files should be included. */ - static class KnownFilter extends FileFilter { + static class KnownFilter extends AbstractFilter { @Override String getWhereClause() { @@ -992,7 +941,7 @@ class FileSearchFiltering { return result; } - private FileSearchFiltering() { + private SearchFiltering(){ // Class should not be instantiated } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/SearchWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/SearchWorker.java index 1a513afda1..c1877109b5 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/SearchWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/SearchWorker.java @@ -35,7 +35,7 @@ final class SearchWorker extends SwingWorker { private final static Logger logger = Logger.getLogger(SearchWorker.class.getName()); private static final String USER_NAME_PROPERTY = "user.name"; //NON-NLS - private final List filters; + private final List filters; private final FileSearch.AttributeType groupingAttr; private final FileSorter.SortingMethod fileSort; private final FileGroup.GroupSortingAlgorithm groupSortAlgorithm; @@ -52,7 +52,7 @@ final class SearchWorker extends SwingWorker { * @param groupSort The Algorithm to sort groups by. * @param fileSortMethod The SortingMethod to use for files. */ - SearchWorker(CentralRepository centralRepo, List searchfilters, FileSearch.AttributeType groupingAttribute, FileGroup.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod) { + SearchWorker(CentralRepository centralRepo, List searchfilters, FileSearch.AttributeType groupingAttribute, FileGroup.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod) { centralRepoDb = centralRepo; filters = searchfilters; groupingAttr = groupingAttribute; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/SizeFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/SizeFilterPanel.java index 1e78b9a079..c6f0478f38 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/SizeFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/SizeFilterPanel.java @@ -178,9 +178,9 @@ final class SizeFilterPanel extends AbstractDiscoveryFilterPanel { } @Override - FileSearchFiltering.FileFilter getFilter() { + AbstractFilter getFilter() { if (sizeCheckbox.isSelected()) { - return new FileSearchFiltering.SizeFilter(sizeList.getSelectedValuesList()); + return new SearchFiltering.SizeFilter(sizeList.getSelectedValuesList()); } return null; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/UserCreatedFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/UserCreatedFilterPanel.java index 6c0ca9d67a..8f6be8b12b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/UserCreatedFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/UserCreatedFilterPanel.java @@ -98,9 +98,9 @@ final class UserCreatedFilterPanel extends AbstractDiscoveryFilterPanel { } @Override - FileSearchFiltering.FileFilter getFilter() { + AbstractFilter getFilter() { if (userCreatedCheckbox.isSelected()) { - return new FileSearchFiltering.UserCreatedFilter(); + return new SearchFiltering.UserCreatedFilter(); } return null; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java index 97cd8e818d..3cb69f0ff4 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java @@ -105,4 +105,9 @@ final class VideoFilterPanel extends AbstractFiltersPanel { private javax.swing.JSplitPane videoFiltersSplitPane; // End of variables declaration//GEN-END:variables + @Override + SearchData.ResultType getResultType() { + return SearchData.ResultType.FILE; + } + } From c2e0e64ab04874e2b17bf088427963cc7366dbf3 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 5 Aug 2020 13:44:17 -0400 Subject: [PATCH 002/130] 6639 discovery filter panels --- .../discovery/AbstractFiltersPanel.java | 19 ++- .../discovery/ArtifactTypeFilterPanel.form | 53 +++++++ .../discovery/ArtifactTypeFilterPanel.java | 105 ++++++++++++ .../autopsy/discovery/Bundle.properties | 6 + .../discovery/Bundle.properties-MERGED | 7 + .../autopsy/discovery/DateFilterPanel.form | 43 +++++ .../autopsy/discovery/DateFilterPanel.java | 101 ++++++++++++ .../autopsy/discovery/DiscoveryDialog.form | 31 +++- .../autopsy/discovery/DiscoveryDialog.java | 150 ++++++++++++++---- .../discovery/DiscoveryEventUtils.java | 30 +++- .../discovery/DiscoveryTopComponent.java | 12 +- .../discovery/DocumentFilterPanel.java | 5 + .../autopsy/discovery/DomainFilterPanel.form | 84 ++++++++-- .../autopsy/discovery/DomainFilterPanel.java | 70 ++++++-- .../DomainUniquenessFilterPanel.form | 43 +++++ .../DomainUniquenessFilterPanel.java | 101 ++++++++++++ .../autopsy/discovery/GroupListPanel.java | 6 +- .../autopsy/discovery/ImageFilterPanel.java | 5 + .../autopsy/discovery/VideoFilterPanel.java | 5 + 19 files changed, 801 insertions(+), 75 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.form create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.java create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.form create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.java create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.form create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.java diff --git a/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java index e36963feac..6abe6ee557 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java @@ -62,7 +62,7 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li } abstract SearchData.ResultType getResultType(); - + /** * Get the type of results this filters panel is for. * @@ -70,6 +70,13 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li */ abstract FileSearchData.FileType getFileType(); + /** + * Get the type of results this filters panel is for. + * + * @return The type of results this panel filters. + */ + abstract ArtifactSearchData.ArtifactType getArtifactType(); + /** * Add a DiscoveryFilterPanel to the specified column with the specified * settings. @@ -245,14 +252,14 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li * @return The list of filters selected by the user. */ synchronized List getFilters() { - + List filtersToUse = new ArrayList<>(); if (getResultType().equals(SearchData.ResultType.FILE)) { - filtersToUse.add(new SearchFiltering.FileTypeFilter(getFileType())); - } else if (getResultType().equals(SearchData.ResultType.ARTIFACT)){ - + filtersToUse.add(new SearchFiltering.FileTypeFilter(getFileType())); + } else if (getResultType().equals(SearchData.ResultType.ARTIFACT)) { + } - + for (AbstractDiscoveryFilterPanel filterPanel : filters) { if (filterPanel.getCheckbox().isSelected()) { AbstractFilter filter = filterPanel.getFilter(); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.form new file mode 100644 index 0000000000..1e6d77593d --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.form @@ -0,0 +1,53 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.java new file mode 100644 index 0000000000..fb14ceaeef --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.java @@ -0,0 +1,105 @@ +/* + * Autopsy + * + * 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.discovery; + +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JList; + +/** + * + * @author wschaefer + */ +class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { + + private static final long serialVersionUID = 1L; + + /** + * Creates new form ArtifactTypeFilterPanel + */ + ArtifactTypeFilterPanel() { + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + artifactTypeCheckbox = new javax.swing.JCheckBox(); + artifactTypeScrollPane = new javax.swing.JScrollPane(); + + org.openide.awt.Mnemonics.setLocalizedText(artifactTypeCheckbox, org.openide.util.NbBundle.getMessage(ArtifactTypeFilterPanel.class, "ArtifactTypeFilterPanel.artifactTypeCheckbox.text")); // NOI18N + + setPreferredSize(new java.awt.Dimension(27, 27)); + + artifactTypeScrollPane.setPreferredSize(new java.awt.Dimension(27, 27)); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(artifactTypeScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 229, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(artifactTypeScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 38, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + + @Override + void configurePanel(boolean selected, int[] indicesSelected) { + artifactTypeCheckbox.setSelected(selected); + } + + @Override + JCheckBox getCheckbox() { + return artifactTypeCheckbox; + } + + @Override + JList getList() { + return null; + } + + @Override + JLabel getAdditionalLabel() { + return null; + } + + @Override + String checkForError() { + return "Domain search is not implemented."; + } + + @Override + AbstractFilter getFilter() { + return null; + } + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JCheckBox artifactTypeCheckbox; + private javax.swing.JScrollPane artifactTypeScrollPane; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties index 795018f1ac..90e86aab72 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties @@ -104,3 +104,9 @@ DiscoveryDialog.step1Label.text=Step 1: Choose result type ResultsSplitPaneDivider.hideButton.text= ResultsSplitPaneDivider.showButton.text= ResultsSplitPaneDivider.detailsLabel.text=Details Area +DiscoveryDialog.domainsButton.text=Domains +DomainFilterPanel.domainFiltersSplitPane.border.title=Step 2: Filter which domains to show +DomainFilterPanel.domainFiltersSplitPane.toolTipText= +DateFilterPanel.dateFilterCheckbox.text=Date Filter +ArtifactTypeFilterPanel.artifactTypeCheckbox.text=Artifact Type +DomainUniquenessFilterPanel.domainUniquenessCheckbox.text=Domain Uniqueness diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED index 74512110fe..1b61a3f9a6 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED @@ -14,6 +14,7 @@ DiscoveryTopComponent.newSearch.text=New Search DiscoveryTopComponent.searchCancelled.text=Search has been cancelled. # {0} - search DiscoveryTopComponent.searchComplete.text=Results with {0} +DiscoveryTopComponent.searchError.text=Error no type specified for search. # {0} - searchType DiscoveryTopComponent.searchInProgress.text=Performing search for results of type {0}. Please wait. DiscoveryUiUtility.bytes.text=bytes @@ -269,6 +270,12 @@ DiscoveryDialog.step1Label.text=Step 1: Choose result type ResultsSplitPaneDivider.hideButton.text= ResultsSplitPaneDivider.showButton.text= ResultsSplitPaneDivider.detailsLabel.text=Details Area +DiscoveryDialog.domainsButton.text=Domains +DomainFilterPanel.domainFiltersSplitPane.border.title=Step 2: Filter which domains to show +DomainFilterPanel.domainFiltersSplitPane.toolTipText= +DateFilterPanel.dateFilterCheckbox.text=Date Filter +ArtifactTypeFilterPanel.artifactTypeCheckbox.text=Artifact Type +DomainUniquenessFilterPanel.domainUniquenessCheckbox.text=Domain Uniqueness VideoThumbnailPanel.bytes.text=bytes VideoThumbnailPanel.deleted.text=All instances of file are deleted. VideoThumbnailPanel.gigaBytes.text=GB diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.form new file mode 100644 index 0000000000..5e523cc270 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.form @@ -0,0 +1,43 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.java new file mode 100644 index 0000000000..5409cebbdc --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.java @@ -0,0 +1,101 @@ +/* + * Autopsy + * + * 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.discovery; + +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JList; + +/** + * + * @author wschaefer + */ +class DateFilterPanel extends AbstractDiscoveryFilterPanel { + + private static final long serialVersionUID = 1L; + + /** + * Creates new form DateFilterPanel + */ + DateFilterPanel() { + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + dateFilterCheckbox = new javax.swing.JCheckBox(); + dateFilterScrollPane = new javax.swing.JScrollPane(); + + org.openide.awt.Mnemonics.setLocalizedText(dateFilterCheckbox, org.openide.util.NbBundle.getMessage(DateFilterPanel.class, "DateFilterPanel.dateFilterCheckbox.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(dateFilterScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 223, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(dateFilterScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 43, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + + @Override + void configurePanel(boolean selected, int[] indicesSelected) { + dateFilterCheckbox.setSelected(selected); + } + + @Override + JCheckBox getCheckbox() { + return dateFilterCheckbox; + } + + @Override + JList getList() { + return null; + } + + @Override + JLabel getAdditionalLabel() { + return null; + } + + @Override + String checkForError() { + return "Domain search is not implemented."; + } + + @Override + AbstractFilter getFilter() { + return null; + } + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JCheckBox dateFilterCheckbox; + private javax.swing.JScrollPane dateFilterScrollPane; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form index 19116a24fe..f53408d443 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form @@ -48,12 +48,14 @@ - + - + - - + + + + @@ -78,6 +80,7 @@ + @@ -191,6 +194,26 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java index 8c080e2b18..a5884beb61 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java @@ -22,6 +22,7 @@ import static java.awt.BorderLayout.CENTER; import java.awt.Color; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.ArrayList; import java.util.EnumSet; import java.util.HashSet; import java.util.List; @@ -52,7 +53,7 @@ import static org.sleuthkit.autopsy.discovery.FileSorter.SortingMethod.BY_FILE_N * Discovery search. */ final class DiscoveryDialog extends javax.swing.JDialog { - + private static final Set CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.CURRENT_CASE, Case.Events.DATA_SOURCE_ADDED, Case.Events.DATA_SOURCE_DELETED); private static final Set INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED); @@ -61,12 +62,15 @@ final class DiscoveryDialog extends javax.swing.JDialog { private ImageFilterPanel imageFilterPanel = null; private VideoFilterPanel videoFilterPanel = null; private DocumentFilterPanel documentFilterPanel = null; + private DomainFilterPanel domainFilterPanel = null; private static final Color SELECTED_COLOR = new Color(216, 230, 242); private static final Color UNSELECTED_COLOR = new Color(240, 240, 240); private SearchWorker searchWorker = null; private static DiscoveryDialog discDialog; private static volatile boolean shouldUpdate = false; + private SearchData.ResultType resultType = SearchData.ResultType.FILE; private FileSearchData.FileType fileType = FileSearchData.FileType.IMAGE; + private ArtifactSearchData.ArtifactType artifactType = null; private final PropertyChangeListener listener; private final Set objectsDetected = new HashSet<>(); private final Set interestingItems = new HashSet<>(); @@ -122,17 +126,15 @@ final class DiscoveryDialog extends javax.swing.JDialog { imageFilterPanel = new ImageFilterPanel(); videoFilterPanel = new VideoFilterPanel(); documentFilterPanel = new DocumentFilterPanel(); + domainFilterPanel = new DomainFilterPanel(); + unselectAllButtons(); imagesButton.setSelected(true); imagesButton.setEnabled(false); imagesButton.setBackground(SELECTED_COLOR); imagesButton.setForeground(Color.BLACK); - videosButton.setSelected(false); - videosButton.setEnabled(true); - videosButton.setBackground(UNSELECTED_COLOR); - documentsButton.setSelected(false); - documentsButton.setEnabled(true); - documentsButton.setBackground(UNSELECTED_COLOR); + resultType = SearchData.ResultType.FILE; fileType = FileSearchData.FileType.IMAGE; + artifactType = null; add(imageFilterPanel, CENTER); imageFilterPanel.addPropertyChangeListener(listener); updateComboBoxes(); @@ -141,6 +143,21 @@ final class DiscoveryDialog extends javax.swing.JDialog { repaint(); } + private void unselectAllButtons() { + imagesButton.setSelected(false); + imagesButton.setEnabled(true); + imagesButton.setBackground(UNSELECTED_COLOR); + videosButton.setSelected(false); + videosButton.setEnabled(true); + videosButton.setBackground(UNSELECTED_COLOR); + documentsButton.setSelected(false); + documentsButton.setEnabled(true); + documentsButton.setBackground(UNSELECTED_COLOR); + domainsButton.setSelected(false); + domainsButton.setEnabled(true); + domainsButton.setBackground(UNSELECTED_COLOR); + } + /** * Private helper method to perform update of comboboxes update. */ @@ -199,17 +216,31 @@ final class DiscoveryDialog extends javax.swing.JDialog { * Validate the current filter settings of the selected type. */ synchronized void validateDialog() { + switch (resultType) { + case FILE: + validateFileDialog(); + break; + case ARTIFACT: + validateArtifactDialog(); + break; + } + } + + /** + * Validate the filter settings for File type filters. + */ + private synchronized void validateFileDialog() { switch (fileType) { case IMAGE: if (imageFilterPanel != null) { imageFilterPanel.validateFields(); } - return; + break; case VIDEO: if (videoFilterPanel != null) { videoFilterPanel.validateFields(); } - return; + break; case DOCUMENTS: if (documentFilterPanel != null) { documentFilterPanel.validateFields(); @@ -220,6 +251,21 @@ final class DiscoveryDialog extends javax.swing.JDialog { } } + /** + * Validate the filter settings for Artifact type filters. + */ + private synchronized void validateArtifactDialog() { + switch (artifactType) { + case DOMAIN: + if (domainFilterPanel != null) { + domainFilterPanel.validateFields(); + } + break; + default: + break; + } + } + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -235,6 +281,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { documentsButton = new javax.swing.JButton(); javax.swing.JLabel step1Label = new javax.swing.JLabel(); javax.swing.Box.Filler filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(104, 0), new java.awt.Dimension(104, 0), new java.awt.Dimension(104, 32767)); + domainsButton = new javax.swing.JButton(); javax.swing.JPanel displaySettingsPanel = new javax.swing.JPanel(); searchButton = new javax.swing.JButton(); errorLabel = new javax.swing.JLabel(); @@ -249,6 +296,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); setMinimumSize(new java.awt.Dimension(600, 300)); setPreferredSize(new java.awt.Dimension(1000, 650)); + getContentPane().setLayout(new java.awt.BorderLayout()); imagesButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/pictures-icon.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(imagesButton, org.openide.util.NbBundle.getMessage(DiscoveryDialog.class, "DiscoveryDialog.imagesButton.text")); // NOI18N @@ -292,6 +340,17 @@ final class DiscoveryDialog extends javax.swing.JDialog { org.openide.awt.Mnemonics.setLocalizedText(step1Label, org.openide.util.NbBundle.getMessage(DiscoveryDialog.class, "DiscoveryDialog.step1Label.text")); // NOI18N + domainsButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/web-file.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(domainsButton, org.openide.util.NbBundle.getMessage(DiscoveryDialog.class, "DiscoveryDialog.domainsButton.text")); // NOI18N + domainsButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/web-file.png"))); // NOI18N + domainsButton.setDisabledSelectedIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/web-file.png"))); // NOI18N + domainsButton.setFocusable(false); + domainsButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + domainsButtonActionPerformed(evt); + } + }); + javax.swing.GroupLayout toolBarPanelLayout = new javax.swing.GroupLayout(toolBarPanel); toolBarPanel.setLayout(toolBarPanelLayout); toolBarPanelLayout.setHorizontalGroup( @@ -306,13 +365,18 @@ final class DiscoveryDialog extends javax.swing.JDialog { .addComponent(videosButton, javax.swing.GroupLayout.PREFERRED_SIZE, 110, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(documentsButton) - .addContainerGap(370, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(domainsButton) + .addContainerGap(190, Short.MAX_VALUE)) .addGroup(toolBarPanelLayout.createSequentialGroup() .addComponent(step1Label, javax.swing.GroupLayout.PREFERRED_SIZE, 243, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(filler1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap(391, Short.MAX_VALUE)))) ); + + toolBarPanelLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {documentsButton, domainsButton, imagesButton, videosButton}); + toolBarPanelLayout.setVerticalGroup( toolBarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(toolBarPanelLayout.createSequentialGroup() @@ -324,7 +388,8 @@ final class DiscoveryDialog extends javax.swing.JDialog { .addGroup(toolBarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(videosButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(imagesButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(documentsButton, javax.swing.GroupLayout.PREFERRED_SIZE, 43, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(documentsButton, javax.swing.GroupLayout.PREFERRED_SIZE, 43, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(domainsButton, javax.swing.GroupLayout.PREFERRED_SIZE, 43, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGap(8, 8, 8)) ); @@ -417,16 +482,13 @@ final class DiscoveryDialog extends javax.swing.JDialog { private void imagesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_imagesButtonActionPerformed removeAllPanels(); add(imageFilterPanel, CENTER); + unselectAllButtons(); imagesButton.setSelected(true); imagesButton.setEnabled(false); imagesButton.setBackground(SELECTED_COLOR); imagesButton.setForeground(Color.BLACK); - videosButton.setSelected(false); - videosButton.setEnabled(true); - videosButton.setBackground(UNSELECTED_COLOR); - documentsButton.setSelected(false); - documentsButton.setEnabled(true); - documentsButton.setBackground(UNSELECTED_COLOR); + resultType = SearchData.ResultType.FILE; + artifactType = null; fileType = FileSearchData.FileType.IMAGE; imageFilterPanel.addPropertyChangeListener(listener); validateDialog(); @@ -437,17 +499,14 @@ final class DiscoveryDialog extends javax.swing.JDialog { private void videosButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_videosButtonActionPerformed removeAllPanels(); add(videoFilterPanel, CENTER); - imagesButton.setSelected(false); - imagesButton.setEnabled(true); - imagesButton.setBackground(UNSELECTED_COLOR); + unselectAllButtons(); videosButton.setSelected(true); videosButton.setEnabled(false); videosButton.setBackground(SELECTED_COLOR); videosButton.setForeground(Color.BLACK); - documentsButton.setSelected(false); - documentsButton.setEnabled(true); - documentsButton.setBackground(UNSELECTED_COLOR); videoFilterPanel.addPropertyChangeListener(listener); + resultType = SearchData.ResultType.FILE; + artifactType = null; fileType = FileSearchData.FileType.VIDEO; validateDialog(); pack(); @@ -457,16 +516,13 @@ final class DiscoveryDialog extends javax.swing.JDialog { private void documentsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_documentsButtonActionPerformed removeAllPanels(); add(documentFilterPanel, CENTER); + unselectAllButtons(); documentsButton.setSelected(true); documentsButton.setEnabled(false); documentsButton.setBackground(SELECTED_COLOR); documentsButton.setForeground(Color.BLACK); - videosButton.setSelected(false); - videosButton.setEnabled(true); - videosButton.setBackground(UNSELECTED_COLOR); - imagesButton.setSelected(false); - imagesButton.setEnabled(true); - imagesButton.setBackground(UNSELECTED_COLOR); + resultType = SearchData.ResultType.FILE; + artifactType = null; fileType = FileSearchData.FileType.DOCUMENTS; documentFilterPanel.addPropertyChangeListener(listener); validateDialog(); @@ -490,6 +546,10 @@ final class DiscoveryDialog extends javax.swing.JDialog { remove(videoFilterPanel); videoFilterPanel.removePropertyChangeListener(listener); } + if (domainFilterPanel != null) { + remove(domainFilterPanel); + domainFilterPanel.removePropertyChangeListener(listener); + } } private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed @@ -508,10 +568,16 @@ final class DiscoveryDialog extends javax.swing.JDialog { filters = videoFilterPanel.getFilters(); } else if (documentsButton.isSelected()) { filters = documentFilterPanel.getFilters(); - } else { + } else if (imagesButton.isSelected()) { filters = imageFilterPanel.getFilters(); + } else if (domainsButton.isSelected()) { + filters = domainFilterPanel.getFilters(); + } else { + logger.log(Level.SEVERE, "No filter type selected"); + filters = new ArrayList<>(); } - DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.SearchStartedEvent(fileType)); + + DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.SearchStartedEvent(resultType, fileType, artifactType)); // Get the grouping attribute and group sorting method FileSearch.AttributeType groupingAttr = groupByCombobox.getItemAt(groupByCombobox.getSelectedIndex()).getAttributeType(); @@ -534,7 +600,24 @@ final class DiscoveryDialog extends javax.swing.JDialog { tc.toFront(); tc.requestActive(); }//GEN-LAST:event_searchButtonActionPerformed - + + private void domainsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_domainsButtonActionPerformed + removeAllPanels(); + add(domainFilterPanel, CENTER); + unselectAllButtons(); + domainsButton.setSelected(true); + domainsButton.setEnabled(false); + domainsButton.setBackground(SELECTED_COLOR); + domainsButton.setForeground(Color.BLACK); + resultType = SearchData.ResultType.ARTIFACT; + artifactType = ArtifactSearchData.ArtifactType.DOMAIN; + fileType = null; + documentFilterPanel.addPropertyChangeListener(listener); + validateDialog(); + pack(); + repaint(); + }//GEN-LAST:event_domainsButtonActionPerformed + @Override public void dispose() { setVisible(false); @@ -569,6 +652,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton documentsButton; + private javax.swing.JButton domainsButton; private javax.swing.JLabel errorLabel; private javax.swing.JComboBox groupByCombobox; private javax.swing.JComboBox groupSortingComboBox; @@ -583,7 +667,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { * filters available. */ private class CasePropertyChangeListener implements PropertyChangeListener { - + @Override @SuppressWarnings("fallthrough") public void propertyChange(PropertyChangeEvent evt) { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java index 9fb97bc088..735c4ed2cf 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java @@ -22,8 +22,10 @@ import com.google.common.eventbus.EventBus; import java.util.Collections; import java.util.List; import java.util.Map; +import org.sleuthkit.autopsy.discovery.ArtifactSearchData.ArtifactType; import org.sleuthkit.autopsy.discovery.FileSearch.GroupKey; import org.sleuthkit.autopsy.discovery.FileSearchData.FileType; +import org.sleuthkit.autopsy.discovery.SearchData.ResultType; import org.sleuthkit.datamodel.AbstractFile; /** @@ -54,15 +56,28 @@ final class DiscoveryEventUtils { */ static final class SearchStartedEvent { + private final ResultType resultType; private final FileType fileType; + private final ArtifactType artifactType; /** * Construct a new SearchStartedEvent * * @param type The type of file the search event is for. */ - SearchStartedEvent(FileType type) { - this.fileType = type; + SearchStartedEvent(ResultType resultType, FileType fileType, ArtifactType artifactType) { + this.resultType = resultType; + this.fileType = fileType; + this.artifactType = artifactType; + } + + /** + * Get the broad search type. + * + * @return The result type, either FILES, or ARTIFACTS. + */ + ResultType getResultType() { + return resultType; } /** @@ -70,9 +85,18 @@ final class DiscoveryEventUtils { * * @return The type of files being searched for. */ - FileType getType() { + FileType getFileType() { return fileType; } + + /** + * Get the type of artifact the search is being performed for. + * + * @return The type of artifacts being searched for. + */ + ArtifactType getArtifactType() { + return artifactType; + } } /** diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java index caef97f838..85fa13c4f2 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java @@ -36,6 +36,7 @@ import org.openide.windows.RetainLocation; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.coreutils.ThreadConfined; +import org.sleuthkit.autopsy.discovery.SearchData.ResultType; /** * Create a dialog for displaying the Discovery results. @@ -277,12 +278,19 @@ public final class DiscoveryTopComponent extends TopComponent { */ @Messages({"DiscoveryTopComponent.cancelButton.text=Cancel Search", "# {0} - searchType", - "DiscoveryTopComponent.searchInProgress.text=Performing search for results of type {0}. Please wait."}) + "DiscoveryTopComponent.searchInProgress.text=Performing search for results of type {0}. Please wait.", + "DiscoveryTopComponent.searchError.text=Error no type specified for search."}) @Subscribe void handleSearchStartedEvent(DiscoveryEventUtils.SearchStartedEvent searchStartedEvent) { newSearchButton.setText(Bundle.DiscoveryTopComponent_cancelButton_text()); progressMessageTextArea.setForeground(Color.red); - progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchInProgress_text(searchStartedEvent.getType().name())); + String text = Bundle.DiscoveryTopComponent_searchError_text(); + if (searchStartedEvent.getResultType() == ResultType.FILE) { + text = Bundle.DiscoveryTopComponent_searchInProgress_text(searchStartedEvent.getFileType().name()); + } else if (searchStartedEvent.getResultType() == ResultType.ARTIFACT) { + text = Bundle.DiscoveryTopComponent_searchInProgress_text(searchStartedEvent.getArtifactType().name()); + } + progressMessageTextArea.setText(text); } /** diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java index 015e14e2ab..c7a17ac917 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java @@ -103,4 +103,9 @@ final class DocumentFilterPanel extends AbstractFiltersPanel { return SearchData.ResultType.FILE; } + @Override + ArtifactSearchData.ArtifactType getArtifactType() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.form index 4f9abb50dc..ae5df7bf5c 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.form @@ -1,6 +1,11 @@ -
+ + + + + + @@ -11,18 +16,71 @@ + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java index f25324f43f..580cf10ff5 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java @@ -1,10 +1,25 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy + * + * 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.discovery; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; + /** * * @author wschaefer @@ -18,7 +33,13 @@ public class DomainFilterPanel extends AbstractFiltersPanel { * Creates new form DomainFilterPanel */ public DomainFilterPanel() { + super(); initComponents(); + addFilter(new DataSourceFilterPanel(), false, null, 0); + addFilter(new ArtifactTypeFilterPanel(), false, null, 1); + addFilter(new DateFilterPanel(), false, null, 0); + addFilter(new DomainUniquenessFilterPanel(), false, null, 1); + addPanelsToScrollPane(domainFiltersSplitPane); } /** @@ -30,16 +51,37 @@ public class DomainFilterPanel extends AbstractFiltersPanel { // //GEN-BEGIN:initComponents private void initComponents() { - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 400, Short.MAX_VALUE) + javax.swing.JScrollPane domainFiltersScrollPane = new javax.swing.JScrollPane(); + javax.swing.JPanel domainFiltersPanel = new javax.swing.JPanel(); + domainFiltersSplitPane = new javax.swing.JSplitPane(); + + setPreferredSize(new java.awt.Dimension(225, 70)); + setLayout(new java.awt.BorderLayout()); + + domainFiltersSplitPane.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(DomainFilterPanel.class, "DomainFilterPanel.domainFiltersSplitPane.border.title"))); // NOI18N + domainFiltersSplitPane.setResizeWeight(0.5); + domainFiltersSplitPane.setToolTipText(org.openide.util.NbBundle.getMessage(DomainFilterPanel.class, "DomainFilterPanel.domainFiltersSplitPane.toolTipText")); // NOI18N + + javax.swing.GroupLayout domainFiltersPanelLayout = new javax.swing.GroupLayout(domainFiltersPanel); + domainFiltersPanel.setLayout(domainFiltersPanelLayout); + domainFiltersPanelLayout.setHorizontalGroup( + domainFiltersPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(domainFiltersPanelLayout.createSequentialGroup() + .addGap(8, 8, 8) + .addComponent(domainFiltersSplitPane) + .addGap(8, 8, 8)) ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 300, Short.MAX_VALUE) + domainFiltersPanelLayout.setVerticalGroup( + domainFiltersPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(domainFiltersPanelLayout.createSequentialGroup() + .addGap(8, 8, 8) + .addComponent(domainFiltersSplitPane) + .addGap(8, 8, 8)) ); + + domainFiltersScrollPane.setViewportView(domainFiltersPanel); + + add(domainFiltersScrollPane, java.awt.BorderLayout.CENTER); }// //GEN-END:initComponents @Override @@ -52,7 +94,13 @@ public class DomainFilterPanel extends AbstractFiltersPanel { return SearchData.ResultType.ARTIFACT; } + @Override + ArtifactSearchData.ArtifactType getArtifactType() { + return ARTIFACT_TYPE; + } + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JSplitPane domainFiltersSplitPane; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.form new file mode 100644 index 0000000000..9e1ccd6039 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.form @@ -0,0 +1,43 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.java new file mode 100644 index 0000000000..f0bf9a372c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.java @@ -0,0 +1,101 @@ +/* + * Autopsy + * + * 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.discovery; + +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JList; + +/** + * + * @author wschaefer + */ +class DomainUniquenessFilterPanel extends AbstractDiscoveryFilterPanel { + + private static final long serialVersionUID = 1L; + + /** + * Creates new form DomainUniquenessFilterPanel + */ + DomainUniquenessFilterPanel() { + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + domainUniquenessCheckbox = new javax.swing.JCheckBox(); + domainUniqueScrollPane = new javax.swing.JScrollPane(); + + org.openide.awt.Mnemonics.setLocalizedText(domainUniquenessCheckbox, org.openide.util.NbBundle.getMessage(DomainUniquenessFilterPanel.class, "DomainUniquenessFilterPanel.domainUniquenessCheckbox.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(domainUniqueScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 207, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(domainUniqueScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 48, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + + @Override + void configurePanel(boolean selected, int[] indicesSelected) { + domainUniquenessCheckbox.setSelected(selected); + } + + @Override + JCheckBox getCheckbox() { + return domainUniquenessCheckbox; + } + + @Override + JList getList() { + return null; + } + + @Override + JLabel getAdditionalLabel() { + return null; + } + + @Override + String checkForError() { + return "Domain search is not implemented."; + } + + @Override + AbstractFilter getFilter() { + return null; + } + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JScrollPane domainUniqueScrollPane; + private javax.swing.JCheckBox domainUniquenessCheckbox; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/GroupListPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/GroupListPanel.java index 2fa91c2380..caaacd1d30 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/GroupListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/GroupListPanel.java @@ -37,7 +37,7 @@ import org.sleuthkit.autopsy.discovery.FileSearchData.FileType; final class GroupListPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; - private FileType resultType = null; + private FileType fileType = null; private Map groupMap = null; private List searchfilters; private FileSearch.AttributeType groupingAttribute; @@ -59,7 +59,7 @@ final class GroupListPanel extends javax.swing.JPanel { */ @Subscribe void handleSearchStartedEvent(DiscoveryEventUtils.SearchStartedEvent searchStartedEvent) { - resultType = searchStartedEvent.getType(); + fileType = searchStartedEvent.getFileType(); groupKeyList.setListData(new GroupKey[0]); } @@ -170,7 +170,7 @@ final class GroupListPanel extends javax.swing.JPanel { if (selectedGroup.equals(groupKey)) { selectedGroupKey = groupKey; DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.GroupSelectedEvent( - searchfilters, groupingAttribute, groupSort, fileSortMethod, selectedGroupKey, groupMap.get(selectedGroupKey), resultType)); + searchfilters, groupingAttribute, groupSort, fileSortMethod, selectedGroupKey, groupMap.get(selectedGroupKey), fileType)); break; } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.java index fc22e7af8f..f59d0da648 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.java @@ -108,4 +108,9 @@ final class ImageFilterPanel extends AbstractFiltersPanel { SearchData.ResultType getResultType() { return SearchData.ResultType.FILE; } + + @Override + ArtifactSearchData.ArtifactType getArtifactType() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java index 3cb69f0ff4..e39519c0ee 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java @@ -110,4 +110,9 @@ final class VideoFilterPanel extends AbstractFiltersPanel { return SearchData.ResultType.FILE; } + @Override + ArtifactSearchData.ArtifactType getArtifactType() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + } From b924aa4a9c17c073fc0e125a61e8d3cb89282931 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 10 Aug 2020 13:11:10 -0400 Subject: [PATCH 003/130] 6639 discovery domain panel changes --- .../autopsy/discovery/ArtifactSearchData.java | 32 ++-- .../discovery/ArtifactTypeFilterPanel.form | 13 ++ .../discovery/ArtifactTypeFilterPanel.java | 58 ++++++- .../autopsy/discovery/Bundle.properties | 8 +- .../autopsy/discovery/Bundle_ja.properties | 4 + .../discovery/DataSourceFilterPanel.java | 1 + .../autopsy/discovery/DateFilterPanel.form | 154 +++++++++++++++++- .../autopsy/discovery/DateFilterPanel.java | 140 +++++++++++++++- .../autopsy/discovery/DiscoveryDialog.java | 1 - .../autopsy/discovery/DomainFilterPanel.java | 10 +- .../DomainUniquenessFilterPanel.form | 16 ++ .../DomainUniquenessFilterPanel.java | 10 ++ 12 files changed, 417 insertions(+), 30 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/Bundle_ja.properties diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ArtifactSearchData.java b/Core/src/org/sleuthkit/autopsy/discovery/ArtifactSearchData.java index a4e84b3242..e67871861c 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ArtifactSearchData.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ArtifactSearchData.java @@ -5,6 +5,11 @@ */ package org.sleuthkit.autopsy.discovery; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.Set; import org.openide.util.NbBundle; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -13,13 +18,13 @@ import org.sleuthkit.datamodel.BlackboardArtifact; */ public class ArtifactSearchData extends SearchData { - + private static final Set DOMAIN_ARTIFACT_TYPES = EnumSet.of(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY, BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG); + @Override - ResultType getResultType(){ + ResultType getResultType() { return ResultType.ARTIFACT; } - - + /** * Enum representing the file type. We don't simply use * FileTypeUtils.FileTypeCategory because: - Some file types categories @@ -31,26 +36,26 @@ public class ArtifactSearchData extends SearchData { "ArtifactSearchData.ArtifactType.Other.displayName=Other"}) enum ArtifactType { - DOMAIN(0, Bundle.ArtifactSearchData_ArtifactType_Domain_displayName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK), - OTHER(1, Bundle.ArtifactSearchData_ArtifactType_Other_displayName(), null); + DOMAIN(0, Bundle.ArtifactSearchData_ArtifactType_Domain_displayName(), DOMAIN_ARTIFACT_TYPES), + OTHER(1, Bundle.ArtifactSearchData_ArtifactType_Other_displayName(), new HashSet<>()); private final int ranking; // For ordering in the UI private final String displayName; - private final BlackboardArtifact.ARTIFACT_TYPE artifactType; + private final Set artifactTypes = new HashSet<>(); - ArtifactType(int value, String displayName, BlackboardArtifact.ARTIFACT_TYPE type) { + ArtifactType(int value, String displayName, Set types) { this.ranking = value; this.displayName = displayName; - this.artifactType = type; + this.artifactTypes.addAll(types); } /** - * Get the MIME types matching this category. + * Get the BlackboardArtifact types matching this category. * - * @return Collection of MIME type strings + * @return Collection of BlackboardArtifact types. */ - BlackboardArtifact.ARTIFACT_TYPE getMediaTypes() { - return artifactType; + Collection getBlackboardTypes() { + return Collections.unmodifiableCollection(artifactTypes); } @Override @@ -67,7 +72,6 @@ public class ArtifactSearchData extends SearchData { return ranking; } - static ArtifactType fromBlackboardArtifact(final BlackboardArtifact.ARTIFACT_TYPE type) { switch (type) { case TSK_WEB_BOOKMARK: diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.form index 1e6d77593d..988d1acedf 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.form @@ -48,6 +48,19 @@ + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.java index fb14ceaeef..c5c01c545b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.java @@ -18,9 +18,11 @@ */ package org.sleuthkit.autopsy.discovery; +import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; +import org.sleuthkit.datamodel.BlackboardArtifact; /** * @@ -35,6 +37,21 @@ class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { */ ArtifactTypeFilterPanel() { initComponents(); + setUpArtifactTypeFilter(); + + } + + /** + * Initialize the data source filter. + */ + private void setUpArtifactTypeFilter() { + int count = 0; + DefaultListModel artifactTypeModel = (DefaultListModel) jList1.getModel(); + artifactTypeModel.removeAllElements(); + for (BlackboardArtifact.ARTIFACT_TYPE artifactType : ArtifactSearchData.ArtifactType.DOMAIN.getBlackboardTypes()) { + artifactTypeModel.add(count, new ArtifactTypeItem(artifactType)); + count++; + } } /** @@ -48,6 +65,7 @@ class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { artifactTypeCheckbox = new javax.swing.JCheckBox(); artifactTypeScrollPane = new javax.swing.JScrollPane(); + jList1 = new javax.swing.JList<>(); org.openide.awt.Mnemonics.setLocalizedText(artifactTypeCheckbox, org.openide.util.NbBundle.getMessage(ArtifactTypeFilterPanel.class, "ArtifactTypeFilterPanel.artifactTypeCheckbox.text")); // NOI18N @@ -55,6 +73,10 @@ class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { artifactTypeScrollPane.setPreferredSize(new java.awt.Dimension(27, 27)); + jList1.setModel(new DefaultListModel()); + jList1.setEnabled(false); + artifactTypeScrollPane.setViewportView(jList1); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -79,7 +101,7 @@ class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { @Override JList getList() { - return null; + return null; } @Override @@ -89,7 +111,7 @@ class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { @Override String checkForError() { - return "Domain search is not implemented."; + return "Domain search is not implemented."; } @Override @@ -97,9 +119,41 @@ class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { return null; } + /** + * Utility class to allow us to display the AritfactType display name + * instead of the name. + */ + private class ArtifactTypeItem { + + private final BlackboardArtifact.ARTIFACT_TYPE artifactType; + + /** + * Construct a new ArtifactTypeItem. + * + * @param ds The artifact type being wrapped. + */ + ArtifactTypeItem(BlackboardArtifact.ARTIFACT_TYPE artifactType) { + this.artifactType = artifactType; + } + + /** + * Get the ArtifactType represented by this ArtifactTypeItem. + * + * @return The ArtifactType represented by this ArtifactTypeItem. + */ + BlackboardArtifact.ARTIFACT_TYPE getArtifactType() { + return artifactType; + } + + @Override + public String toString() { + return artifactType.getDisplayName(); + } + } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JCheckBox artifactTypeCheckbox; private javax.swing.JScrollPane artifactTypeScrollPane; + private javax.swing.JList jList1; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties index 90e86aab72..dffbc4580e 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties @@ -108,5 +108,9 @@ DiscoveryDialog.domainsButton.text=Domains DomainFilterPanel.domainFiltersSplitPane.border.title=Step 2: Filter which domains to show DomainFilterPanel.domainFiltersSplitPane.toolTipText= DateFilterPanel.dateFilterCheckbox.text=Date Filter -ArtifactTypeFilterPanel.artifactTypeCheckbox.text=Artifact Type -DomainUniquenessFilterPanel.domainUniquenessCheckbox.text=Domain Uniqueness +ArtifactTypeFilterPanel.artifactTypeCheckbox.text=Artifact Type: +DomainUniquenessFilterPanel.domainUniquenessCheckbox.text=Domain Uniqueness: +DateFilterPanel.mostRecentButton.text=Only last: +DateFilterPanel.daysLabel.text=days of activity +DateFilterPanel.endCheckBox.text=End: +DateFilterPanel.startCheckBox.text=Start: diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/discovery/Bundle_ja.properties new file mode 100644 index 0000000000..2f28dc35d8 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/Bundle_ja.properties @@ -0,0 +1,4 @@ + +DateFilterPanel.endCheckBox.text=\u7d42\u4e86: + +DateFilterPanel.startCheckBox.text=\u958b\u59cb: diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DataSourceFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DataSourceFilterPanel.java index 7ecd859e52..6afc8c6c69 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DataSourceFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DataSourceFilterPanel.java @@ -140,6 +140,7 @@ final class DataSourceFilterPanel extends AbstractDiscoveryFilterPanel { dsListModel.removeAllElements(); for (DataSource ds : Case.getCurrentCase().getSleuthkitCase().getDataSources()) { dsListModel.add(count, new DataSourceItem(ds)); + count++; } } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error loading data sources", ex); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.form index 5e523cc270..ed1d57ecf8 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.form @@ -2,6 +2,8 @@
+ + @@ -25,19 +27,163 @@ - + + + + + - + + + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.java index 5409cebbdc..5353586761 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.java @@ -21,6 +21,9 @@ package org.sleuthkit.autopsy.discovery; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; +import javax.swing.SpinnerNumberModel; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.communications.Utils; /** * @@ -29,12 +32,18 @@ import javax.swing.JList; class DateFilterPanel extends AbstractDiscoveryFilterPanel { private static final long serialVersionUID = 1L; + private final SpinnerNumberModel numberModel; /** * Creates new form DateFilterPanel */ + @NbBundle.Messages({"# {0} - timeZone", + "DateFilterPanel.dateRange.text=Date Range ({0}):"}) DateFilterPanel() { + // numberModel is used in initComponents + numberModel = new SpinnerNumberModel(10, 1, Integer.MAX_VALUE, 1); initComponents(); + jRadioButton1.setText(Bundle.DateFilterPanel_dateRange_text(Utils.getUserPreferredZoneId().toString())); } /** @@ -46,23 +55,135 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { // //GEN-BEGIN:initComponents private void initComponents() { + buttonGroup1 = new javax.swing.ButtonGroup(); dateFilterCheckbox = new javax.swing.JCheckBox(); - dateFilterScrollPane = new javax.swing.JScrollPane(); + jPanel1 = new javax.swing.JPanel(); + daysSpinner = new javax.swing.JSpinner(numberModel); + daysLabel = new javax.swing.JLabel(); + mostRecentButton = new javax.swing.JRadioButton(); + startCheckBox = new javax.swing.JCheckBox(); + startDatePicker = new com.github.lgooddatepicker.components.DatePicker(); + endDatePicker = new com.github.lgooddatepicker.components.DatePicker(); + endCheckBox = new javax.swing.JCheckBox(); + jRadioButton1 = new javax.swing.JRadioButton(); org.openide.awt.Mnemonics.setLocalizedText(dateFilterCheckbox, org.openide.util.NbBundle.getMessage(DateFilterPanel.class, "DateFilterPanel.dateFilterCheckbox.text")); // NOI18N + daysSpinner.setEnabled(false); + daysSpinner.setPreferredSize(new java.awt.Dimension(75, 26)); + + org.openide.awt.Mnemonics.setLocalizedText(daysLabel, org.openide.util.NbBundle.getMessage(DateFilterPanel.class, "DateFilterPanel.daysLabel.text")); // NOI18N + daysLabel.setEnabled(false); + + buttonGroup1.add(mostRecentButton); + org.openide.awt.Mnemonics.setLocalizedText(mostRecentButton, org.openide.util.NbBundle.getMessage(DateFilterPanel.class, "DateFilterPanel.mostRecentButton.text")); // NOI18N + mostRecentButton.setEnabled(false); + mostRecentButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + mostRecentButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(startCheckBox, org.openide.util.NbBundle.getMessage(DateFilterPanel.class, "DateFilterPanel.startCheckBox.text")); // NOI18N + startCheckBox.setEnabled(false); + startCheckBox.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + startCheckBoxStateChanged(evt); + } + }); + + startDatePicker.setEnabled(false); + startDatePicker.setMinimumSize(new java.awt.Dimension(60, 22)); + startDatePicker.setPreferredSize(new java.awt.Dimension(110, 22)); + + endDatePicker.setEnabled(false); + endDatePicker.setMinimumSize(new java.awt.Dimension(60, 22)); + endDatePicker.setPreferredSize(new java.awt.Dimension(110, 22)); + + org.openide.awt.Mnemonics.setLocalizedText(endCheckBox, org.openide.util.NbBundle.getMessage(DateFilterPanel.class, "DateFilterPanel.endCheckBox.text")); // NOI18N + endCheckBox.setEnabled(false); + endCheckBox.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + endCheckBoxStateChanged(evt); + } + }); + + buttonGroup1.add(jRadioButton1); + jRadioButton1.setEnabled(false); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(mostRecentButton, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(daysSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(daysLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 132, Short.MAX_VALUE)) + .addComponent(jRadioButton1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() + .addGap(30, 30, 30) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(endCheckBox) + .addComponent(startCheckBox)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(endDatePicker, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(startDatePicker, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(mostRecentButton) + .addComponent(daysSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(daysLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jRadioButton1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(startCheckBox) + .addComponent(startDatePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(endCheckBox) + .addComponent(endDatePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(0, 0, 0)) + ); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(dateFilterScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 223, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(0, 0, 0)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(dateFilterScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 43, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(8, 8, 8)) ); }// //GEN-END:initComponents + private void mostRecentButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mostRecentButtonActionPerformed + + }//GEN-LAST:event_mostRecentButtonActionPerformed + + private void startCheckBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_startCheckBoxStateChanged + startDatePicker.setEnabled(startCheckBox.isSelected()); +// validateFilters(); + }//GEN-LAST:event_startCheckBoxStateChanged + + private void endCheckBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_endCheckBoxStateChanged + endDatePicker.setEnabled(endCheckBox.isSelected()); +// validateFilters(); + }//GEN-LAST:event_endCheckBoxStateChanged + @Override void configurePanel(boolean selected, int[] indicesSelected) { dateFilterCheckbox.setSelected(selected); @@ -75,7 +196,7 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { @Override JList getList() { - return null; + return null; } @Override @@ -95,7 +216,16 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.ButtonGroup buttonGroup1; private javax.swing.JCheckBox dateFilterCheckbox; - private javax.swing.JScrollPane dateFilterScrollPane; + private javax.swing.JLabel daysLabel; + private javax.swing.JSpinner daysSpinner; + private javax.swing.JCheckBox endCheckBox; + private com.github.lgooddatepicker.components.DatePicker endDatePicker; + private javax.swing.JPanel jPanel1; + private javax.swing.JRadioButton jRadioButton1; + private javax.swing.JRadioButton mostRecentButton; + private javax.swing.JCheckBox startCheckBox; + private com.github.lgooddatepicker.components.DatePicker startDatePicker; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java index a5884beb61..22d165dcb5 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java @@ -296,7 +296,6 @@ final class DiscoveryDialog extends javax.swing.JDialog { setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); setMinimumSize(new java.awt.Dimension(600, 300)); setPreferredSize(new java.awt.Dimension(1000, 650)); - getContentPane().setLayout(new java.awt.BorderLayout()); imagesButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/pictures-icon.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(imagesButton, org.openide.util.NbBundle.getMessage(DiscoveryDialog.class, "DiscoveryDialog.imagesButton.text")); // NOI18N diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java index 580cf10ff5..6bdab70fd3 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java @@ -37,8 +37,14 @@ public class DomainFilterPanel extends AbstractFiltersPanel { initComponents(); addFilter(new DataSourceFilterPanel(), false, null, 0); addFilter(new ArtifactTypeFilterPanel(), false, null, 1); - addFilter(new DateFilterPanel(), false, null, 0); - addFilter(new DomainUniquenessFilterPanel(), false, null, 1); + addFilter(new DateFilterPanel(), false, null, 1); + int[] pastOccurrencesIndices; + if (!CentralRepository.isEnabled()) { + pastOccurrencesIndices = new int[]{0}; + } else { + pastOccurrencesIndices = new int[]{2, 3, 4}; + } + addFilter(new PastOccurrencesFilterPanel(), true, pastOccurrencesIndices, 0); addPanelsToScrollPane(domainFiltersSplitPane); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.form index 9e1ccd6039..b18df2e114 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.form @@ -38,6 +38,22 @@ + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.java index f0bf9a372c..421cfef6c4 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.java @@ -48,9 +48,18 @@ class DomainUniquenessFilterPanel extends AbstractDiscoveryFilterPanel { domainUniquenessCheckbox = new javax.swing.JCheckBox(); domainUniqueScrollPane = new javax.swing.JScrollPane(); + jList1 = new javax.swing.JList<>(); org.openide.awt.Mnemonics.setLocalizedText(domainUniquenessCheckbox, org.openide.util.NbBundle.getMessage(DomainUniquenessFilterPanel.class, "DomainUniquenessFilterPanel.domainUniquenessCheckbox.text")); // NOI18N + jList1.setModel(new javax.swing.AbstractListModel() { + String[] strings = { "Unique", "Multiple instances" }; + public int getSize() { return strings.length; } + public String getElementAt(int i) { return strings[i]; } + }); + jList1.setEnabled(false); + domainUniqueScrollPane.setViewportView(jList1); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -97,5 +106,6 @@ class DomainUniquenessFilterPanel extends AbstractDiscoveryFilterPanel { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JScrollPane domainUniqueScrollPane; private javax.swing.JCheckBox domainUniquenessCheckbox; + private javax.swing.JList jList1; // End of variables declaration//GEN-END:variables } From a86248fc9f5f26d30679fadccc44421f581d224a Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 17 Aug 2020 09:58:25 -0400 Subject: [PATCH 004/130] 6639 Discovery refactoring --- .../discovery/AbstractFiltersPanel.java | 4 ++-- .../discovery/ArtifactTypeFilterPanel.java | 2 +- ...archData.java => AttributeSearchData.java} | 4 ++-- .../autopsy/discovery/DiscoveryDialog.java | 8 +++---- .../discovery/DiscoveryEventUtils.java | 2 +- .../discovery/DiscoveryTopComponent.java | 2 +- .../discovery/DocumentFilterPanel.java | 2 +- .../autopsy/discovery/DomainFilterPanel.java | 6 +++--- .../autopsy/discovery/ImageFilterPanel.java | 2 +- .../discovery/PastOccurrencesFilterPanel.java | 15 +++++++++---- .../autopsy/discovery/SearchData.java | 21 +++++++++++++++---- .../autopsy/discovery/VideoFilterPanel.java | 2 +- 12 files changed, 45 insertions(+), 25 deletions(-) rename Core/src/org/sleuthkit/autopsy/discovery/{ArtifactSearchData.java => AttributeSearchData.java} (97%) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java index 6abe6ee557..e400f60791 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java @@ -75,7 +75,7 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li * * @return The type of results this panel filters. */ - abstract ArtifactSearchData.ArtifactType getArtifactType(); + abstract AttributeSearchData.ArtifactType getArtifactType(); /** * Add a DiscoveryFilterPanel to the specified column with the specified @@ -256,7 +256,7 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li List filtersToUse = new ArrayList<>(); if (getResultType().equals(SearchData.ResultType.FILE)) { filtersToUse.add(new SearchFiltering.FileTypeFilter(getFileType())); - } else if (getResultType().equals(SearchData.ResultType.ARTIFACT)) { + } else if (getResultType().equals(SearchData.ResultType.ATTRIBUTE)) { } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.java index c5c01c545b..52cf607dba 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.java @@ -48,7 +48,7 @@ class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { int count = 0; DefaultListModel artifactTypeModel = (DefaultListModel) jList1.getModel(); artifactTypeModel.removeAllElements(); - for (BlackboardArtifact.ARTIFACT_TYPE artifactType : ArtifactSearchData.ArtifactType.DOMAIN.getBlackboardTypes()) { + for (BlackboardArtifact.ARTIFACT_TYPE artifactType : AttributeSearchData.ArtifactType.DOMAIN.getBlackboardTypes()) { artifactTypeModel.add(count, new ArtifactTypeItem(artifactType)); count++; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ArtifactSearchData.java b/Core/src/org/sleuthkit/autopsy/discovery/AttributeSearchData.java similarity index 97% rename from Core/src/org/sleuthkit/autopsy/discovery/ArtifactSearchData.java rename to Core/src/org/sleuthkit/autopsy/discovery/AttributeSearchData.java index e67871861c..99b947754f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ArtifactSearchData.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/AttributeSearchData.java @@ -16,13 +16,13 @@ import org.sleuthkit.datamodel.BlackboardArtifact; /** * Utility enums for searches made for artifacts with Discovery. */ -public class ArtifactSearchData extends SearchData { +public class AttributeSearchData extends SearchData { private static final Set DOMAIN_ARTIFACT_TYPES = EnumSet.of(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY, BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG); @Override ResultType getResultType() { - return ResultType.ARTIFACT; + return ResultType.ATTRIBUTE; } /** diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java index 22d165dcb5..8256488f3b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java @@ -70,7 +70,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { private static volatile boolean shouldUpdate = false; private SearchData.ResultType resultType = SearchData.ResultType.FILE; private FileSearchData.FileType fileType = FileSearchData.FileType.IMAGE; - private ArtifactSearchData.ArtifactType artifactType = null; + private AttributeSearchData.ArtifactType artifactType = null; private final PropertyChangeListener listener; private final Set objectsDetected = new HashSet<>(); private final Set interestingItems = new HashSet<>(); @@ -220,7 +220,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { case FILE: validateFileDialog(); break; - case ARTIFACT: + case ATTRIBUTE: validateArtifactDialog(); break; } @@ -608,8 +608,8 @@ final class DiscoveryDialog extends javax.swing.JDialog { domainsButton.setEnabled(false); domainsButton.setBackground(SELECTED_COLOR); domainsButton.setForeground(Color.BLACK); - resultType = SearchData.ResultType.ARTIFACT; - artifactType = ArtifactSearchData.ArtifactType.DOMAIN; + resultType = SearchData.ResultType.ATTRIBUTE; + artifactType = AttributeSearchData.ArtifactType.DOMAIN; fileType = null; documentFilterPanel.addPropertyChangeListener(listener); validateDialog(); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java index 735c4ed2cf..11b814b75b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java @@ -22,7 +22,7 @@ import com.google.common.eventbus.EventBus; import java.util.Collections; import java.util.List; import java.util.Map; -import org.sleuthkit.autopsy.discovery.ArtifactSearchData.ArtifactType; +import org.sleuthkit.autopsy.discovery.AttributeSearchData.ArtifactType; import org.sleuthkit.autopsy.discovery.FileSearch.GroupKey; import org.sleuthkit.autopsy.discovery.FileSearchData.FileType; import org.sleuthkit.autopsy.discovery.SearchData.ResultType; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java index 85fa13c4f2..2b252b2073 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java @@ -287,7 +287,7 @@ public final class DiscoveryTopComponent extends TopComponent { String text = Bundle.DiscoveryTopComponent_searchError_text(); if (searchStartedEvent.getResultType() == ResultType.FILE) { text = Bundle.DiscoveryTopComponent_searchInProgress_text(searchStartedEvent.getFileType().name()); - } else if (searchStartedEvent.getResultType() == ResultType.ARTIFACT) { + } else if (searchStartedEvent.getResultType() == ResultType.ATTRIBUTE) { text = Bundle.DiscoveryTopComponent_searchInProgress_text(searchStartedEvent.getArtifactType().name()); } progressMessageTextArea.setText(text); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java index c7a17ac917..4b0c870a74 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java @@ -104,7 +104,7 @@ final class DocumentFilterPanel extends AbstractFiltersPanel { } @Override - ArtifactSearchData.ArtifactType getArtifactType() { + AttributeSearchData.ArtifactType getArtifactType() { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java index 6bdab70fd3..175c64d3a9 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java @@ -27,7 +27,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; public class DomainFilterPanel extends AbstractFiltersPanel { private static final long serialVersionUID = 1L; - private static final ArtifactSearchData.ArtifactType ARTIFACT_TYPE = ArtifactSearchData.ArtifactType.DOMAIN; + private static final AttributeSearchData.ArtifactType ARTIFACT_TYPE = AttributeSearchData.ArtifactType.DOMAIN; /** * Creates new form DomainFilterPanel @@ -97,11 +97,11 @@ public class DomainFilterPanel extends AbstractFiltersPanel { @Override SearchData.ResultType getResultType() { - return SearchData.ResultType.ARTIFACT; + return SearchData.ResultType.ATTRIBUTE; } @Override - ArtifactSearchData.ArtifactType getArtifactType() { + AttributeSearchData.ArtifactType getArtifactType() { return ARTIFACT_TYPE; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.java index f59d0da648..d86ffbe81c 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.java @@ -110,7 +110,7 @@ final class ImageFilterPanel extends AbstractFiltersPanel { } @Override - ArtifactSearchData.ArtifactType getArtifactType() { + AttributeSearchData.ArtifactType getArtifactType() { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java index a6d3d2b841..0766443629 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java @@ -24,6 +24,7 @@ import javax.swing.JLabel; import javax.swing.JList; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.discovery.FileSearchData.Frequency; +import org.sleuthkit.autopsy.discovery.SearchData.ResultType; /** * Panel to allow configuration of the Past Occurrences filter. @@ -37,9 +38,15 @@ final class PastOccurrencesFilterPanel extends AbstractDiscoveryFilterPanel { */ PastOccurrencesFilterPanel() { initComponents(); - setUpFrequencyFilter(); + setUpFrequencyFilter(ResultType.FILE); + } + /** + * Creates new form PastOccurrencesFilterPanel. + */ + PastOccurrencesFilterPanel(ResultType type) { + initComponents(); + setUpFrequencyFilter(type); } - /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -94,11 +101,11 @@ final class PastOccurrencesFilterPanel extends AbstractDiscoveryFilterPanel { /** * Initialize the frequency filter. */ - private void setUpFrequencyFilter() { + private void setUpFrequencyFilter(ResultType type) { int count = 0; DefaultListModel frequencyListModel = (DefaultListModel) crFrequencyList.getModel(); frequencyListModel.removeAllElements(); - if (!CentralRepository.isEnabled()) { + if (!CentralRepository.isEnabled() && type != ResultType.ATTRIBUTE) { for (FileSearchData.Frequency freq : FileSearchData.Frequency.getOptionsForFilteringWithoutCr()) { frequencyListModel.add(count, freq); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/SearchData.java b/Core/src/org/sleuthkit/autopsy/discovery/SearchData.java index c6700c5a16..357c7d9664 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/SearchData.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/SearchData.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy + * + * 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.discovery; @@ -10,7 +23,7 @@ abstract class SearchData { enum ResultType { FILE, - ARTIFACT; + ATTRIBUTE; } abstract ResultType getResultType(); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java index e39519c0ee..698f13290e 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java @@ -111,7 +111,7 @@ final class VideoFilterPanel extends AbstractFiltersPanel { } @Override - ArtifactSearchData.ArtifactType getArtifactType() { + AttributeSearchData.ArtifactType getArtifactType() { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } From e2a7b72525329e94cb2955c719fa27ac83978878 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 17 Aug 2020 10:01:19 -0400 Subject: [PATCH 005/130] 6639 update copyrights --- .../autopsy/discovery/AbstractFilter.java | 19 ++++++++++++++++--- .../discovery/AttributeSearchData.java | 19 ++++++++++++++++--- .../discovery/Bundle.properties-MERGED | 10 ++++++++-- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/AbstractFilter.java b/Core/src/org/sleuthkit/autopsy/discovery/AbstractFilter.java index 39826ca36a..bb5320488d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/AbstractFilter.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/AbstractFilter.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy + * + * 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.discovery; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/AttributeSearchData.java b/Core/src/org/sleuthkit/autopsy/discovery/AttributeSearchData.java index 99b947754f..d6f5282eff 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/AttributeSearchData.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/AttributeSearchData.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy + * + * 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.discovery; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED index 1b61a3f9a6..a54e5e670f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED @@ -7,6 +7,8 @@ DataSourceModuleWrapper.exifModule.text=Exif Parser module was not run on data s DataSourceModuleWrapper.fileTypeModule.text=File Type Identification module was not run on data source: {0}\n # {0} - dataSourceName DataSourceModuleWrapper.hashModule.text=Hash Lookup module was not run on data source: {0}\n +# {0} - timeZone +DateFilterPanel.dateRange.text=Date Range ({0}): DiscoveryDialog.name.text=Discovery DiscoveryTopComponent.cancelButton.text=Cancel Search DiscoveryTopComponent.name=\ Discovery @@ -274,8 +276,12 @@ DiscoveryDialog.domainsButton.text=Domains DomainFilterPanel.domainFiltersSplitPane.border.title=Step 2: Filter which domains to show DomainFilterPanel.domainFiltersSplitPane.toolTipText= DateFilterPanel.dateFilterCheckbox.text=Date Filter -ArtifactTypeFilterPanel.artifactTypeCheckbox.text=Artifact Type -DomainUniquenessFilterPanel.domainUniquenessCheckbox.text=Domain Uniqueness +ArtifactTypeFilterPanel.artifactTypeCheckbox.text=Artifact Type: +DomainUniquenessFilterPanel.domainUniquenessCheckbox.text=Domain Uniqueness: +DateFilterPanel.mostRecentButton.text=Only last: +DateFilterPanel.daysLabel.text=days of activity +DateFilterPanel.endCheckBox.text=End: +DateFilterPanel.startCheckBox.text=Start: VideoThumbnailPanel.bytes.text=bytes VideoThumbnailPanel.deleted.text=All instances of file are deleted. VideoThumbnailPanel.gigaBytes.text=GB From d0be74fc65d95e7dbf1a5b82652e39b9be25452c Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 17 Aug 2020 10:06:59 -0400 Subject: [PATCH 006/130] 6639 fix appearance of past occrrurences filter --- .../autopsy/discovery/DomainFilterPanel.java | 7 +++---- .../discovery/PastOccurrencesFilterPanel.java | 14 ++++---------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java index 175c64d3a9..9091d0f3c9 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java @@ -39,12 +39,11 @@ public class DomainFilterPanel extends AbstractFiltersPanel { addFilter(new ArtifactTypeFilterPanel(), false, null, 1); addFilter(new DateFilterPanel(), false, null, 1); int[] pastOccurrencesIndices; - if (!CentralRepository.isEnabled()) { - pastOccurrencesIndices = new int[]{0}; - } else { + if (CentralRepository.isEnabled()) { pastOccurrencesIndices = new int[]{2, 3, 4}; + addFilter(new PastOccurrencesFilterPanel(), true, pastOccurrencesIndices, 0); } - addFilter(new PastOccurrencesFilterPanel(), true, pastOccurrencesIndices, 0); + addPanelsToScrollPane(domainFiltersSplitPane); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java index 0766443629..cd20850a55 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java @@ -38,15 +38,9 @@ final class PastOccurrencesFilterPanel extends AbstractDiscoveryFilterPanel { */ PastOccurrencesFilterPanel() { initComponents(); - setUpFrequencyFilter(ResultType.FILE); - } - /** - * Creates new form PastOccurrencesFilterPanel. - */ - PastOccurrencesFilterPanel(ResultType type) { - initComponents(); - setUpFrequencyFilter(type); + setUpFrequencyFilter(); } + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -101,11 +95,11 @@ final class PastOccurrencesFilterPanel extends AbstractDiscoveryFilterPanel { /** * Initialize the frequency filter. */ - private void setUpFrequencyFilter(ResultType type) { + private void setUpFrequencyFilter() { int count = 0; DefaultListModel frequencyListModel = (DefaultListModel) crFrequencyList.getModel(); frequencyListModel.removeAllElements(); - if (!CentralRepository.isEnabled() && type != ResultType.ATTRIBUTE) { + if (!CentralRepository.isEnabled()) { for (FileSearchData.Frequency freq : FileSearchData.Frequency.getOptionsForFilteringWithoutCr()) { frequencyListModel.add(count, freq); } From bd13fd36dba6ee39f7a2f14f44c13fac4a20543b Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 17 Aug 2020 10:19:07 -0400 Subject: [PATCH 007/130] 6639 change discovery domain icon --- .../autopsy/discovery/DiscoveryDialog.form | 6 +++--- .../autopsy/discovery/DiscoveryDialog.java | 6 +++--- .../org/sleuthkit/autopsy/images/domain-32.png | Bin 0 -> 2381 bytes 3 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/images/domain-32.png diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form index f53408d443..93d2015fdb 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form @@ -197,16 +197,16 @@ - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java index 8256488f3b..9d031eba88 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java @@ -339,10 +339,10 @@ final class DiscoveryDialog extends javax.swing.JDialog { org.openide.awt.Mnemonics.setLocalizedText(step1Label, org.openide.util.NbBundle.getMessage(DiscoveryDialog.class, "DiscoveryDialog.step1Label.text")); // NOI18N - domainsButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/web-file.png"))); // NOI18N + domainsButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/domain-32.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(domainsButton, org.openide.util.NbBundle.getMessage(DiscoveryDialog.class, "DiscoveryDialog.domainsButton.text")); // NOI18N - domainsButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/web-file.png"))); // NOI18N - domainsButton.setDisabledSelectedIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/web-file.png"))); // NOI18N + domainsButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/domain-32.png"))); // NOI18N + domainsButton.setDisabledSelectedIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/domain-32.png"))); // NOI18N domainsButton.setFocusable(false); domainsButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { diff --git a/Core/src/org/sleuthkit/autopsy/images/domain-32.png b/Core/src/org/sleuthkit/autopsy/images/domain-32.png new file mode 100644 index 0000000000000000000000000000000000000000..ba62d997b9cae2f585eb04142f041ccf9ae579c6 GIT binary patch literal 2381 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 Date: Mon, 17 Aug 2020 10:58:40 -0400 Subject: [PATCH 008/130] 6639 fix comments --- .../autopsy/discovery/AbstractFilter.java | 8 +- .../discovery/AbstractFiltersPanel.java | 15 ++- .../discovery/ArtifactTypeFilterPanel.form | 4 +- .../discovery/ArtifactTypeFilterPanel.java | 5 +- .../discovery/AttributeSearchData.java | 21 ++-- .../autopsy/discovery/Bundle_ja.properties | 4 - .../autopsy/discovery/DateFilterPanel.form | 9 +- .../autopsy/discovery/DateFilterPanel.java | 32 ++--- .../autopsy/discovery/DiscoveryDialog.java | 7 +- .../discovery/DiscoveryEventUtils.java | 18 +-- .../discovery/DiscoveryTopComponent.java | 2 +- .../discovery/DocumentFilterPanel.java | 2 +- .../autopsy/discovery/DomainFilterPanel.java | 10 +- .../DomainUniquenessFilterPanel.form | 59 ---------- .../DomainUniquenessFilterPanel.java | 111 ------------------ .../autopsy/discovery/ImageFilterPanel.java | 2 +- .../discovery/PastOccurrencesFilterPanel.java | 1 - .../autopsy/discovery/SearchData.java | 15 ++- .../autopsy/discovery/SearchFiltering.java | 92 +++++++-------- .../autopsy/discovery/VideoFilterPanel.java | 2 +- 20 files changed, 120 insertions(+), 299 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/discovery/Bundle_ja.properties delete mode 100644 Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.form delete mode 100644 Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.java diff --git a/Core/src/org/sleuthkit/autopsy/discovery/AbstractFilter.java b/Core/src/org/sleuthkit/autopsy/discovery/AbstractFilter.java index bb5320488d..4e0ecd2e79 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/AbstractFilter.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/AbstractFilter.java @@ -29,7 +29,7 @@ import org.sleuthkit.datamodel.SleuthkitCase; abstract class AbstractFilter { /** - * Returns part of a query on the tsk_files table that can be AND-ed with + * Returns part of a query on the table that can be AND-ed with * other pieces * * @return the SQL query or an empty string if there is no SQL query for @@ -48,15 +48,15 @@ abstract class AbstractFilter { } /** - * Run a secondary filter that does not operate on tsk_files. + * Run a secondary filter that does not operate on table. * - * @param currentResults The current list of matching files; empty if no + * @param currentResults The current list of matching results; empty if no * filters have yet been run. * @param caseDb The case database * @param centralRepoDb The central repo database. Can be null if the * filter does not require it. * - * @return The list of files that match this filter (and any that came + * @return The list of results that match this filter (and any that came * before it) * * @throws FileSearchException diff --git a/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java index e400f60791..d6ed042c18 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java @@ -61,21 +61,26 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li secondColumnPanel.setLayout(new GridBagLayout()); } + /** + * Get the broad ResultType, such as files or attributes. + * + * @return + */ abstract SearchData.ResultType getResultType(); /** - * Get the type of results this filters panel is for. + * Get the file type of results this filters panel is for. * - * @return The type of results this panel filters. + * @return The file type of results this panel filters. */ abstract FileSearchData.FileType getFileType(); /** - * Get the type of results this filters panel is for. + * Get the attribute type of results this filters panel is for. * - * @return The type of results this panel filters. + * @return The attribute type of results this panel filters. */ - abstract AttributeSearchData.ArtifactType getArtifactType(); + abstract AttributeSearchData.AttributeType getArtifactType(); /** * Add a DiscoveryFilterPanel to the specified column with the specified diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.form index 988d1acedf..79cd9586a3 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.form @@ -30,12 +30,12 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.java index 52cf607dba..f058b8d071 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.java @@ -25,8 +25,7 @@ import javax.swing.JList; import org.sleuthkit.datamodel.BlackboardArtifact; /** - * - * @author wschaefer + * Filter for selection of a specific Arrtifact type to limit results to. */ class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { @@ -48,7 +47,7 @@ class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { int count = 0; DefaultListModel artifactTypeModel = (DefaultListModel) jList1.getModel(); artifactTypeModel.removeAllElements(); - for (BlackboardArtifact.ARTIFACT_TYPE artifactType : AttributeSearchData.ArtifactType.DOMAIN.getBlackboardTypes()) { + for (BlackboardArtifact.ARTIFACT_TYPE artifactType : AttributeSearchData.AttributeType.DOMAIN.getBlackboardTypes()) { artifactTypeModel.add(count, new ArtifactTypeItem(artifactType)); count++; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/AttributeSearchData.java b/Core/src/org/sleuthkit/autopsy/discovery/AttributeSearchData.java index d6f5282eff..922817a654 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/AttributeSearchData.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/AttributeSearchData.java @@ -27,7 +27,7 @@ import org.openide.util.NbBundle; import org.sleuthkit.datamodel.BlackboardArtifact; /** - * Utility enums for searches made for artifacts with Discovery. + * Utility enums for searches made for attributes with Discovery. */ public class AttributeSearchData extends SearchData { @@ -39,24 +39,21 @@ public class AttributeSearchData extends SearchData { } /** - * Enum representing the file type. We don't simply use - * FileTypeUtils.FileTypeCategory because: - Some file types categories - * overlap - It is convenient to have the "OTHER" option for files that - * don't match the given types + * Enum representing the attribute type. */ @NbBundle.Messages({ - "ArtifactSearchData.ArtifactType.Domain.displayName=Domain", - "ArtifactSearchData.ArtifactType.Other.displayName=Other"}) - enum ArtifactType { + "AttributeSearchData.AttributeType.Domain.displayName=Domain", + "AttributeSearchData.AttributeType.Other.displayName=Other"}) + enum AttributeType { - DOMAIN(0, Bundle.ArtifactSearchData_ArtifactType_Domain_displayName(), DOMAIN_ARTIFACT_TYPES), - OTHER(1, Bundle.ArtifactSearchData_ArtifactType_Other_displayName(), new HashSet<>()); + DOMAIN(0, Bundle.AttributeSearchData_AttributeType_Domain_displayName(), DOMAIN_ARTIFACT_TYPES), + OTHER(1, Bundle.AttributeSearchData_AttributeType_Other_displayName(), new HashSet<>()); private final int ranking; // For ordering in the UI private final String displayName; private final Set artifactTypes = new HashSet<>(); - ArtifactType(int value, String displayName, Set types) { + AttributeType(int value, String displayName, Set types) { this.ranking = value; this.displayName = displayName; this.artifactTypes.addAll(types); @@ -85,7 +82,7 @@ public class AttributeSearchData extends SearchData { return ranking; } - static ArtifactType fromBlackboardArtifact(final BlackboardArtifact.ARTIFACT_TYPE type) { + static AttributeType fromBlackboardArtifact(final BlackboardArtifact.ARTIFACT_TYPE type) { switch (type) { case TSK_WEB_BOOKMARK: return DOMAIN; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/discovery/Bundle_ja.properties deleted file mode 100644 index 2f28dc35d8..0000000000 --- a/Core/src/org/sleuthkit/autopsy/discovery/Bundle_ja.properties +++ /dev/null @@ -1,4 +0,0 @@ - -DateFilterPanel.endCheckBox.text=\u7d42\u4e86: - -DateFilterPanel.startCheckBox.text=\u958b\u59cb: diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.form index ed1d57ecf8..f85fef8593 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.form @@ -57,7 +57,7 @@ - + @@ -81,7 +81,7 @@ - + @@ -127,9 +127,6 @@ - - - @@ -175,7 +172,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.java index 5353586761..d4e5e7bcb3 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.java @@ -26,8 +26,7 @@ import org.openide.util.NbBundle; import org.sleuthkit.autopsy.communications.Utils; /** - * - * @author wschaefer + * Filter panel for allowing the user to filter on date. */ class DateFilterPanel extends AbstractDiscoveryFilterPanel { @@ -35,7 +34,7 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { private final SpinnerNumberModel numberModel; /** - * Creates new form DateFilterPanel + * Creates new form DateFilterPanel. */ @NbBundle.Messages({"# {0} - timeZone", "DateFilterPanel.dateRange.text=Date Range ({0}):"}) @@ -43,7 +42,7 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { // numberModel is used in initComponents numberModel = new SpinnerNumberModel(10, 1, Integer.MAX_VALUE, 1); initComponents(); - jRadioButton1.setText(Bundle.DateFilterPanel_dateRange_text(Utils.getUserPreferredZoneId().toString())); + rangeRadioButton.setText(Bundle.DateFilterPanel_dateRange_text(Utils.getUserPreferredZoneId().toString())); } /** @@ -65,7 +64,7 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { startDatePicker = new com.github.lgooddatepicker.components.DatePicker(); endDatePicker = new com.github.lgooddatepicker.components.DatePicker(); endCheckBox = new javax.swing.JCheckBox(); - jRadioButton1 = new javax.swing.JRadioButton(); + rangeRadioButton = new javax.swing.JRadioButton(); org.openide.awt.Mnemonics.setLocalizedText(dateFilterCheckbox, org.openide.util.NbBundle.getMessage(DateFilterPanel.class, "DateFilterPanel.dateFilterCheckbox.text")); // NOI18N @@ -78,11 +77,6 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { buttonGroup1.add(mostRecentButton); org.openide.awt.Mnemonics.setLocalizedText(mostRecentButton, org.openide.util.NbBundle.getMessage(DateFilterPanel.class, "DateFilterPanel.mostRecentButton.text")); // NOI18N mostRecentButton.setEnabled(false); - mostRecentButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - mostRecentButtonActionPerformed(evt); - } - }); org.openide.awt.Mnemonics.setLocalizedText(startCheckBox, org.openide.util.NbBundle.getMessage(DateFilterPanel.class, "DateFilterPanel.startCheckBox.text")); // NOI18N startCheckBox.setEnabled(false); @@ -108,8 +102,8 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { } }); - buttonGroup1.add(jRadioButton1); - jRadioButton1.setEnabled(false); + buttonGroup1.add(rangeRadioButton); + rangeRadioButton.setEnabled(false); javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); @@ -121,7 +115,7 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { .addComponent(daysSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(daysLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 132, Short.MAX_VALUE)) - .addComponent(jRadioButton1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(rangeRadioButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() .addGap(30, 30, 30) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -140,7 +134,7 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { .addComponent(daysSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(daysLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jRadioButton1) + .addComponent(rangeRadioButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(startCheckBox) @@ -170,18 +164,14 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { ); }// //GEN-END:initComponents - private void mostRecentButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mostRecentButtonActionPerformed - - }//GEN-LAST:event_mostRecentButtonActionPerformed - private void startCheckBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_startCheckBoxStateChanged startDatePicker.setEnabled(startCheckBox.isSelected()); -// validateFilters(); +// validateFilters(); //TODO JIRA-6714 when search will begin doing something }//GEN-LAST:event_startCheckBoxStateChanged private void endCheckBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_endCheckBoxStateChanged endDatePicker.setEnabled(endCheckBox.isSelected()); -// validateFilters(); +// validateFilters(); //TODO JIRA-6714 when search will begin doing something }//GEN-LAST:event_endCheckBoxStateChanged @Override @@ -223,8 +213,8 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { private javax.swing.JCheckBox endCheckBox; private com.github.lgooddatepicker.components.DatePicker endDatePicker; private javax.swing.JPanel jPanel1; - private javax.swing.JRadioButton jRadioButton1; private javax.swing.JRadioButton mostRecentButton; + private javax.swing.JRadioButton rangeRadioButton; private javax.swing.JCheckBox startCheckBox; private com.github.lgooddatepicker.components.DatePicker startDatePicker; // End of variables declaration//GEN-END:variables diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java index 9d031eba88..9fd4f1a00a 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java @@ -70,7 +70,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { private static volatile boolean shouldUpdate = false; private SearchData.ResultType resultType = SearchData.ResultType.FILE; private FileSearchData.FileType fileType = FileSearchData.FileType.IMAGE; - private AttributeSearchData.ArtifactType artifactType = null; + private AttributeSearchData.AttributeType artifactType = null; private final PropertyChangeListener listener; private final Set objectsDetected = new HashSet<>(); private final Set interestingItems = new HashSet<>(); @@ -143,6 +143,9 @@ final class DiscoveryDialog extends javax.swing.JDialog { repaint(); } + /** + * Set the type buttons to a default state where none are selected. + */ private void unselectAllButtons() { imagesButton.setSelected(false); imagesButton.setEnabled(true); @@ -609,7 +612,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { domainsButton.setBackground(SELECTED_COLOR); domainsButton.setForeground(Color.BLACK); resultType = SearchData.ResultType.ATTRIBUTE; - artifactType = AttributeSearchData.ArtifactType.DOMAIN; + artifactType = AttributeSearchData.AttributeType.DOMAIN; fileType = null; documentFilterPanel.addPropertyChangeListener(listener); validateDialog(); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java index 11b814b75b..7951d6f175 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java @@ -22,7 +22,7 @@ import com.google.common.eventbus.EventBus; import java.util.Collections; import java.util.List; import java.util.Map; -import org.sleuthkit.autopsy.discovery.AttributeSearchData.ArtifactType; +import org.sleuthkit.autopsy.discovery.AttributeSearchData.AttributeType; import org.sleuthkit.autopsy.discovery.FileSearch.GroupKey; import org.sleuthkit.autopsy.discovery.FileSearchData.FileType; import org.sleuthkit.autopsy.discovery.SearchData.ResultType; @@ -58,23 +58,23 @@ final class DiscoveryEventUtils { private final ResultType resultType; private final FileType fileType; - private final ArtifactType artifactType; + private final AttributeType attributeType; /** * Construct a new SearchStartedEvent * * @param type The type of file the search event is for. */ - SearchStartedEvent(ResultType resultType, FileType fileType, ArtifactType artifactType) { + SearchStartedEvent(ResultType resultType, FileType fileType, AttributeType attributeType) { this.resultType = resultType; this.fileType = fileType; - this.artifactType = artifactType; + this.attributeType = attributeType; } /** * Get the broad search type. * - * @return The result type, either FILES, or ARTIFACTS. + * @return The result type, either FILES, or ATTRIBUTES. */ ResultType getResultType() { return resultType; @@ -90,12 +90,12 @@ final class DiscoveryEventUtils { } /** - * Get the type of artifact the search is being performed for. + * Get the type of attribute the search is being performed for. * - * @return The type of artifacts being searched for. + * @return The type of attribute being searched for. */ - ArtifactType getArtifactType() { - return artifactType; + AttributeType getAttributeType() { + return attributeType; } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java index 2b252b2073..5f47b2d694 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java @@ -288,7 +288,7 @@ public final class DiscoveryTopComponent extends TopComponent { if (searchStartedEvent.getResultType() == ResultType.FILE) { text = Bundle.DiscoveryTopComponent_searchInProgress_text(searchStartedEvent.getFileType().name()); } else if (searchStartedEvent.getResultType() == ResultType.ATTRIBUTE) { - text = Bundle.DiscoveryTopComponent_searchInProgress_text(searchStartedEvent.getArtifactType().name()); + text = Bundle.DiscoveryTopComponent_searchInProgress_text(searchStartedEvent.getAttributeType().name()); } progressMessageTextArea.setText(text); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java index 4b0c870a74..e1635c4e50 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java @@ -104,7 +104,7 @@ final class DocumentFilterPanel extends AbstractFiltersPanel { } @Override - AttributeSearchData.ArtifactType getArtifactType() { + AttributeSearchData.AttributeType getArtifactType() { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java index 9091d0f3c9..a028c88a0e 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java @@ -21,16 +21,15 @@ package org.sleuthkit.autopsy.discovery; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; /** - * - * @author wschaefer + * Filter panel for searching domain attributes with Discovery. */ public class DomainFilterPanel extends AbstractFiltersPanel { private static final long serialVersionUID = 1L; - private static final AttributeSearchData.ArtifactType ARTIFACT_TYPE = AttributeSearchData.ArtifactType.DOMAIN; + private static final AttributeSearchData.AttributeType ARTIFACT_TYPE = AttributeSearchData.AttributeType.DOMAIN; /** - * Creates new form DomainFilterPanel + * Creates new form DomainFilterPanel. */ public DomainFilterPanel() { super(); @@ -43,7 +42,6 @@ public class DomainFilterPanel extends AbstractFiltersPanel { pastOccurrencesIndices = new int[]{2, 3, 4}; addFilter(new PastOccurrencesFilterPanel(), true, pastOccurrencesIndices, 0); } - addPanelsToScrollPane(domainFiltersSplitPane); } @@ -100,7 +98,7 @@ public class DomainFilterPanel extends AbstractFiltersPanel { } @Override - AttributeSearchData.ArtifactType getArtifactType() { + AttributeSearchData.AttributeType getArtifactType() { return ARTIFACT_TYPE; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.form deleted file mode 100644 index b18df2e114..0000000000 --- a/Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.form +++ /dev/null @@ -1,59 +0,0 @@ - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.java deleted file mode 100644 index 421cfef6c4..0000000000 --- a/Core/src/org/sleuthkit/autopsy/discovery/DomainUniquenessFilterPanel.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Autopsy - * - * 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.discovery; - -import javax.swing.JCheckBox; -import javax.swing.JLabel; -import javax.swing.JList; - -/** - * - * @author wschaefer - */ -class DomainUniquenessFilterPanel extends AbstractDiscoveryFilterPanel { - - private static final long serialVersionUID = 1L; - - /** - * Creates new form DomainUniquenessFilterPanel - */ - DomainUniquenessFilterPanel() { - initComponents(); - } - - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { - - domainUniquenessCheckbox = new javax.swing.JCheckBox(); - domainUniqueScrollPane = new javax.swing.JScrollPane(); - jList1 = new javax.swing.JList<>(); - - org.openide.awt.Mnemonics.setLocalizedText(domainUniquenessCheckbox, org.openide.util.NbBundle.getMessage(DomainUniquenessFilterPanel.class, "DomainUniquenessFilterPanel.domainUniquenessCheckbox.text")); // NOI18N - - jList1.setModel(new javax.swing.AbstractListModel() { - String[] strings = { "Unique", "Multiple instances" }; - public int getSize() { return strings.length; } - public String getElementAt(int i) { return strings[i]; } - }); - jList1.setEnabled(false); - domainUniqueScrollPane.setViewportView(jList1); - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(domainUniqueScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 207, Short.MAX_VALUE) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(domainUniqueScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 48, Short.MAX_VALUE) - ); - }// //GEN-END:initComponents - - @Override - void configurePanel(boolean selected, int[] indicesSelected) { - domainUniquenessCheckbox.setSelected(selected); - } - - @Override - JCheckBox getCheckbox() { - return domainUniquenessCheckbox; - } - - @Override - JList getList() { - return null; - } - - @Override - JLabel getAdditionalLabel() { - return null; - } - - @Override - String checkForError() { - return "Domain search is not implemented."; - } - - @Override - AbstractFilter getFilter() { - return null; - } - - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JScrollPane domainUniqueScrollPane; - private javax.swing.JCheckBox domainUniquenessCheckbox; - private javax.swing.JList jList1; - // End of variables declaration//GEN-END:variables -} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.java index d86ffbe81c..b0d0d01287 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.java @@ -110,7 +110,7 @@ final class ImageFilterPanel extends AbstractFiltersPanel { } @Override - AttributeSearchData.ArtifactType getArtifactType() { + AttributeSearchData.AttributeType getArtifactType() { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java index cd20850a55..e03f32780b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java @@ -24,7 +24,6 @@ import javax.swing.JLabel; import javax.swing.JList; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.discovery.FileSearchData.Frequency; -import org.sleuthkit.autopsy.discovery.SearchData.ResultType; /** * Panel to allow configuration of the Past Occurrences filter. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/SearchData.java b/Core/src/org/sleuthkit/autopsy/discovery/SearchData.java index 357c7d9664..4368de669b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/SearchData.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/SearchData.java @@ -18,15 +18,22 @@ */ package org.sleuthkit.autopsy.discovery; - +/** + * Abstract class to contain data that is common to all result types. + */ abstract class SearchData { - + + /** + * Enum of the broad result type categories. + */ enum ResultType { FILE, ATTRIBUTE; } - + + /** + * Get the broad result type. + */ abstract ResultType getResultType(); - } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/SearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/SearchFiltering.java index a21b11fd1e..beecf6c7d1 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/SearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/SearchFiltering.java @@ -156,18 +156,18 @@ class SearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.SizeFilter.desc=Size(s): {0}", - "FileSearchFiltering.SizeFilter.or=, "}) + "SearchFiltering.SizeFilter.desc=Size(s): {0}", + "SearchFiltering.SizeFilter.or=, "}) @Override String getDesc() { String desc = ""; // NON-NLS for (FileSize size : fileSizes) { if (!desc.isEmpty()) { - desc += Bundle.FileSearchFiltering_SizeFilter_or(); + desc += Bundle.SearchFiltering_SizeFilter_or(); } desc += size.getSizeGroup(); } - desc = Bundle.FileSearchFiltering_SizeFilter_desc(desc); + desc = Bundle.SearchFiltering_SizeFilter_desc(desc); return desc; } } @@ -220,22 +220,22 @@ class SearchFiltering { } @NbBundle.Messages({ - "FileSearchFiltering.ParentSearchTerm.fullString= (exact)", - "FileSearchFiltering.ParentSearchTerm.subString= (substring)", - "FileSearchFiltering.ParentSearchTerm.includeString= (include)", - "FileSearchFiltering.ParentSearchTerm.excludeString= (exclude)",}) + "SearchFiltering.ParentSearchTerm.fullString= (exact)", + "SearchFiltering.ParentSearchTerm.subString= (substring)", + "SearchFiltering.ParentSearchTerm.includeString= (include)", + "SearchFiltering.ParentSearchTerm.excludeString= (exclude)",}) @Override public String toString() { String returnString = getSearchStr(); if (isFullPath()) { - returnString += Bundle.FileSearchFiltering_ParentSearchTerm_fullString(); + returnString += Bundle.SearchFiltering_ParentSearchTerm_fullString(); } else { - returnString += Bundle.FileSearchFiltering_ParentSearchTerm_subString(); + returnString += Bundle.SearchFiltering_ParentSearchTerm_subString(); } if (isIncluded()) { - returnString += Bundle.FileSearchFiltering_ParentSearchTerm_includeString(); + returnString += Bundle.SearchFiltering_ParentSearchTerm_includeString(); } else { - returnString += Bundle.FileSearchFiltering_ParentSearchTerm_excludeString(); + returnString += Bundle.SearchFiltering_ParentSearchTerm_excludeString(); } return returnString; } @@ -310,31 +310,31 @@ class SearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.ParentFilter.desc=Paths matching: {0}", - "FileSearchFiltering.ParentFilter.or=, ", - "FileSearchFiltering.ParentFilter.exact=(exact match)", - "FileSearchFiltering.ParentFilter.substring=(substring)", - "FileSearchFiltering.ParentFilter.included=(included)", - "FileSearchFiltering.ParentFilter.excluded=(excluded)"}) + "SearchFiltering.ParentFilter.desc=Paths matching: {0}", + "SearchFiltering.ParentFilter.or=, ", + "SearchFiltering.ParentFilter.exact=(exact match)", + "SearchFiltering.ParentFilter.substring=(substring)", + "SearchFiltering.ParentFilter.included=(included)", + "SearchFiltering.ParentFilter.excluded=(excluded)"}) @Override String getDesc() { String desc = ""; // NON-NLS for (ParentSearchTerm searchTerm : parentSearchTerms) { if (!desc.isEmpty()) { - desc += Bundle.FileSearchFiltering_ParentFilter_or(); + desc += Bundle.SearchFiltering_ParentFilter_or(); } if (searchTerm.isFullPath()) { - desc += searchTerm.getSearchStr() + Bundle.FileSearchFiltering_ParentFilter_exact(); + desc += searchTerm.getSearchStr() + Bundle.SearchFiltering_ParentFilter_exact(); } else { - desc += searchTerm.getSearchStr() + Bundle.FileSearchFiltering_ParentFilter_substring(); + desc += searchTerm.getSearchStr() + Bundle.SearchFiltering_ParentFilter_substring(); } if (searchTerm.isIncluded()) { - desc += Bundle.FileSearchFiltering_ParentFilter_included(); + desc += Bundle.SearchFiltering_ParentFilter_included(); } else { - desc += Bundle.FileSearchFiltering_ParentFilter_excluded(); + desc += Bundle.SearchFiltering_ParentFilter_excluded(); } } - desc = Bundle.FileSearchFiltering_ParentFilter_desc(desc); + desc = Bundle.SearchFiltering_ParentFilter_desc(desc); return desc; } } @@ -370,21 +370,21 @@ class SearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.DataSourceFilter.desc=Data source(s): {0}", - "FileSearchFiltering.DataSourceFilter.or=, ", + "SearchFiltering.DataSourceFilter.desc=Data source(s): {0}", + "SearchFiltering.DataSourceFilter.or=, ", "# {0} - Data source name", "# {1} - Data source ID", - "FileSearchFiltering.DataSourceFilter.datasource={0}({1})",}) + "SearchFiltering.DataSourceFilter.datasource={0}({1})",}) @Override String getDesc() { String desc = ""; // NON-NLS for (DataSource ds : dataSources) { if (!desc.isEmpty()) { - desc += Bundle.FileSearchFiltering_DataSourceFilter_or(); + desc += Bundle.SearchFiltering_DataSourceFilter_or(); } - desc += Bundle.FileSearchFiltering_DataSourceFilter_datasource(ds.getName(), ds.getId()); + desc += Bundle.SearchFiltering_DataSourceFilter_datasource(ds.getName(), ds.getId()); } - desc = Bundle.FileSearchFiltering_DataSourceFilter_desc(desc); + desc = Bundle.SearchFiltering_DataSourceFilter_desc(desc); return desc; } } @@ -419,10 +419,10 @@ class SearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.KeywordListFilter.desc=Keywords in list(s): {0}",}) + "SearchFiltering.KeywordListFilter.desc=Keywords in list(s): {0}",}) @Override String getDesc() { - return Bundle.FileSearchFiltering_KeywordListFilter_desc(concatenateSetNamesForDisplay(listNames)); + return Bundle.SearchFiltering_KeywordListFilter_desc(concatenateSetNamesForDisplay(listNames)); } } @@ -469,18 +469,18 @@ class SearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.FileTypeFilter.desc=Type: {0}", - "FileSearchFiltering.FileTypeFilter.or=, ",}) + "SearchFiltering.FileTypeFilter.desc=Type: {0}", + "SearchFiltering.FileTypeFilter.or=, ",}) @Override String getDesc() { String desc = ""; for (FileType cat : categories) { if (!desc.isEmpty()) { - desc += Bundle.FileSearchFiltering_FileTypeFilter_or(); + desc += Bundle.SearchFiltering_FileTypeFilter_or(); } desc += cat.toString(); } - desc = Bundle.FileSearchFiltering_FileTypeFilter_desc(desc); + desc = Bundle.SearchFiltering_FileTypeFilter_desc(desc); return desc; } } @@ -539,18 +539,18 @@ class SearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.FrequencyFilter.desc=Past occurrences: {0}", - "FileSearchFiltering.FrequencyFilter.or=, ",}) + "SearchFiltering.FrequencyFilter.desc=Past occurrences: {0}", + "SearchFiltering.FrequencyFilter.or=, ",}) @Override String getDesc() { String desc = ""; // NON-NLS for (Frequency freq : frequencies) { if (!desc.isEmpty()) { - desc += Bundle.FileSearchFiltering_FrequencyFilter_or(); + desc += Bundle.SearchFiltering_FrequencyFilter_or(); } desc += freq.toString(); } - return Bundle.FileSearchFiltering_FrequencyFilter_desc(desc); + return Bundle.SearchFiltering_FrequencyFilter_desc(desc); } } @@ -623,10 +623,10 @@ class SearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.InterestingItemSetFilter.desc=Interesting item hits in set(s): {0}",}) + "SearchFiltering.InterestingItemSetFilter.desc=Interesting item hits in set(s): {0}",}) @Override String getDesc() { - return Bundle.FileSearchFiltering_InterestingItemSetFilter_desc(concatenateSetNamesForDisplay(setNames)); + return Bundle.SearchFiltering_InterestingItemSetFilter_desc(concatenateSetNamesForDisplay(setNames)); } } @@ -661,10 +661,10 @@ class SearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.ObjectDetectionFilter.desc=Objects detected in set(s): {0}",}) + "SearchFiltering.ObjectDetectionFilter.desc=Objects detected in set(s): {0}",}) @Override String getDesc() { - return Bundle.FileSearchFiltering_ObjectDetectionFilter_desc(concatenateSetNamesForDisplay(typeNames)); + return Bundle.SearchFiltering_ObjectDetectionFilter_desc(concatenateSetNamesForDisplay(typeNames)); } } @@ -737,10 +737,10 @@ class SearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.ScoreFilter.desc=Score(s) of : {0}",}) + "SearchFiltering.ScoreFilter.desc=Score(s) of : {0}",}) @Override String getDesc() { - return Bundle.FileSearchFiltering_ScoreFilter_desc( + return Bundle.SearchFiltering_ScoreFilter_desc( concatenateSetNamesForDisplay(scores.stream().map(p -> p.toString()).collect(Collectors.toList()))); } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java index 698f13290e..8d0d51ef34 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java @@ -111,7 +111,7 @@ final class VideoFilterPanel extends AbstractFiltersPanel { } @Override - AttributeSearchData.ArtifactType getArtifactType() { + AttributeSearchData.AttributeType getArtifactType() { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } From d33cd161ef6f30523dc80bd5f22485b2a902d5dc Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 17 Aug 2020 11:35:27 -0400 Subject: [PATCH 009/130] 6639 disabling of other occurrences consistant --- .../autopsy/discovery/Bundle.properties | 2 +- .../discovery/Bundle.properties-MERGED | 74 +++++++++---------- .../autopsy/discovery/DateFilterPanel.form | 6 ++ .../autopsy/discovery/DateFilterPanel.java | 18 +++++ .../autopsy/discovery/DomainFilterPanel.java | 4 +- .../discovery/PastOccurrencesFilterPanel.java | 25 ++++++- 6 files changed, 85 insertions(+), 44 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties index dffbc4580e..250df96f59 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties @@ -107,7 +107,7 @@ ResultsSplitPaneDivider.detailsLabel.text=Details Area DiscoveryDialog.domainsButton.text=Domains DomainFilterPanel.domainFiltersSplitPane.border.title=Step 2: Filter which domains to show DomainFilterPanel.domainFiltersSplitPane.toolTipText= -DateFilterPanel.dateFilterCheckbox.text=Date Filter +DateFilterPanel.dateFilterCheckbox.text=Date Filter: ArtifactTypeFilterPanel.artifactTypeCheckbox.text=Artifact Type: DomainUniquenessFilterPanel.domainUniquenessCheckbox.text=Domain Uniqueness: DateFilterPanel.mostRecentButton.text=Only last: diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED index a54e5e670f..39b573d24f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED @@ -1,5 +1,5 @@ -ArtifactSearchData.ArtifactType.Domain.displayName=Domain -ArtifactSearchData.ArtifactType.Other.displayName=Other +AttributeSearchData.AttributeType.Domain.displayName=Domain +AttributeSearchData.AttributeType.Other.displayName=Other CTL_OpenDiscoveryAction=Discovery # {0} - dataSourceName DataSourceModuleWrapper.exifModule.text=Exif Parser module was not run on data source: {0}\n @@ -113,44 +113,10 @@ FileSearchDialog.orderSizeRadioButton.text=Group Size FileSearchDialog.jLabel5.text=Order files by: FileSearchDialog.parentCheckBox.text=Parent FileSearchFiltering.concatenateSetNamesForDisplay.comma=, -# {0} - Data source name -# {1} - Data source ID -FileSearchFiltering.DataSourceFilter.datasource={0}({1}) -# {0} - filters -FileSearchFiltering.DataSourceFilter.desc=Data source(s): {0} -FileSearchFiltering.DataSourceFilter.or=, -# {0} - filters -FileSearchFiltering.FileTypeFilter.desc=Type: {0} -FileSearchFiltering.FileTypeFilter.or=, -# {0} - filters -FileSearchFiltering.FrequencyFilter.desc=Past occurrences: {0} -FileSearchFiltering.FrequencyFilter.or=, # {0} - filters FileSearchFiltering.HashSetFilter.desc=Hash set hits in set(s): {0} -# {0} - filters -FileSearchFiltering.InterestingItemSetFilter.desc=Interesting item hits in set(s): {0} -# {0} - filters -FileSearchFiltering.KeywordListFilter.desc=Keywords in list(s): {0} FileSearchFiltering.KnownFilter.desc=which are not known -# {0} - filters -FileSearchFiltering.ObjectDetectionFilter.desc=Objects detected in set(s): {0} -# {0} - filters -FileSearchFiltering.ParentFilter.desc=Paths matching: {0} -FileSearchFiltering.ParentFilter.exact=(exact match) -FileSearchFiltering.ParentFilter.excluded=(excluded) -FileSearchFiltering.ParentFilter.included=(included) -FileSearchFiltering.ParentFilter.or=, -FileSearchFiltering.ParentFilter.substring=(substring) -FileSearchFiltering.ParentSearchTerm.excludeString=\ (exclude) -FileSearchFiltering.ParentSearchTerm.fullString=\ (exact) -FileSearchFiltering.ParentSearchTerm.includeString=\ (include) -FileSearchFiltering.ParentSearchTerm.subString=\ (substring) FileSearchFiltering.PreviouslyNotableFilter.desc=that were previously marked as notable -# {0} - filters -FileSearchFiltering.ScoreFilter.desc=Score(s) of : {0} -# {0} - filters -FileSearchFiltering.SizeFilter.desc=Size(s): {0} -FileSearchFiltering.SizeFilter.or=, # {0} - tag names FileSearchFiltering.TagsFilter.desc=Tagged {0} FileSearchFiltering.TagsFilter.or=, @@ -232,6 +198,40 @@ DiscoveryDialog.searchButton.text=Search DetailsPanel.instancesList.border.title=Instances ResultsPanel.unableToCreate.text=Unable to create summary. ResultsPanel.viewFileInDir.name=View File in Directory +# {0} - Data source name +# {1} - Data source ID +SearchFiltering.DataSourceFilter.datasource={0}({1}) +# {0} - filters +SearchFiltering.DataSourceFilter.desc=Data source(s): {0} +SearchFiltering.DataSourceFilter.or=, +# {0} - filters +SearchFiltering.FileTypeFilter.desc=Type: {0} +SearchFiltering.FileTypeFilter.or=, +# {0} - filters +SearchFiltering.FrequencyFilter.desc=Past occurrences: {0} +SearchFiltering.FrequencyFilter.or=, +# {0} - filters +SearchFiltering.InterestingItemSetFilter.desc=Interesting item hits in set(s): {0} +# {0} - filters +SearchFiltering.KeywordListFilter.desc=Keywords in list(s): {0} +# {0} - filters +SearchFiltering.ObjectDetectionFilter.desc=Objects detected in set(s): {0} +# {0} - filters +SearchFiltering.ParentFilter.desc=Paths matching: {0} +SearchFiltering.ParentFilter.exact=(exact match) +SearchFiltering.ParentFilter.excluded=(excluded) +SearchFiltering.ParentFilter.included=(included) +SearchFiltering.ParentFilter.or=, +SearchFiltering.ParentFilter.substring=(substring) +SearchFiltering.ParentSearchTerm.excludeString=\ (exclude) +SearchFiltering.ParentSearchTerm.fullString=\ (exact) +SearchFiltering.ParentSearchTerm.includeString=\ (include) +SearchFiltering.ParentSearchTerm.subString=\ (substring) +# {0} - filters +SearchFiltering.ScoreFilter.desc=Score(s) of : {0} +# {0} - filters +SearchFiltering.SizeFilter.desc=Size(s): {0} +SearchFiltering.SizeFilter.or=, SizeFilterPanel.sizeCheckbox.text=File Size: DataSourceFilterPanel.dataSourceCheckbox.text=Data Source: UserCreatedFilterPanel.userCreatedCheckbox.text=Possibly User Created @@ -275,7 +275,7 @@ ResultsSplitPaneDivider.detailsLabel.text=Details Area DiscoveryDialog.domainsButton.text=Domains DomainFilterPanel.domainFiltersSplitPane.border.title=Step 2: Filter which domains to show DomainFilterPanel.domainFiltersSplitPane.toolTipText= -DateFilterPanel.dateFilterCheckbox.text=Date Filter +DateFilterPanel.dateFilterCheckbox.text=Date Filter: ArtifactTypeFilterPanel.artifactTypeCheckbox.text=Artifact Type: DomainUniquenessFilterPanel.domainUniquenessCheckbox.text=Domain Uniqueness: DateFilterPanel.mostRecentButton.text=Only last: diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.form index f85fef8593..a07307e518 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.form @@ -127,6 +127,9 @@
+ + +
@@ -179,6 +182,9 @@ + + + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.java index d4e5e7bcb3..5c397ae038 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.java @@ -77,6 +77,11 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { buttonGroup1.add(mostRecentButton); org.openide.awt.Mnemonics.setLocalizedText(mostRecentButton, org.openide.util.NbBundle.getMessage(DateFilterPanel.class, "DateFilterPanel.mostRecentButton.text")); // NOI18N mostRecentButton.setEnabled(false); + mostRecentButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + mostRecentButtonActionPerformed(evt); + } + }); org.openide.awt.Mnemonics.setLocalizedText(startCheckBox, org.openide.util.NbBundle.getMessage(DateFilterPanel.class, "DateFilterPanel.startCheckBox.text")); // NOI18N startCheckBox.setEnabled(false); @@ -104,6 +109,11 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { buttonGroup1.add(rangeRadioButton); rangeRadioButton.setEnabled(false); + rangeRadioButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + rangeRadioButtonActionPerformed(evt); + } + }); javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); @@ -174,6 +184,14 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { // validateFilters(); //TODO JIRA-6714 when search will begin doing something }//GEN-LAST:event_endCheckBoxStateChanged + private void mostRecentButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mostRecentButtonActionPerformed + + }//GEN-LAST:event_mostRecentButtonActionPerformed + + private void rangeRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rangeRadioButtonActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_rangeRadioButtonActionPerformed + @Override void configurePanel(boolean selected, int[] indicesSelected) { dateFilterCheckbox.setSelected(selected); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java index a028c88a0e..b6f4a0c42b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java @@ -37,11 +37,11 @@ public class DomainFilterPanel extends AbstractFiltersPanel { addFilter(new DataSourceFilterPanel(), false, null, 0); addFilter(new ArtifactTypeFilterPanel(), false, null, 1); addFilter(new DateFilterPanel(), false, null, 1); - int[] pastOccurrencesIndices; + int[] pastOccurrencesIndices = null; if (CentralRepository.isEnabled()) { pastOccurrencesIndices = new int[]{2, 3, 4}; - addFilter(new PastOccurrencesFilterPanel(), true, pastOccurrencesIndices, 0); } + addFilter(new PastOccurrencesFilterPanel(), true, pastOccurrencesIndices, 0); addPanelsToScrollPane(domainFiltersSplitPane); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java index e03f32780b..b6979fe9e4 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java @@ -24,6 +24,7 @@ import javax.swing.JLabel; import javax.swing.JList; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.discovery.FileSearchData.Frequency; +import org.sleuthkit.autopsy.discovery.SearchData.ResultType; /** * Panel to allow configuration of the Past Occurrences filter. @@ -31,15 +32,26 @@ import org.sleuthkit.autopsy.discovery.FileSearchData.Frequency; final class PastOccurrencesFilterPanel extends AbstractDiscoveryFilterPanel { private static final long serialVersionUID = 1L; + private final ResultType type; /** * Creates new form PastOccurrencesFilterPanel. */ PastOccurrencesFilterPanel() { initComponents(); + type = ResultType.FILE; setUpFrequencyFilter(); } - + + /** + * Creates new form PastOccurrencesFilterPanel. + */ + PastOccurrencesFilterPanel(ResultType type) { + initComponents(); + this.type = type; + setUpFrequencyFilter(); + } + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -98,13 +110,15 @@ final class PastOccurrencesFilterPanel extends AbstractDiscoveryFilterPanel { int count = 0; DefaultListModel frequencyListModel = (DefaultListModel) crFrequencyList.getModel(); frequencyListModel.removeAllElements(); - if (!CentralRepository.isEnabled()) { + if (!CentralRepository.isEnabled() && type != ResultType.ATTRIBUTE) { for (FileSearchData.Frequency freq : FileSearchData.Frequency.getOptionsForFilteringWithoutCr()) { frequencyListModel.add(count, freq); } } else { for (FileSearchData.Frequency freq : FileSearchData.Frequency.getOptionsForFilteringWithCr()) { - frequencyListModel.add(count, freq); + if (type == ResultType.FILE || freq != FileSearchData.Frequency.KNOWN) { + frequencyListModel.add(count, freq); + } } } } @@ -117,7 +131,10 @@ final class PastOccurrencesFilterPanel extends AbstractDiscoveryFilterPanel { @Override void configurePanel(boolean selected, int[] indicesSelected) { - pastOccurrencesCheckbox.setSelected(selected); + boolean canBeFilteredOn = type == ResultType.FILE || CentralRepository.isEnabled(); + pastOccurrencesCheckbox.setEnabled(canBeFilteredOn); + pastOccurrencesCheckbox.setSelected(selected && canBeFilteredOn); + if (pastOccurrencesCheckbox.isEnabled() && pastOccurrencesCheckbox.isSelected()) { crFrequencyScrollPane.setEnabled(true); crFrequencyList.setEnabled(true); From 881b31bb60e76f1d783f5d6fdfd6ae5b7fee2b3f Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 17 Aug 2020 11:43:21 -0400 Subject: [PATCH 010/130] 6610 move UI files --- .../autopsy/discovery/Bundle.properties | 51 ---------------- .../discovery/DiscoveryEventUtils.java | 1 + .../autopsy/discovery/FileSearch.java | 2 + .../autopsy/discovery/SearchFiltering.java | 1 + .../AbstractDiscoveryFilterPanel.java | 2 +- .../discovery/{ => ui}/AbstractFilter.java | 4 +- .../{ => ui}/AbstractFiltersPanel.java | 6 +- .../{ => ui}/ArtifactTypeFilterPanel.form | 2 +- .../{ => ui}/ArtifactTypeFilterPanel.java | 7 ++- .../autopsy/discovery/ui/Bundle.properties | 55 ++++++++++++++++++ .../{ => ui}/DataSourceFilterPanel.form | 2 +- .../{ => ui}/DataSourceFilterPanel.java | 3 +- .../{ => ui}/DataSourceModulesWrapper.java | 3 +- .../discovery/{ => ui}/DateFilterPanel.form | 10 ++-- .../discovery/{ => ui}/DateFilterPanel.java | 3 +- .../discovery/{ => ui}/DetailsPanel.form | 2 +- .../discovery/{ => ui}/DetailsPanel.java | 4 +- .../discovery/{ => ui}/DiscoveryDialog.form | 23 ++++---- .../discovery/{ => ui}/DiscoveryDialog.java | 11 +++- .../{ => ui}/DiscoveryExtractAction.java | 2 +- .../{ => ui}/DiscoveryThumbnailChildren.java | 2 +- .../{ => ui}/DiscoveryTopComponent.form | 0 .../{ => ui}/DiscoveryTopComponent.java | 4 +- .../discovery/{ => ui}/DiscoveryUiUtils.java | 4 +- .../{ => ui}/DocumentFilterPanel.form | 4 +- .../{ => ui}/DocumentFilterPanel.java | 5 +- .../discovery/{ => ui}/DocumentPanel.form | 16 ++--- .../discovery/{ => ui}/DocumentPanel.java | 16 ++--- .../{ => ui}/DocumentPreviewViewer.form | 0 .../{ => ui}/DocumentPreviewViewer.java | 2 +- .../discovery/{ => ui}/DocumentWrapper.java | 4 +- .../discovery/{ => ui}/DomainFilterPanel.form | 4 +- .../discovery/{ => ui}/DomainFilterPanel.java | 5 +- .../discovery/{ => ui}/GroupListPanel.form | 2 +- .../discovery/{ => ui}/GroupListPanel.java | 7 ++- .../{ => ui}/HashSetFilterPanel.form | 2 +- .../{ => ui}/HashSetFilterPanel.java | 3 +- .../discovery/{ => ui}/ImageFilterPanel.form | 4 +- .../discovery/{ => ui}/ImageFilterPanel.java | 5 +- .../{ => ui}/ImageThumbnailPanel.form | 14 ++--- .../{ => ui}/ImageThumbnailPanel.java | 15 ++--- .../{ => ui}/ImageThumbnailViewer.form | 0 .../{ => ui}/ImageThumbnailViewer.java | 2 +- .../{ => ui}/ImageThumbnailWrapper.java | 3 +- .../{ => ui}/InterestingItemsFilterPanel.form | 2 +- .../{ => ui}/InterestingItemsFilterPanel.java | 3 +- .../{ => ui}/ObjectDetectedFilterPanel.form | 0 .../{ => ui}/ObjectDetectedFilterPanel.java | 3 +- .../{ => ui}/OpenDiscoveryAction.java | 3 +- .../discovery/{ => ui}/PageWorker.java | 9 ++- .../{ => ui}/ParentFolderFilterPanel.form | 16 ++--- .../{ => ui}/ParentFolderFilterPanel.java | 3 +- .../{ => ui}/PastOccurrencesFilterPanel.form | 2 +- .../{ => ui}/PastOccurrencesFilterPanel.java | 4 +- .../discovery/{ => ui}/ResultsPanel.form | 8 +-- .../discovery/{ => ui}/ResultsPanel.java | 9 ++- .../{ => ui}/ResultsSplitPaneDivider.form | 6 +- .../{ => ui}/ResultsSplitPaneDivider.java | 3 +- .../discovery/{ => ui}/SearchWorker.java | 7 ++- .../discovery/{ => ui}/SizeFilterPanel.form | 2 +- .../discovery/{ => ui}/SizeFilterPanel.java | 4 +- .../discovery/{ => ui}/SwingAnimator.java | 2 +- .../{ => ui}/SwingAnimatorCallback.java | 2 +- .../{ => ui}/UserCreatedFilterPanel.form | 2 +- .../{ => ui}/UserCreatedFilterPanel.java | 3 +- .../discovery/{ => ui}/VideoFilterPanel.form | 2 +- .../discovery/{ => ui}/VideoFilterPanel.java | 5 +- .../{ => ui}/VideoThumbnailPanel.form | 12 ++-- .../{ => ui}/VideoThumbnailPanel.java | 15 ++--- .../{ => ui}/VideoThumbnailViewer.form | 4 +- .../{ => ui}/VideoThumbnailViewer.java | 6 +- .../{ => ui}/VideoThumbnailsWrapper.java | 3 +- .../autopsy/discovery/{ => ui}/arrow-down.png | Bin .../autopsy/discovery/{ => ui}/arrow-up.png | Bin 74 files changed, 270 insertions(+), 187 deletions(-) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/AbstractDiscoveryFilterPanel.java (98%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/AbstractFilter.java (93%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/AbstractFiltersPanel.java (97%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/ArtifactTypeFilterPanel.form (94%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/ArtifactTypeFilterPanel.java (95%) create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DataSourceFilterPanel.form (96%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DataSourceFilterPanel.java (98%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DataSourceModulesWrapper.java (98%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DateFilterPanel.form (94%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DateFilterPanel.java (99%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DetailsPanel.form (97%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DetailsPanel.java (98%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DiscoveryDialog.form (93%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DiscoveryDialog.java (98%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DiscoveryExtractAction.java (97%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DiscoveryThumbnailChildren.java (98%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DiscoveryTopComponent.form (100%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DiscoveryTopComponent.java (99%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DiscoveryUiUtils.java (98%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DocumentFilterPanel.form (95%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DocumentFilterPanel.java (95%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DocumentPanel.form (88%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DocumentPanel.java (92%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DocumentPreviewViewer.form (100%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DocumentPreviewViewer.java (99%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DocumentWrapper.java (94%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DomainFilterPanel.form (92%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/DomainFilterPanel.java (95%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/GroupListPanel.form (95%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/GroupListPanel.java (96%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/HashSetFilterPanel.form (95%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/HashSetFilterPanel.java (98%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/ImageFilterPanel.form (92%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/ImageFilterPanel.java (95%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/ImageThumbnailPanel.form (89%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/ImageThumbnailPanel.java (91%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/ImageThumbnailViewer.form (100%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/ImageThumbnailViewer.java (98%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/ImageThumbnailWrapper.java (95%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/InterestingItemsFilterPanel.form (95%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/InterestingItemsFilterPanel.java (98%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/ObjectDetectedFilterPanel.form (100%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/ObjectDetectedFilterPanel.java (98%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/OpenDiscoveryAction.java (97%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/PageWorker.java (91%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/ParentFolderFilterPanel.form (93%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/ParentFolderFilterPanel.java (99%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/PastOccurrencesFilterPanel.form (95%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/PastOccurrencesFilterPanel.java (97%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/ResultsPanel.form (97%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/ResultsPanel.java (98%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/ResultsSplitPaneDivider.form (93%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/ResultsSplitPaneDivider.java (98%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/SearchWorker.java (91%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/SizeFilterPanel.form (96%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/SizeFilterPanel.java (97%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/SwingAnimator.java (98%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/SwingAnimatorCallback.java (96%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/UserCreatedFilterPanel.form (93%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/UserCreatedFilterPanel.java (97%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/VideoFilterPanel.form (95%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/VideoFilterPanel.java (95%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/VideoThumbnailPanel.form (88%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/VideoThumbnailPanel.java (93%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/VideoThumbnailViewer.form (97%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/VideoThumbnailViewer.java (95%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/VideoThumbnailsWrapper.java (96%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/arrow-down.png (100%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/arrow-up.png (100%) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties index 250df96f59..82c3178cef 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties @@ -44,33 +44,14 @@ FileSearchPanel.interestingItemsCheckbox.text=Interesting Item: FileSearchPanel.scoreCheckbox.text=Has Score: FileSearchPanel.notableCheckbox.text=Must have been tagged as notable FileSearchPanel.objectsCheckbox.text=Object Detected: -ResultsPanel.currentPageLabel.text=Page: - -ResultsPanel.pageControlsLabel.text=Pages: -ResultsPanel.gotoPageLabel.text=Go to Page: -ResultsPanel.pageSizeLabel.text=Page Size: DiscoveryExtractAction.title.extractFiles.text=Extract File FileSearchPanel.includeRadioButton.text=Include FileSearchPanel.excludeRadioButton.text=Exclude FileSearchPanel.knownFilesCheckbox.toolTipText= FileSearchPanel.knownFilesCheckbox.text=Hide known files -GroupListPanel.groupKeyList.border.title=Groups FileSearchPanel.stepThreeLabel.text=Step 3: Choose display settings -DocumentPanel.fileSizeLabel.toolTipText= -DocumentPanel.isDeletedLabel.toolTipText= -ImageThumbnailPanel.isDeletedLabel.toolTipText= FileSearchPanel.userCreatedCheckbox.text=Possibly User Created -DiscoveryDialog.documentsButton.text=Documents -DiscoveryDialog.videosButton.text=Videos -DiscoveryDialog.imagesButton.text=Images -DiscoveryDialog.searchButton.text=Search -DetailsPanel.instancesList.border.title=Instances -SizeFilterPanel.sizeCheckbox.text=File Size: -DataSourceFilterPanel.dataSourceCheckbox.text=Data Source: UserCreatedFilterPanel.userCreatedCheckbox.text=Possibly User Created -# To change this license header, choose License Headers in Project Properties. -# To change this template file, choose Tools | Templates -# and open the template in the editor. -HashSetFilterPanel.hashSetCheckbox.text=Hash Set: InterestingItemFilterPanel.interestingItemsCheckbox.text=Interesting Item: ParentFolderFilterPanel.parentCheckbox.text=Parent Folder: ParentFolderFilterPanel.deleteButton.text=Delete @@ -80,37 +61,5 @@ ParentFolderFilterPanel.substringRadioButton.text=Substring ParentFolderFilterPanel.fullRadioButton.text=Full ParentFolderFilterPanel.parentLabel.text=(All will be used) ParentFolderFilterPanel.addButton.text=Add -ParentFolderFilterPanel.parentCheckbox.text_1=Parent Folder: -ParentFolderFilterPanel.addButton.text_1=Add -ParentFolderFilterPanel.deleteButton.text_1=Delete -ParentFolderFilterPanel.excludeRadioButton.text_1=Exclude -ParentFolderFilterPanel.substringRadioButton.text_1=Substring -ParentFolderFilterPanel.includeRadioButton.text_1=Include -ParentFolderFilterPanel.fullRadioButton.text_1=Full -ParentFolderFilterPanel.parentLabel.text_1=(All will be used) -InterestingItemsFilterPanel.interestingItemsCheckbox.text=Interesting Item: -UserCreatedFilterPanel.userCreatedCheckbox.text_1=Possibly User Created -PastOccurrencesFilterPanel.pastOccurrencesCheckbox.text=Past Occurrences: ObjectDetectedFilterPanel.text=Object Detected: -DiscoveryDialog.sortingPanel.border.title=Step 3: Choose display settings -DiscoveryDialog.groupByLabel.text=Group By: -DiscoveryDialog.orderByLabel.text=Order Within Groups By: -DiscoveryDialog.orderGroupsByLabel.text=Order Groups By: -ImageFilterPanel.imageFiltersSplitPane.toolTipText= -DocumentFilterPanel.documentsFiltersSplitPane.border.title=Step 2: Filter which documents to show -ImageFilterPanel.imageFiltersSplitPane.border.title=Step 2: Filter which images to show -VideoFilterPanel.videoFiltersSplitPane.border.title=Step 2: Filter which videos to show -DiscoveryDialog.step1Label.text=Step 1: Choose result type -ResultsSplitPaneDivider.hideButton.text= -ResultsSplitPaneDivider.showButton.text= -ResultsSplitPaneDivider.detailsLabel.text=Details Area -DiscoveryDialog.domainsButton.text=Domains -DomainFilterPanel.domainFiltersSplitPane.border.title=Step 2: Filter which domains to show -DomainFilterPanel.domainFiltersSplitPane.toolTipText= -DateFilterPanel.dateFilterCheckbox.text=Date Filter: -ArtifactTypeFilterPanel.artifactTypeCheckbox.text=Artifact Type: DomainUniquenessFilterPanel.domainUniquenessCheckbox.text=Domain Uniqueness: -DateFilterPanel.mostRecentButton.text=Only last: -DateFilterPanel.daysLabel.text=days of activity -DateFilterPanel.endCheckBox.text=End: -DateFilterPanel.startCheckBox.text=Start: diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java index 7951d6f175..4507d06f18 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.discovery; +import org.sleuthkit.autopsy.discovery.ui.AbstractFilter; import com.google.common.eventbus.EventBus; import java.util.Collections; import java.util.List; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/FileSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/FileSearch.java index a2fad07be3..09dd98882c 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/FileSearch.java @@ -18,6 +18,8 @@ */ package org.sleuthkit.autopsy.discovery; +import org.sleuthkit.autopsy.discovery.ui.VideoThumbnailsWrapper; +import org.sleuthkit.autopsy.discovery.ui.AbstractFilter; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.io.Files; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/SearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/SearchFiltering.java index beecf6c7d1..bf52e38563 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/SearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/SearchFiltering.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.discovery; +import org.sleuthkit.autopsy.discovery.ui.AbstractFilter; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/AbstractDiscoveryFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractDiscoveryFilterPanel.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/discovery/AbstractDiscoveryFilterPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractDiscoveryFilterPanel.java index 36e0318a75..2be3071af6 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/AbstractDiscoveryFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractDiscoveryFilterPanel.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.awt.event.ActionListener; import javax.swing.JCheckBox; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/AbstractFilter.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFilter.java similarity index 93% rename from Core/src/org/sleuthkit/autopsy/discovery/AbstractFilter.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFilter.java index 4e0ecd2e79..1ac8ed925e 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/AbstractFilter.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFilter.java @@ -16,11 +16,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.util.ArrayList; import java.util.List; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.discovery.FileSearchException; +import org.sleuthkit.autopsy.discovery.ResultFile; import org.sleuthkit.datamodel.SleuthkitCase; /** diff --git a/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java similarity index 97% rename from Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java index d6ed042c18..eb7d0de8c8 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.awt.Component; import java.awt.GridBagConstraints; @@ -31,6 +31,10 @@ import javax.swing.JSplitPane; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import org.apache.commons.lang3.StringUtils; +import org.sleuthkit.autopsy.discovery.AttributeSearchData; +import org.sleuthkit.autopsy.discovery.FileSearchData; +import org.sleuthkit.autopsy.discovery.SearchData; +import org.sleuthkit.autopsy.discovery.SearchFiltering; /** * Abstract class extending JPanel for displaying all the filters associated diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.form similarity index 94% rename from Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.form index 79cd9586a3..d269dc7d15 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.form @@ -5,7 +5,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java similarity index 95% rename from Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java index f058b8d071..c7691cb2b0 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ArtifactTypeFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java @@ -16,12 +16,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; +import org.sleuthkit.autopsy.discovery.AttributeSearchData; import org.sleuthkit.datamodel.BlackboardArtifact; /** @@ -80,11 +81,11 @@ class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(artifactTypeScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 229, Short.MAX_VALUE) + .addComponent(artifactTypeScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(artifactTypeScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 38, Short.MAX_VALUE) + .addComponent(artifactTypeScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); }// //GEN-END:initComponents diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties new file mode 100644 index 0000000000..a2873c3d89 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties @@ -0,0 +1,55 @@ +# To change this license header, choose License Headers in Project Properties. +# To change this template file, choose Tools | Templates +# and open the template in the editor. + +DiscoveryDialog.sortingPanel.border.title=Step 3: Choose display settings +DiscoveryDialog.searchButton.text=Search +DiscoveryDialog.domainsButton.text=Domains +DiscoveryDialog.groupByLabel.text=Group By: +DiscoveryDialog.step1Label.text=Step 1: Choose result type +DiscoveryDialog.orderByLabel.text=Order Within Groups By: +DiscoveryDialog.documentsButton.text=Documents +DiscoveryDialog.orderGroupsByLabel.text=Order Groups By: +DiscoveryDialog.videosButton.text=Videos +DiscoveryDialog.imagesButton.text=Images +VideoFilterPanel.videoFiltersSplitPane.border.title=Step 2: Filter which videos to show +DataSourceFilterPanel.dataSourceCheckbox.text=Data Source: +ParentFolderFilterPanel.parentLabel.text_1=(All will be used) +ParentFolderFilterPanel.parentCheckbox.text_1=Parent Folder: +ParentFolderFilterPanel.addButton.text_1=Add +ParentFolderFilterPanel.deleteButton.text_1=Delete +ParentFolderFilterPanel.excludeRadioButton.text_1=Exclude +ParentFolderFilterPanel.substringRadioButton.text_1=Substring +ParentFolderFilterPanel.includeRadioButton.text_1=Include +ParentFolderFilterPanel.fullRadioButton.text_1=Full +UserCreatedFilterPanel.userCreatedCheckbox.text_1=Possibly User Created +GroupListPanel.groupKeyList.border.title=Groups +ResultsSplitPaneDivider.detailsLabel.text=Details Area +ResultsSplitPaneDivider.showButton.text= +ResultsSplitPaneDivider.hideButton.text= +ImageFilterPanel.imageFiltersSplitPane.toolTipText= +ImageFilterPanel.imageFiltersSplitPane.border.title=Step 2: Filter which images to show +ArtifactTypeFilterPanel.artifactTypeCheckbox.text=Artifact Type: +InterestingItemsFilterPanel.interestingItemsCheckbox.text=Interesting Item: +DocumentPanel.fileSizeLabel.toolTipText= +DocumentPanel.isDeletedLabel.toolTipText= +DomainFilterPanel.domainFiltersSplitPane.toolTipText= +DomainFilterPanel.domainFiltersSplitPane.border.title=Step 2: Filter which domains to show +SizeFilterPanel.sizeCheckbox.text=File Size: +DateFilterPanel.dateFilterCheckbox.text=Date Filter: +DateFilterPanel.endCheckBox.text=End: +DateFilterPanel.startCheckBox.text=Start: +DateFilterPanel.mostRecentButton.text=Only last: +DateFilterPanel.daysLabel.text=days of activity +ImageThumbnailPanel.isDeletedLabel.toolTipText= +ResultsPanel.pageControlsLabel.text=Pages: +ResultsPanel.currentPageLabel.text=Page: - +ResultsPanel.pageSizeLabel.text=Page Size: +ResultsPanel.gotoPageLabel.text=Go to Page: +# To change this license header, choose License Headers in Project Properties. +# To change this template file, choose Tools | Templates +# and open the template in the editor. +HashSetFilterPanel.hashSetCheckbox.text=Hash Set: +PastOccurrencesFilterPanel.pastOccurrencesCheckbox.text=Past Occurrences: +DocumentFilterPanel.documentsFiltersSplitPane.border.title=Step 2: Filter which documents to show +DetailsPanel.instancesList.border.title=Instances diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DataSourceFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DataSourceFilterPanel.form similarity index 96% rename from Core/src/org/sleuthkit/autopsy/discovery/DataSourceFilterPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/DataSourceFilterPanel.form index 44ea93cd5a..3f2a9d4a1d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DataSourceFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DataSourceFilterPanel.form @@ -5,7 +5,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DataSourceFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DataSourceFilterPanel.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/discovery/DataSourceFilterPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/DataSourceFilterPanel.java index 6afc8c6c69..6321afa357 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DataSourceFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DataSourceFilterPanel.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.util.List; import java.util.logging.Level; @@ -27,6 +27,7 @@ import javax.swing.JLabel; import javax.swing.JList; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.discovery.SearchFiltering; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DataSourceModulesWrapper.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DataSourceModulesWrapper.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/discovery/DataSourceModulesWrapper.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/DataSourceModulesWrapper.java index b1857c2413..170aec7acf 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DataSourceModulesWrapper.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DataSourceModulesWrapper.java @@ -16,9 +16,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.discovery.Bundle; import org.sleuthkit.autopsy.modules.exif.ExifParserModuleFactory; import org.sleuthkit.autopsy.modules.filetypeid.FileTypeIdModuleFactory; import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupModuleFactory; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form similarity index 94% rename from Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form index a07307e518..6801b3f579 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form @@ -7,7 +7,7 @@ - + @@ -112,7 +112,7 @@ - + @@ -123,7 +123,7 @@ - + @@ -134,7 +134,7 @@ - + @@ -167,7 +167,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java index 5c397ae038..1776e862d4 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DateFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import javax.swing.JCheckBox; import javax.swing.JLabel; @@ -24,6 +24,7 @@ import javax.swing.JList; import javax.swing.SpinnerNumberModel; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.communications.Utils; +import org.sleuthkit.autopsy.discovery.Bundle; /** * Filter panel for allowing the user to filter on date. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DetailsPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DetailsPanel.form similarity index 97% rename from Core/src/org/sleuthkit/autopsy/discovery/DetailsPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/DetailsPanel.form index 32f78a9645..bd3d8c5af9 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DetailsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DetailsPanel.form @@ -106,7 +106,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DetailsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DetailsPanel.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/discovery/DetailsPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/DetailsPanel.java index 6b0a37e276..9b30ef3383 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DetailsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DetailsPanel.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import com.google.common.eventbus.Subscribe; import java.awt.Component; @@ -39,6 +39,8 @@ import org.sleuthkit.autopsy.corecomponents.TableFilterNode; import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; +import org.sleuthkit.autopsy.discovery.Bundle; +import org.sleuthkit.autopsy.discovery.DiscoveryEventUtils; import org.sleuthkit.autopsy.modules.hashdatabase.AddContentToHashDbAction; import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction; import org.sleuthkit.datamodel.AbstractFile; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.form similarity index 93% rename from Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.form index 93d2015fdb..522cd9b43e 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.form @@ -6,9 +6,6 @@ - - - @@ -94,7 +91,7 @@ - + @@ -121,7 +118,7 @@ - + @@ -151,7 +148,7 @@ - + @@ -168,7 +165,7 @@ - + @@ -200,7 +197,7 @@ - + @@ -263,7 +260,7 @@ - + @@ -282,7 +279,7 @@ - + @@ -361,7 +358,7 @@ - + @@ -372,7 +369,7 @@ - + @@ -383,7 +380,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index 9fd4f1a00a..977a6fa046 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import static java.awt.BorderLayout.CENTER; import java.awt.Color; @@ -36,11 +36,19 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.discovery.AttributeSearchData; +import org.sleuthkit.autopsy.discovery.Bundle; +import org.sleuthkit.autopsy.discovery.DiscoveryEventUtils; +import org.sleuthkit.autopsy.discovery.FileGroup; import org.sleuthkit.autopsy.discovery.FileGroup.GroupSortingAlgorithm; +import org.sleuthkit.autopsy.discovery.FileSearch; import static org.sleuthkit.autopsy.discovery.FileGroup.GroupSortingAlgorithm.BY_GROUP_SIZE; import org.sleuthkit.autopsy.discovery.FileSearch.GroupingAttributeType; +import org.sleuthkit.autopsy.discovery.FileSearchData; +import org.sleuthkit.autopsy.discovery.FileSorter; import static org.sleuthkit.autopsy.discovery.FileSearch.GroupingAttributeType.PARENT_PATH; import org.sleuthkit.autopsy.discovery.FileSorter.SortingMethod; +import org.sleuthkit.autopsy.discovery.SearchData; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -298,7 +306,6 @@ final class DiscoveryDialog extends javax.swing.JDialog { setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); setMinimumSize(new java.awt.Dimension(600, 300)); - setPreferredSize(new java.awt.Dimension(1000, 650)); imagesButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/pictures-icon.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(imagesButton, org.openide.util.NbBundle.getMessage(DiscoveryDialog.class, "DiscoveryDialog.imagesButton.text")); // NOI18N diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryExtractAction.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryExtractAction.java similarity index 97% rename from Core/src/org/sleuthkit/autopsy/discovery/DiscoveryExtractAction.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryExtractAction.java index acaf0ccc99..7965878017 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryExtractAction.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryExtractAction.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import org.sleuthkit.autopsy.directorytree.actionhelpers.ExtractActionHelper; import java.awt.event.ActionEvent; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryThumbnailChildren.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryThumbnailChildren.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/discovery/DiscoveryThumbnailChildren.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryThumbnailChildren.java index bdcf2f876f..dce68e3a41 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryThumbnailChildren.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryThumbnailChildren.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.util.Arrays; import java.util.HashSet; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.form similarity index 100% rename from Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.form diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java index 5f47b2d694..010a086b30 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import com.google.common.eventbus.Subscribe; import java.awt.BorderLayout; @@ -36,6 +36,8 @@ import org.openide.windows.RetainLocation; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.coreutils.ThreadConfined; +import org.sleuthkit.autopsy.discovery.Bundle; +import org.sleuthkit.autopsy.discovery.DiscoveryEventUtils; import org.sleuthkit.autopsy.discovery.SearchData.ResultType; /** diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryUiUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryUiUtils.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/discovery/DiscoveryUiUtils.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryUiUtils.java index 55392f54f2..72b0d5db3b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryUiUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryUiUtils.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.awt.Component; import java.awt.Dimension; @@ -37,6 +37,8 @@ import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.discovery.Bundle; +import org.sleuthkit.autopsy.discovery.ResultFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.DataSource; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentFilterPanel.form similarity index 95% rename from Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentFilterPanel.form index a1c49c4c07..16b22c3672 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentFilterPanel.form @@ -58,14 +58,14 @@ + - + - diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentFilterPanel.java similarity index 95% rename from Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentFilterPanel.java index e1635c4e50..29e29972bd 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentFilterPanel.java @@ -16,9 +16,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.discovery.AttributeSearchData; +import org.sleuthkit.autopsy.discovery.FileSearchData; +import org.sleuthkit.autopsy.discovery.SearchData; /** * Class which displays all filters available for the Documents search type. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DocumentPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentPanel.form similarity index 88% rename from Core/src/org/sleuthkit/autopsy/discovery/DocumentPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentPanel.form index bb29cdb8b4..9329d6f976 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DocumentPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentPanel.form @@ -80,16 +80,16 @@ - + - + - + - + @@ -100,20 +100,20 @@ - + - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DocumentPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentPanel.java similarity index 92% rename from Core/src/org/sleuthkit/autopsy/discovery/DocumentPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentPanel.java index 2852c7579a..78d88e9cb7 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DocumentPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentPanel.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.awt.Color; import java.awt.Component; @@ -29,6 +29,8 @@ import javax.swing.JList; import javax.swing.ListCellRenderer; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.corecomponents.AutoWrappingJTextPane; +import org.sleuthkit.autopsy.discovery.Bundle; +import org.sleuthkit.autopsy.discovery.FileSearchData; /** * Class which displays a preview and details about a document. @@ -67,15 +69,15 @@ class DocumentPanel extends javax.swing.JPanel implements ListCellRenderer - + - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java similarity index 95% rename from Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java index b6f4a0c42b..05e0907935 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java @@ -16,9 +16,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.discovery.AttributeSearchData; +import org.sleuthkit.autopsy.discovery.FileSearchData; +import org.sleuthkit.autopsy.discovery.SearchData; /** * Filter panel for searching domain attributes with Discovery. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/GroupListPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.form similarity index 95% rename from Core/src/org/sleuthkit/autopsy/discovery/GroupListPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.form index be51027b3a..47ead7ce0b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/GroupListPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.form @@ -46,7 +46,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/GroupListPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java similarity index 96% rename from Core/src/org/sleuthkit/autopsy/discovery/GroupListPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java index caaacd1d30..46de95137c 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/GroupListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import com.google.common.eventbus.Subscribe; import java.awt.Cursor; @@ -28,8 +28,13 @@ import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.discovery.Bundle; +import org.sleuthkit.autopsy.discovery.DiscoveryEventUtils; +import org.sleuthkit.autopsy.discovery.FileGroup; +import org.sleuthkit.autopsy.discovery.FileSearch; import org.sleuthkit.autopsy.discovery.FileSearch.GroupKey; import org.sleuthkit.autopsy.discovery.FileSearchData.FileType; +import org.sleuthkit.autopsy.discovery.FileSorter; /** * Panel to display the list of groups which are provided by a search. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/HashSetFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/HashSetFilterPanel.form similarity index 95% rename from Core/src/org/sleuthkit/autopsy/discovery/HashSetFilterPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/HashSetFilterPanel.form index 8f83bc0e77..56c033db74 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/HashSetFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/HashSetFilterPanel.form @@ -5,7 +5,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/HashSetFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/HashSetFilterPanel.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/discovery/HashSetFilterPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/HashSetFilterPanel.java index 17673cfece..1703737c1c 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/HashSetFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/HashSetFilterPanel.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.util.List; import java.util.logging.Level; @@ -25,6 +25,7 @@ import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.discovery.SearchFiltering; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.TskCoreException; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageFilterPanel.form similarity index 92% rename from Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/ImageFilterPanel.form index 7a3374f5cb..0eab977a06 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageFilterPanel.form @@ -61,13 +61,13 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageFilterPanel.java similarity index 95% rename from Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/ImageFilterPanel.java index b0d0d01287..8008b9a41f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ImageFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageFilterPanel.java @@ -16,9 +16,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.discovery.AttributeSearchData; +import org.sleuthkit.autopsy.discovery.FileSearchData; +import org.sleuthkit.autopsy.discovery.SearchData; /** * Panel for displaying all the filters associated with the Image type. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageThumbnailPanel.form similarity index 89% rename from Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/ImageThumbnailPanel.form index c3ae30091c..46c5d3601f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageThumbnailPanel.form @@ -102,16 +102,16 @@ - + - + - + - + @@ -122,13 +122,13 @@ - + - + - +
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageThumbnailPanel.java similarity index 91% rename from Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/ImageThumbnailPanel.java index 8f7b90ad08..88c2eb9526 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageThumbnailPanel.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.awt.Color; import java.awt.Component; @@ -28,6 +28,7 @@ import javax.swing.JComponent; import javax.swing.JList; import javax.swing.ListCellRenderer; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.discovery.Bundle; /** * Class which displays a thumbnail and information for an image file. @@ -76,15 +77,15 @@ final class ImageThumbnailPanel extends javax.swing.JPanel implements ListCellRe isDeletedLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/file-icon-deleted.png"))); // NOI18N isDeletedLabel.setToolTipText(org.openide.util.NbBundle.getMessage(ImageThumbnailPanel.class, "ImageThumbnailPanel.isDeletedLabel.toolTipText")); // NOI18N - isDeletedLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())); - isDeletedLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())); - isDeletedLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())); + isDeletedLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize())); + isDeletedLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize())); + isDeletedLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize())); scoreLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/red-circle-exclamation.png"))); // NOI18N scoreLabel.setToolTipText(""); - scoreLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())); - scoreLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())); - scoreLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())); + scoreLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize())); + scoreLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize())); + scoreLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize())); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailViewer.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageThumbnailViewer.form similarity index 100% rename from Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailViewer.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/ImageThumbnailViewer.form diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailViewer.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageThumbnailViewer.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailViewer.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/ImageThumbnailViewer.java index b1f5ce97e7..273cca8023 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailViewer.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageThumbnailViewer.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.util.ArrayList; import java.util.List; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailWrapper.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageThumbnailWrapper.java similarity index 95% rename from Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailWrapper.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/ImageThumbnailWrapper.java index b4e7bb0b01..2dc072b175 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ImageThumbnailWrapper.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageThumbnailWrapper.java @@ -16,10 +16,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.awt.Image; import org.sleuthkit.autopsy.coreutils.ImageUtils; +import org.sleuthkit.autopsy.discovery.ResultFile; /** * Class to wrap all the information necessary for an image thumbnail to be diff --git a/Core/src/org/sleuthkit/autopsy/discovery/InterestingItemsFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/InterestingItemsFilterPanel.form similarity index 95% rename from Core/src/org/sleuthkit/autopsy/discovery/InterestingItemsFilterPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/InterestingItemsFilterPanel.form index ff3b7cea10..c5a8660cdd 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/InterestingItemsFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/InterestingItemsFilterPanel.form @@ -5,7 +5,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/InterestingItemsFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/InterestingItemsFilterPanel.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/discovery/InterestingItemsFilterPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/InterestingItemsFilterPanel.java index 1eea4a020b..1106391d9b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/InterestingItemsFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/InterestingItemsFilterPanel.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.util.List; import java.util.logging.Level; @@ -25,6 +25,7 @@ import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.discovery.SearchFiltering; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.TskCoreException; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ObjectDetectedFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/ObjectDetectedFilterPanel.form similarity index 100% rename from Core/src/org/sleuthkit/autopsy/discovery/ObjectDetectedFilterPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/ObjectDetectedFilterPanel.form diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ObjectDetectedFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ObjectDetectedFilterPanel.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/discovery/ObjectDetectedFilterPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/ObjectDetectedFilterPanel.java index a87c826f33..4dacc11d55 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ObjectDetectedFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ObjectDetectedFilterPanel.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.util.List; import java.util.logging.Level; @@ -25,6 +25,7 @@ import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.discovery.SearchFiltering; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.TskCoreException; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/OpenDiscoveryAction.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/OpenDiscoveryAction.java similarity index 97% rename from Core/src/org/sleuthkit/autopsy/discovery/OpenDiscoveryAction.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/OpenDiscoveryAction.java index 04530f8ad2..d1982ab364 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/OpenDiscoveryAction.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/OpenDiscoveryAction.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.awt.Component; import javax.swing.ImageIcon; @@ -31,6 +31,7 @@ import org.openide.util.NbBundle; import org.openide.util.actions.CallableSystemAction; import org.openide.util.actions.Presenter; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.discovery.Bundle; /** * Class to open the Discovery dialog. Allows the user to run searches and see diff --git a/Core/src/org/sleuthkit/autopsy/discovery/PageWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java similarity index 91% rename from Core/src/org/sleuthkit/autopsy/discovery/PageWorker.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java index 52418bef11..f9c5415294 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/PageWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.util.List; import java.util.ArrayList; @@ -26,6 +26,13 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.discovery.FileSearch.GroupKey; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.discovery.DiscoveryEventUtils; +import org.sleuthkit.autopsy.discovery.FileGroup; +import org.sleuthkit.autopsy.discovery.FileSearch; +import org.sleuthkit.autopsy.discovery.FileSearchData; +import org.sleuthkit.autopsy.discovery.FileSearchException; +import org.sleuthkit.autopsy.discovery.FileSorter; +import org.sleuthkit.autopsy.discovery.ResultFile; /** * SwingWorker to retrieve the contents of a page. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/ParentFolderFilterPanel.form similarity index 93% rename from Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/ParentFolderFilterPanel.form index b350ab42b3..fe21dc8607 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ParentFolderFilterPanel.form @@ -5,7 +5,7 @@ - + @@ -24,7 +24,7 @@ - + @@ -160,7 +160,7 @@ - + @@ -172,7 +172,7 @@ - + @@ -183,7 +183,7 @@ - + @@ -194,7 +194,7 @@ - + @@ -202,7 +202,7 @@ - + @@ -222,7 +222,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ParentFolderFilterPanel.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/ParentFolderFilterPanel.java index 3df211b2d0..841dd910bc 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ParentFolderFilterPanel.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.util.ArrayList; import java.util.List; @@ -24,6 +24,7 @@ import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; +import org.sleuthkit.autopsy.discovery.SearchFiltering; import org.sleuthkit.autopsy.discovery.SearchFiltering.ParentSearchTerm; /** diff --git a/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.form similarity index 95% rename from Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.form index 37ea6de900..bfe666aee3 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.form @@ -5,7 +5,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java similarity index 97% rename from Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java index b6979fe9e4..20fead3473 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java @@ -16,15 +16,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.discovery.FileSearchData; import org.sleuthkit.autopsy.discovery.FileSearchData.Frequency; import org.sleuthkit.autopsy.discovery.SearchData.ResultType; +import org.sleuthkit.autopsy.discovery.SearchFiltering; /** * Panel to allow configuration of the Past Occurrences filter. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.form similarity index 97% rename from Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.form index cad2e006cd..d256c2374e 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.form @@ -79,7 +79,7 @@ - + @@ -127,7 +127,7 @@ - + @@ -153,7 +153,7 @@ - + @@ -199,7 +199,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java index eb844a7a73..e2686c58eb 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import com.google.common.eventbus.Subscribe; import java.awt.Cursor; @@ -38,6 +38,13 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.discovery.FileSearch.GroupKey; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.discovery.Bundle; +import org.sleuthkit.autopsy.discovery.DiscoveryEventUtils; +import org.sleuthkit.autopsy.discovery.FileGroup; +import org.sleuthkit.autopsy.discovery.FileSearch; +import org.sleuthkit.autopsy.discovery.FileSearchData; +import org.sleuthkit.autopsy.discovery.FileSorter; +import org.sleuthkit.autopsy.discovery.ResultFile; import org.sleuthkit.autopsy.textsummarizer.TextSummary; /** diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ResultsSplitPaneDivider.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.form similarity index 93% rename from Core/src/org/sleuthkit/autopsy/discovery/ResultsSplitPaneDivider.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.form index 48ae94d8a9..a61f5a9c93 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ResultsSplitPaneDivider.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.form @@ -54,7 +54,7 @@ - + @@ -69,7 +69,7 @@ - + @@ -94,7 +94,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ResultsSplitPaneDivider.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/discovery/ResultsSplitPaneDivider.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.java index 0a89f28711..6243416325 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ResultsSplitPaneDivider.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.java @@ -16,9 +16,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.awt.Cursor; +import org.sleuthkit.autopsy.discovery.DiscoveryEventUtils; /** * Panel for separating the results list from the details area. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/SearchWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java similarity index 91% rename from Core/src/org/sleuthkit/autopsy/discovery/SearchWorker.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java index c1877109b5..ea14294d95 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/SearchWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.util.LinkedHashMap; import javax.swing.SwingWorker; @@ -27,6 +27,11 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.discovery.FileSearch.GroupKey; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.discovery.DiscoveryEventUtils; +import org.sleuthkit.autopsy.discovery.FileGroup; +import org.sleuthkit.autopsy.discovery.FileSearch; +import org.sleuthkit.autopsy.discovery.FileSearchException; +import org.sleuthkit.autopsy.discovery.FileSorter; /** * SwingWorker to perform search on a background thread. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/SizeFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/SizeFilterPanel.form similarity index 96% rename from Core/src/org/sleuthkit/autopsy/discovery/SizeFilterPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/SizeFilterPanel.form index 1b77a4329e..fd63ea077d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/SizeFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/SizeFilterPanel.form @@ -5,7 +5,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/SizeFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/SizeFilterPanel.java similarity index 97% rename from Core/src/org/sleuthkit/autopsy/discovery/SizeFilterPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/SizeFilterPanel.java index c6f0478f38..8ca29f0018 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/SizeFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/SizeFilterPanel.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.util.ArrayList; import java.util.List; @@ -24,7 +24,9 @@ import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; +import org.sleuthkit.autopsy.discovery.FileSearchData; import org.sleuthkit.autopsy.discovery.FileSearchData.FileSize; +import org.sleuthkit.autopsy.discovery.SearchFiltering; /** * Panel to allow configuration of the Size Filter. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/SwingAnimator.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/SwingAnimator.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/discovery/SwingAnimator.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/SwingAnimator.java index 2dac8559bb..cb32183eb2 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/SwingAnimator.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/SwingAnimator.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/SwingAnimatorCallback.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/SwingAnimatorCallback.java similarity index 96% rename from Core/src/org/sleuthkit/autopsy/discovery/SwingAnimatorCallback.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/SwingAnimatorCallback.java index 86f7d2f7fb..2393f7957b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/SwingAnimatorCallback.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/SwingAnimatorCallback.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; /** * diff --git a/Core/src/org/sleuthkit/autopsy/discovery/UserCreatedFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/UserCreatedFilterPanel.form similarity index 93% rename from Core/src/org/sleuthkit/autopsy/discovery/UserCreatedFilterPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/UserCreatedFilterPanel.form index 520bf47dc3..a6fc200308 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/UserCreatedFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/UserCreatedFilterPanel.form @@ -5,7 +5,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/UserCreatedFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/UserCreatedFilterPanel.java similarity index 97% rename from Core/src/org/sleuthkit/autopsy/discovery/UserCreatedFilterPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/UserCreatedFilterPanel.java index 8f6be8b12b..5d421a0b0d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/UserCreatedFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/UserCreatedFilterPanel.java @@ -16,11 +16,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; +import org.sleuthkit.autopsy.discovery.SearchFiltering; /** * Panel to allow configuration of the User Created Filter. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoFilterPanel.form similarity index 95% rename from Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/VideoFilterPanel.form index 1a853b425a..914d724f3d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoFilterPanel.form @@ -71,7 +71,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoFilterPanel.java similarity index 95% rename from Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/VideoFilterPanel.java index 8d0d51ef34..d1388a45ba 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoFilterPanel.java @@ -16,9 +16,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.discovery.AttributeSearchData; +import org.sleuthkit.autopsy.discovery.FileSearchData; +import org.sleuthkit.autopsy.discovery.SearchData; /** * Panel for displaying all filters available for the searches of type Video. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailPanel.form similarity index 88% rename from Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailPanel.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailPanel.form index 522acb16c8..759e61c6d2 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailPanel.form @@ -78,13 +78,13 @@ - + - + - + @@ -94,13 +94,13 @@ - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailPanel.java similarity index 93% rename from Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailPanel.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailPanel.java index d8845f565a..609904ee2a 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailPanel.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.awt.Color; import java.awt.Component; @@ -32,6 +32,7 @@ import javax.swing.JLabel; import javax.swing.JList; import javax.swing.ListCellRenderer; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.discovery.Bundle; /** * Class which displays thumbnails and information for a video file. @@ -113,14 +114,14 @@ final class VideoThumbnailPanel extends javax.swing.JPanel implements ListCellRe imagePanel.setLayout(new java.awt.GridBagLayout()); scoreLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/red-circle-exclamation.png"))); // NOI18N - scoreLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())); - scoreLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())); - scoreLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())); + scoreLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize())); + scoreLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize())); + scoreLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize())); deletedLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/file-icon-deleted.png"))); // NOI18N - deletedLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())); - deletedLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())); - deletedLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.DiscoveryUiUtils.getIconSize())); + deletedLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize())); + deletedLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize())); + deletedLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.discovery.ui.DiscoveryUiUtils.getIconSize())); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailViewer.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailViewer.form similarity index 97% rename from Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailViewer.form rename to Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailViewer.form index aa8875a52d..54c180973c 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailViewer.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailViewer.form @@ -35,11 +35,11 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailViewer.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailViewer.java similarity index 95% rename from Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailViewer.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailViewer.java index bb3c5a30ea..8824e6f5d8 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailViewer.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailViewer.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.util.ArrayList; import java.util.List; @@ -104,7 +104,7 @@ final class VideoThumbnailViewer extends javax.swing.JPanel { thumbnailList.setModel(thumbnailListModel); thumbnailList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); - thumbnailList.setCellRenderer(new org.sleuthkit.autopsy.discovery.VideoThumbnailPanel()); + thumbnailList.setCellRenderer(new org.sleuthkit.autopsy.discovery.ui.VideoThumbnailPanel()); thumbnailListScrollPane.setViewportView(thumbnailList); add(thumbnailListScrollPane, java.awt.BorderLayout.CENTER); @@ -112,7 +112,7 @@ final class VideoThumbnailViewer extends javax.swing.JPanel { // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JList thumbnailList; + private javax.swing.JList thumbnailList; private javax.swing.JScrollPane thumbnailListScrollPane; // End of variables declaration//GEN-END:variables diff --git a/Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailsWrapper.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailsWrapper.java similarity index 96% rename from Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailsWrapper.java rename to Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailsWrapper.java index 52c188ac80..429b26d926 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/VideoThumbnailsWrapper.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailsWrapper.java @@ -16,12 +16,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.ui; import java.awt.Image; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.sleuthkit.autopsy.discovery.ResultFile; /** * Class to wrap all the information necessary for video thumbnails to be diff --git a/Core/src/org/sleuthkit/autopsy/discovery/arrow-down.png b/Core/src/org/sleuthkit/autopsy/discovery/ui/arrow-down.png similarity index 100% rename from Core/src/org/sleuthkit/autopsy/discovery/arrow-down.png rename to Core/src/org/sleuthkit/autopsy/discovery/ui/arrow-down.png diff --git a/Core/src/org/sleuthkit/autopsy/discovery/arrow-up.png b/Core/src/org/sleuthkit/autopsy/discovery/ui/arrow-up.png similarity index 100% rename from Core/src/org/sleuthkit/autopsy/discovery/arrow-up.png rename to Core/src/org/sleuthkit/autopsy/discovery/ui/arrow-up.png From 3eee575d66621e09f837adb19dc4f77bc87a2f1b Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 17 Aug 2020 13:42:39 -0400 Subject: [PATCH 011/130] 6610 refactor and move search related discovery files --- .../autopsy/discovery/Bundle.properties | 65 -- .../{ui => search}/AbstractFilter.java | 14 +- .../{ => search}/AttributeSearchData.java | 16 +- .../{ => search}/DiscoveryEventUtils.java | 91 +- .../discovery/search/DiscoveryKeyUtils.java | 341 +++++++ .../discovery/{ => search}/FileGroup.java | 19 +- .../discovery/{ => search}/FileSearch.java | 857 +----------------- .../{ => search}/FileSearchData.java | 52 +- .../{ => search}/FileSearchException.java | 2 +- .../discovery/{ => search}/FileSorter.java | 12 +- .../discovery/{ => search}/ResultFile.java | 46 +- .../discovery/{ => search}/SearchData.java | 8 +- .../{ => search}/SearchFiltering.java | 155 ++-- .../discovery/{ => search}/SearchResults.java | 8 +- .../discovery/search/SummaryHelpers.java | 236 +++++ .../ui/AbstractDiscoveryFilterPanel.java | 1 + .../discovery/ui/AbstractFiltersPanel.java | 9 +- .../discovery/ui/ArtifactTypeFilterPanel.java | 3 +- .../{ => ui}/Bundle.properties-MERGED | 0 .../discovery/ui/DataSourceFilterPanel.java | 3 +- .../ui/DataSourceModulesWrapper.java | 1 - .../autopsy/discovery/ui/DateFilterPanel.java | 2 +- .../autopsy/discovery/ui/DetailsPanel.java | 2 +- .../autopsy/discovery/ui/DiscoveryDialog.java | 28 +- .../discovery/ui/DiscoveryTopComponent.form | 2 +- .../discovery/ui/DiscoveryTopComponent.java | 6 +- .../discovery/ui/DiscoveryUiUtils.java | 292 +++++- .../discovery/ui/DocumentFilterPanel.java | 6 +- .../autopsy/discovery/ui/DocumentPanel.java | 3 +- .../autopsy/discovery/ui/DocumentWrapper.java | 3 +- .../discovery/ui/DomainFilterPanel.java | 6 +- .../autopsy/discovery/ui/GroupListPanel.java | 14 +- .../discovery/ui/HashSetFilterPanel.java | 3 +- .../discovery/ui/ImageFilterPanel.java | 6 +- .../discovery/ui/ImageThumbnailPanel.java | 1 - .../discovery/ui/ImageThumbnailWrapper.java | 2 +- .../ui/InterestingItemsFilterPanel.java | 3 +- .../ui/ObjectDetectedFilterPanel.java | 3 +- .../discovery/ui/OpenDiscoveryAction.java | 1 - .../autopsy/discovery/ui/PageWorker.java | 17 +- .../discovery/ui/ParentFolderFilterPanel.java | 5 +- .../ui/PastOccurrencesFilterPanel.java | 4 - .../autopsy/discovery/ui/ResultsPanel.java | 18 +- .../discovery/ui/ResultsSplitPaneDivider.java | 2 +- .../autopsy/discovery/ui/SearchWorker.java | 13 +- .../autopsy/discovery/ui/SizeFilterPanel.java | 7 +- .../discovery/ui/UserCreatedFilterPanel.java | 3 +- .../discovery/ui/VideoFilterPanel.java | 6 +- .../discovery/ui/VideoThumbnailPanel.java | 1 - .../discovery/ui/VideoThumbnailsWrapper.java | 2 +- 50 files changed, 1203 insertions(+), 1197 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties rename Core/src/org/sleuthkit/autopsy/discovery/{ui => search}/AbstractFilter.java (84%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => search}/AttributeSearchData.java (87%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => search}/DiscoveryEventUtils.java (81%) create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java rename Core/src/org/sleuthkit/autopsy/discovery/{ => search}/FileGroup.java (91%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => search}/FileSearch.java (62%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => search}/FileSearchData.java (93%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => search}/FileSearchException.java (96%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => search}/FileSorter.java (97%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => search}/ResultFile.java (91%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => search}/SearchData.java (85%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => search}/SearchFiltering.java (89%) rename Core/src/org/sleuthkit/autopsy/discovery/{ => search}/SearchResults.java (95%) create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/search/SummaryHelpers.java rename Core/src/org/sleuthkit/autopsy/discovery/{ => ui}/Bundle.properties-MERGED (100%) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties deleted file mode 100644 index 82c3178cef..0000000000 --- a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties +++ /dev/null @@ -1,65 +0,0 @@ -FileSearchDialog.jLabel1.text=File Type -FileSearchDialog.dsCheckBox.text=Data source -FileSearchDialog.cancelButton.text=Cancel -FileSearchDialog.freqCheckBox.text=CR Frequency -FileSearchDialog.sizeCheckBox.text=Size -FileSearchDialog.kwCheckBox.text=Keyword -FileSearchDialog.addParentButton.text=Add -FileSearchDialog.deleteParentButton.text=Delete -FileSearchDialog.parentFullRadioButton.text=Full -FileSearchDialog.parentSubstringRadioButton.text=Substring -FileSearchDialog.jLabel2.text=(All will be used) -FileSearchDialog.jLabel3.text=Group by attribute: -FileSearchDialog.jLabel4.text=Order groups by: -FileSearchDialog.orderAttrRadioButton.text=Attribute -FileSearchDialog.orderSizeRadioButton.text=Group Size -FileSearchDialog.jLabel5.text=Order files by: -FileSearchDialog.parentCheckBox.text=Parent -FileSearchPanel.sortingPanel.border.title=Grouping -FileSearchPanel.addButton.text=Add -FileSearchPanel.substringRadioButton.text=Substring -FileSearchPanel.fullRadioButton.text=Full -FileSearchPanel.parentCheckbox.text=Parent Folder: -FileSearchPanel.keywordCheckbox.text=Keyword: -FileSearchPanel.crFrequencyCheckbox.text=Past Occurrences: -FileSearchPanel.dataSourceCheckbox.text=Data Source: -FileSearchPanel.sizeCheckbox.text=File Size: -FileSearchPanel.orderGroupsByLabel.text=Order Groups By: -FileSearchPanel.filtersScrollPane.border.title=Filters -FileSearchPanel.parentLabel.text=(All will be used) -FileSearchPanel.deleteButton.text=Delete -FileSearchPanel.orderByLabel.text=Order Within Groups By: -FileSearchPanel.groupByLabel.text=Group By: -FileSearchDialog.searchButton.text=Search -FileSearchDialog.hashCheckBox.text=Hash Set -FileSearchDialog.intCheckBox.text=Interesting Items -FileSearchDialog.tagsCheckBox.text=Tags -FileSearchDialog.objCheckBox.text=Objects -FileSearchDialog.exifCheckBox.text=Must contain EXIF data -FileSearchDialog.notableCheckBox.text=Must have been tagged as notable -FileSearchDialog.scoreCheckBox.text=Has score -FileSearchPanel.hashSetCheckbox.text=Hash Set: -FileSearchPanel.tagsCheckbox.text=Tag: -FileSearchPanel.interestingItemsCheckbox.text=Interesting Item: -FileSearchPanel.scoreCheckbox.text=Has Score: -FileSearchPanel.notableCheckbox.text=Must have been tagged as notable -FileSearchPanel.objectsCheckbox.text=Object Detected: -DiscoveryExtractAction.title.extractFiles.text=Extract File -FileSearchPanel.includeRadioButton.text=Include -FileSearchPanel.excludeRadioButton.text=Exclude -FileSearchPanel.knownFilesCheckbox.toolTipText= -FileSearchPanel.knownFilesCheckbox.text=Hide known files -FileSearchPanel.stepThreeLabel.text=Step 3: Choose display settings -FileSearchPanel.userCreatedCheckbox.text=Possibly User Created -UserCreatedFilterPanel.userCreatedCheckbox.text=Possibly User Created -InterestingItemFilterPanel.interestingItemsCheckbox.text=Interesting Item: -ParentFolderFilterPanel.parentCheckbox.text=Parent Folder: -ParentFolderFilterPanel.deleteButton.text=Delete -ParentFolderFilterPanel.excludeRadioButton.text=Exclude -ParentFolderFilterPanel.includeRadioButton.text=Include -ParentFolderFilterPanel.substringRadioButton.text=Substring -ParentFolderFilterPanel.fullRadioButton.text=Full -ParentFolderFilterPanel.parentLabel.text=(All will be used) -ParentFolderFilterPanel.addButton.text=Add -ObjectDetectedFilterPanel.text=Object Detected: -DomainUniquenessFilterPanel.domainUniquenessCheckbox.text=Domain Uniqueness: diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFilter.java b/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java similarity index 84% rename from Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFilter.java rename to Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java index 1ac8ed925e..7ed3d54edd 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFilter.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java @@ -16,19 +16,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery.ui; +package org.sleuthkit.autopsy.discovery.search; import java.util.ArrayList; import java.util.List; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; -import org.sleuthkit.autopsy.discovery.FileSearchException; -import org.sleuthkit.autopsy.discovery.ResultFile; import org.sleuthkit.datamodel.SleuthkitCase; /** * Base class for the filters. */ -abstract class AbstractFilter { +public abstract class AbstractFilter { /** * Returns part of a query on the table that can be AND-ed with @@ -37,7 +35,7 @@ abstract class AbstractFilter { * @return the SQL query or an empty string if there is no SQL query for * this filter. */ - abstract String getWhereClause(); + public abstract String getWhereClause(); /** * Indicates whether this filter needs to use the secondary, non-SQL method @@ -45,7 +43,7 @@ abstract class AbstractFilter { * * @return false by default */ - boolean useAlternateFilter() { + public boolean useAlternateFilter() { return false; } @@ -63,7 +61,7 @@ abstract class AbstractFilter { * * @throws FileSearchException */ - List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, + public List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws FileSearchException { return new ArrayList<>(); } @@ -73,5 +71,5 @@ abstract class AbstractFilter { * * @return A description of the filter */ - abstract String getDesc(); + public abstract String getDesc(); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/AttributeSearchData.java b/Core/src/org/sleuthkit/autopsy/discovery/search/AttributeSearchData.java similarity index 87% rename from Core/src/org/sleuthkit/autopsy/discovery/AttributeSearchData.java rename to Core/src/org/sleuthkit/autopsy/discovery/search/AttributeSearchData.java index 922817a654..322a11867c 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/AttributeSearchData.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/AttributeSearchData.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.search; import java.util.Collection; import java.util.Collections; @@ -29,22 +29,22 @@ import org.sleuthkit.datamodel.BlackboardArtifact; /** * Utility enums for searches made for attributes with Discovery. */ -public class AttributeSearchData extends SearchData { +public class AttributeSearchData implements SearchData { private static final Set DOMAIN_ARTIFACT_TYPES = EnumSet.of(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY, BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG); @Override - ResultType getResultType() { + public ResultType getResultType() { return ResultType.ATTRIBUTE; } /** - * Enum representing the attribute type. + * Enum representing the attribute type. */ @NbBundle.Messages({ "AttributeSearchData.AttributeType.Domain.displayName=Domain", "AttributeSearchData.AttributeType.Other.displayName=Other"}) - enum AttributeType { + public enum AttributeType { DOMAIN(0, Bundle.AttributeSearchData_AttributeType_Domain_displayName(), DOMAIN_ARTIFACT_TYPES), OTHER(1, Bundle.AttributeSearchData_AttributeType_Other_displayName(), new HashSet<>()); @@ -64,7 +64,7 @@ public class AttributeSearchData extends SearchData { * * @return Collection of BlackboardArtifact types. */ - Collection getBlackboardTypes() { + public Collection getBlackboardTypes() { return Collections.unmodifiableCollection(artifactTypes); } @@ -78,11 +78,11 @@ public class AttributeSearchData extends SearchData { * * @return the rank (lower should be displayed first) */ - int getRanking() { + public int getRanking() { return ranking; } - static AttributeType fromBlackboardArtifact(final BlackboardArtifact.ARTIFACT_TYPE type) { + public static AttributeType fromBlackboardArtifact(final BlackboardArtifact.ARTIFACT_TYPE type) { switch (type) { case TSK_WEB_BOOKMARK: return DOMAIN; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java similarity index 81% rename from Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java rename to Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java index 4507d06f18..01b2606b42 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryEventUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java @@ -16,23 +16,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.search; -import org.sleuthkit.autopsy.discovery.ui.AbstractFilter; import com.google.common.eventbus.EventBus; import java.util.Collections; import java.util.List; import java.util.Map; -import org.sleuthkit.autopsy.discovery.AttributeSearchData.AttributeType; -import org.sleuthkit.autopsy.discovery.FileSearch.GroupKey; -import org.sleuthkit.autopsy.discovery.FileSearchData.FileType; -import org.sleuthkit.autopsy.discovery.SearchData.ResultType; +import org.sleuthkit.autopsy.discovery.search.AttributeSearchData.AttributeType; +import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; +import org.sleuthkit.autopsy.discovery.search.FileSearchData.FileType; +import org.sleuthkit.autopsy.discovery.search.SearchData.ResultType; import org.sleuthkit.datamodel.AbstractFile; /** * Class to handle event bus and events for discovery tool. */ -final class DiscoveryEventUtils { +public final class DiscoveryEventUtils { private final static EventBus discoveryEventBus = new EventBus(); @@ -41,7 +40,7 @@ final class DiscoveryEventUtils { * * @return The discovery event bus. */ - static EventBus getDiscoveryEventBus() { + public static EventBus getDiscoveryEventBus() { return discoveryEventBus; } @@ -55,7 +54,7 @@ final class DiscoveryEventUtils { /** * Event to signal the start of a search being performed. */ - static final class SearchStartedEvent { + public static final class SearchStartedEvent { private final ResultType resultType; private final FileType fileType; @@ -66,7 +65,7 @@ final class DiscoveryEventUtils { * * @param type The type of file the search event is for. */ - SearchStartedEvent(ResultType resultType, FileType fileType, AttributeType attributeType) { + public SearchStartedEvent(ResultType resultType, FileType fileType, AttributeType attributeType) { this.resultType = resultType; this.fileType = fileType; this.attributeType = attributeType; @@ -77,7 +76,7 @@ final class DiscoveryEventUtils { * * @return The result type, either FILES, or ATTRIBUTES. */ - ResultType getResultType() { + public ResultType getResultType() { return resultType; } @@ -86,7 +85,7 @@ final class DiscoveryEventUtils { * * @return The type of files being searched for. */ - FileType getFileType() { + public FileType getFileType() { return fileType; } @@ -95,7 +94,7 @@ final class DiscoveryEventUtils { * * @return The type of attribute being searched for. */ - AttributeType getAttributeType() { + public AttributeType getAttributeType() { return attributeType; } } @@ -103,12 +102,12 @@ final class DiscoveryEventUtils { /** * Event to signal that the Instances list should have selection cleared. */ - static final class ClearInstanceSelectionEvent { + public static final class ClearInstanceSelectionEvent { /** * Construct a new ClearInstanceSelectionEvent. */ - ClearInstanceSelectionEvent() { + public ClearInstanceSelectionEvent() { //no arg constructor } } @@ -116,21 +115,21 @@ final class DiscoveryEventUtils { /** * Event to signal that the Instances list should be populated. */ - static final class PopulateInstancesListEvent { + public static final class PopulateInstancesListEvent { private final List instances; /** * Construct a new PopulateInstancesListEvent. */ - PopulateInstancesListEvent(List files) { + public PopulateInstancesListEvent(List files) { instances = files; } /** * @return the instances */ - List getInstances() { + public List getInstances() { return Collections.unmodifiableList(instances); } } @@ -138,7 +137,7 @@ final class DiscoveryEventUtils { /** * Event to signal the completion of a search being performed. */ - static final class SearchCompleteEvent { + public static final class SearchCompleteEvent { private final Map groupMap; private final List searchFilters; @@ -157,7 +156,7 @@ final class DiscoveryEventUtils { * @param groupSort The sorting algorithm used for groups. * @param fileSortMethod The sorting method used for files. */ - SearchCompleteEvent(Map groupMap, List searchfilters, + public SearchCompleteEvent(Map groupMap, List searchfilters, FileSearch.AttributeType groupingAttribute, FileGroup.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod) { this.groupMap = groupMap; @@ -172,7 +171,7 @@ final class DiscoveryEventUtils { * * @return The map of groups which were found by the search. */ - Map getGroupMap() { + public Map getGroupMap() { return Collections.unmodifiableMap(groupMap); } @@ -181,7 +180,7 @@ final class DiscoveryEventUtils { * * @return The search filters which were used by the search. */ - List getFilters() { + public List getFilters() { return Collections.unmodifiableList(searchFilters); } @@ -190,7 +189,7 @@ final class DiscoveryEventUtils { * * @return The grouping attribute used by the search. */ - FileSearch.AttributeType getGroupingAttr() { + public FileSearch.AttributeType getGroupingAttr() { return groupingAttribute; } @@ -199,7 +198,7 @@ final class DiscoveryEventUtils { * * @return The sorting algorithm used for groups. */ - FileGroup.GroupSortingAlgorithm getGroupSort() { + public FileGroup.GroupSortingAlgorithm getGroupSort() { return groupSort; } @@ -208,7 +207,7 @@ final class DiscoveryEventUtils { * * @return The sorting method used for files. */ - FileSorter.SortingMethod getFileSort() { + public FileSorter.SortingMethod getFileSort() { return fileSortMethod; } @@ -218,7 +217,7 @@ final class DiscoveryEventUtils { * Event to signal the completion of page retrieval and include the page * contents. */ - static final class PageRetrievedEvent { + public static final class PageRetrievedEvent { private final List results; private final int page; @@ -231,7 +230,7 @@ final class DiscoveryEventUtils { * @param page The number of the page which was retrieved. * @param results The list of files in the page retrieved. */ - PageRetrievedEvent(FileType resultType, int page, List results) { + public PageRetrievedEvent(FileType resultType, int page, List results) { this.results = results; this.page = page; this.resultType = resultType; @@ -242,7 +241,7 @@ final class DiscoveryEventUtils { * * @return The list of files in the page retrieved. */ - List getSearchResults() { + public List getSearchResults() { return Collections.unmodifiableList(results); } @@ -251,7 +250,7 @@ final class DiscoveryEventUtils { * * @return The number of the page which was retrieved. */ - int getPageNumber() { + public int getPageNumber() { return page; } @@ -260,7 +259,7 @@ final class DiscoveryEventUtils { * * @return The type of files which exist in the page. */ - FileType getType() { + public FileType getType() { return resultType; } } @@ -268,12 +267,12 @@ final class DiscoveryEventUtils { /** * Event to signal that there were no results for the search. */ - static final class NoResultsEvent { + public static final class NoResultsEvent { /** * Construct a new NoResultsEvent. */ - NoResultsEvent() { + public NoResultsEvent() { //no arg constructor } } @@ -281,12 +280,12 @@ final class DiscoveryEventUtils { /** * Event to signal that a search has been cancelled */ - static final class SearchCancelledEvent { + public static final class SearchCancelledEvent { /** * Construct a new SearchCancelledEvent. */ - SearchCancelledEvent() { + public SearchCancelledEvent() { //no arg constructor } @@ -295,7 +294,7 @@ final class DiscoveryEventUtils { /** * Event to signal that a group has been selected. */ - static final class GroupSelectedEvent { + public static final class GroupSelectedEvent { private final FileType resultType; private final GroupKey groupKey; @@ -319,7 +318,7 @@ final class DiscoveryEventUtils { * selected. * @param resultType The type of files which exist in the group. */ - GroupSelectedEvent(List searchfilters, + public GroupSelectedEvent(List searchfilters, FileSearch.AttributeType groupingAttribute, FileGroup.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod, GroupKey groupKey, int groupSize, FileType resultType) { this.searchfilters = searchfilters; @@ -336,7 +335,7 @@ final class DiscoveryEventUtils { * * @return The type of files which exist in the group. */ - FileType getResultType() { + public FileType getResultType() { return resultType; } @@ -347,7 +346,7 @@ final class DiscoveryEventUtils { * @return The group key which is used to uniquely identify the group * selected. */ - GroupKey getGroupKey() { + public GroupKey getGroupKey() { return groupKey; } @@ -356,7 +355,7 @@ final class DiscoveryEventUtils { * * @return The number of files in the group which was selected. */ - int getGroupSize() { + public int getGroupSize() { return groupSize; } @@ -365,7 +364,7 @@ final class DiscoveryEventUtils { * * @return The sorting algorithm used for groups. */ - FileGroup.GroupSortingAlgorithm getGroupSort() { + public FileGroup.GroupSortingAlgorithm getGroupSort() { return groupSort; } @@ -374,7 +373,7 @@ final class DiscoveryEventUtils { * * @return The sorting method used for files. */ - FileSorter.SortingMethod getFileSort() { + public FileSorter.SortingMethod getFileSort() { return fileSortMethod; } @@ -383,7 +382,7 @@ final class DiscoveryEventUtils { * * @return The search filters which were used by the search. */ - List getFilters() { + public List getFilters() { return Collections.unmodifiableList(searchfilters); } @@ -392,7 +391,7 @@ final class DiscoveryEventUtils { * * @return The grouping attribute used by the search. */ - FileSearch.AttributeType getGroupingAttr() { + public FileSearch.AttributeType getGroupingAttr() { return groupingAttribute; } @@ -401,7 +400,7 @@ final class DiscoveryEventUtils { /** * Event to signal that the visibility of the Details area should change. */ - static class DetailsVisibleEvent { + public static class DetailsVisibleEvent { private final boolean showDetailsArea; @@ -411,7 +410,7 @@ final class DiscoveryEventUtils { * @param isVisible True if the details area should be visible, false * otherwise. */ - DetailsVisibleEvent(boolean isVisible) { + public DetailsVisibleEvent(boolean isVisible) { showDetailsArea = isVisible; } @@ -420,7 +419,7 @@ final class DiscoveryEventUtils { * * @return True if the details area should be visible, false otherwise. */ - boolean isShowDetailsArea() { + public boolean isShowDetailsArea() { return showDetailsArea; } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java new file mode 100644 index 0000000000..d009ef0133 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java @@ -0,0 +1,341 @@ +/* + * Autopsy + * + * 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.discovery.search; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import org.openide.util.NbBundle; + +/** + * Utility class for constructing keys for groups and searches. + */ +public class DiscoveryKeyUtils { + + /** + * The key used for grouping for each attribute type. + */ + public abstract static class GroupKey implements Comparable { + + /** + * Get the string version of the group key for display. Each display + * name should correspond to a unique GroupKey object. + * + * @return The display name for this key + */ + abstract String getDisplayName(); + + /** + * Subclasses must implement equals(). + * + * @param otherKey + * + * @return true if the keys are equal, false otherwise + */ + @Override + abstract public boolean equals(Object otherKey); + + /** + * Subclasses must implement hashCode(). + * + * @return the hash code + */ + @Override + abstract public int hashCode(); + + /** + * It should not happen with the current setup, but we need to cover the + * case where two different GroupKey subclasses are compared against + * each other. Use a lexicographic comparison on the class names. + * + * @param otherGroupKey The other group key + * + * @return result of alphabetical comparison on the class name + */ + int compareClassNames(GroupKey otherGroupKey) { + return this.getClass().getName().compareTo(otherGroupKey.getClass().getName()); + } + + @Override + public String toString() { + return getDisplayName(); + } + } + + /** + * Key representing a file size group + */ + static class FileSizeGroupKey extends GroupKey { + + private final FileSearchData.FileSize fileSize; + + FileSizeGroupKey(ResultFile file) { + if (file.getFileType() == FileSearchData.FileType.VIDEO) { + fileSize = FileSearchData.FileSize.fromVideoSize(file.getFirstInstance().getSize()); + } else { + fileSize = FileSearchData.FileSize.fromImageSize(file.getFirstInstance().getSize()); + } + } + + @Override + String getDisplayName() { + return getFileSize().toString(); + } + + @Override + public int compareTo(GroupKey otherGroupKey) { + if (otherGroupKey instanceof FileSizeGroupKey) { + FileSizeGroupKey otherFileSizeGroupKey = (FileSizeGroupKey) otherGroupKey; + return Integer.compare(getFileSize().getRanking(), otherFileSizeGroupKey.getFileSize().getRanking()); + } else { + return compareClassNames(otherGroupKey); + } + } + + @Override + public boolean equals(Object otherKey) { + if (otherKey == this) { + return true; + } + + if (!(otherKey instanceof FileSizeGroupKey)) { + return false; + } + + FileSizeGroupKey otherFileSizeGroupKey = (FileSizeGroupKey) otherKey; + return getFileSize().equals(otherFileSizeGroupKey.getFileSize()); + } + + @Override + public int hashCode() { + return Objects.hash(getFileSize().getRanking()); + } + + /** + * @return the fileSize + */ + FileSearchData.FileSize getFileSize() { + return fileSize; + } + } + + /** + * Key representing a file tag group + */ + static class FileTagGroupKey extends GroupKey { + + private final List tagNames; + private final String tagNamesString; + + @NbBundle.Messages({ + "DiscoveryKeyUtils.FileTagGroupKey.noSets=None"}) + FileTagGroupKey(ResultFile file) { + tagNames = file.getTagNames(); + + if (tagNames.isEmpty()) { + tagNamesString = Bundle.DiscoveryKeyUtils_FileTagGroupKey_noSets(); + } else { + tagNamesString = String.join(",", tagNames); // NON-NLS + } + } + + @Override + String getDisplayName() { + return getTagNamesString(); + } + + @Override + public int compareTo(GroupKey otherGroupKey) { + if (otherGroupKey instanceof FileTagGroupKey) { + FileTagGroupKey otherFileTagGroupKey = (FileTagGroupKey) otherGroupKey; + + // Put the empty list at the end + if (getTagNames().isEmpty()) { + if (otherFileTagGroupKey.getTagNames().isEmpty()) { + return 0; + } else { + return 1; + } + } else if (otherFileTagGroupKey.getTagNames().isEmpty()) { + return -1; + } + + return getTagNamesString().compareTo(otherFileTagGroupKey.getTagNamesString()); + } else { + return compareClassNames(otherGroupKey); + } + } + + @Override + public boolean equals(Object otherKey) { + if (otherKey == this) { + return true; + } + + if (!(otherKey instanceof FileTagGroupKey)) { + return false; + } + + FileTagGroupKey otherFileTagGroupKey = (FileTagGroupKey) otherKey; + return getTagNamesString().equals(otherFileTagGroupKey.getTagNamesString()); + } + + @Override + public int hashCode() { + return Objects.hash(getTagNamesString()); + } + + /** + * @return the tagNames + */ + List getTagNames() { + return Collections.unmodifiableList(tagNames); + } + + /** + * @return the tagNamesString + */ + String getTagNamesString() { + return tagNamesString; + } + } + + /** + * Default attribute used to make one group + */ + static class NoGroupingAttribute extends FileSearch.AttributeType { + + @Override + public GroupKey getGroupKey(ResultFile file) { + return new NoGroupingGroupKey(); + } + } + + /** + * Dummy key for when there is no grouping. All files will have the same + * key. + */ + static class NoGroupingGroupKey extends GroupKey { + + NoGroupingGroupKey() { + // Nothing to save - all files will get the same GroupKey + } + + @NbBundle.Messages({ + "DiscoveryKeyUtils.NoGroupingGroupKey.allFiles=All Files"}) + @Override + String getDisplayName() { + return Bundle.DiscoveryKeyUtils_NoGroupingGroupKey_allFiles(); + } + + @Override + public int compareTo(GroupKey otherGroupKey) { + // As long as the other key is the same type, they are equal + if (otherGroupKey instanceof NoGroupingGroupKey) { + return 0; + } else { + return compareClassNames(otherGroupKey); + } + } + + @Override + public boolean equals(Object otherKey) { + if (otherKey == this) { + return true; + } + // As long as the other key is the same type, they are equal + return otherKey instanceof NoGroupingGroupKey; + } + + @Override + public int hashCode() { + return 0; + } + } + + /** + * Represents a key for a specific search for a specific user. + */ + static class SearchKey implements Comparable { + + private final String keyString; + + /** + * Construct a new SearchKey with all information that defines a search. + * + * @param userName The name of the user performing the search. + * @param filters The FileFilters being used for the search. + * @param groupAttributeType The AttributeType to group by. + * @param groupSortingType The algorithm to sort the groups by. + * @param fileSortingMethod The method to sort the files by. + */ + SearchKey(String userName, List filters, + FileSearch.AttributeType groupAttributeType, + FileGroup.GroupSortingAlgorithm groupSortingType, + FileSorter.SortingMethod fileSortingMethod) { + StringBuilder searchStringBuilder = new StringBuilder(); + searchStringBuilder.append(userName); + for (AbstractFilter filter : filters) { + searchStringBuilder.append(filter.toString()); + } + searchStringBuilder.append(groupAttributeType).append(groupSortingType).append(fileSortingMethod); + keyString = searchStringBuilder.toString(); + } + + @Override + public int compareTo(SearchKey otherSearchKey) { + return getKeyString().compareTo(otherSearchKey.getKeyString()); + } + + @Override + public boolean equals(Object otherKey) { + if (otherKey == this) { + return true; + } + + if (!(otherKey instanceof SearchKey)) { + return false; + } + + SearchKey otherSearchKey = (SearchKey) otherKey; + return getKeyString().equals(otherSearchKey.getKeyString()); + } + + @Override + public int hashCode() { + int hash = 5; + hash = 79 * hash + Objects.hashCode(getKeyString()); + return hash; + } + + /** + * @return the keyString + */ + String getKeyString() { + return keyString; + } + } + + /** + * Private constructor for GroupKeyUtils utility class. + */ + private DiscoveryKeyUtils() { + //private constructor in a utility class intentionally left blank + } +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/FileGroup.java b/Core/src/org/sleuthkit/autopsy/discovery/search/FileGroup.java similarity index 91% rename from Core/src/org/sleuthkit/autopsy/discovery/FileGroup.java rename to Core/src/org/sleuthkit/autopsy/discovery/search/FileGroup.java index ad88550df6..173e9c63d1 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/FileGroup.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/FileGroup.java @@ -16,21 +16,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.search; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.discovery.FileSearch.GroupKey; /** * Class for storing files that belong to a particular group. */ -class FileGroup implements Comparable { +public class FileGroup implements Comparable { private final FileGroup.GroupSortingAlgorithm groupSortingType; - private final GroupKey groupKey; + private final DiscoveryKeyUtils.GroupKey groupKey; private final List files; private final String displayName; @@ -40,7 +39,7 @@ class FileGroup implements Comparable { * @param groupSortingType The method for sorting the group * @param groupKey The GroupKey for this group */ - FileGroup(FileGroup.GroupSortingAlgorithm groupSortingType, GroupKey groupKey) { + public FileGroup(FileGroup.GroupSortingAlgorithm groupSortingType, DiscoveryKeyUtils.GroupKey groupKey) { this.groupSortingType = groupSortingType; this.groupKey = groupKey; files = new ArrayList<>(); @@ -66,7 +65,7 @@ class FileGroup implements Comparable { * * @return The display name of the group. */ - String getDisplayName() { + public String getDisplayName() { return displayName; // NON-NLS } @@ -75,14 +74,14 @@ class FileGroup implements Comparable { * * @return The unique key for the group. */ - GroupKey getGroupKey() { + public DiscoveryKeyUtils.GroupKey getGroupKey() { return groupKey; } /** * Sort all the files in the group */ - void sortFiles(FileSorter sorter) { + public void sortFiles(FileSorter sorter) { Collections.sort(files, sorter); } @@ -142,7 +141,7 @@ class FileGroup implements Comparable { */ @Messages({"FileGroup.groupSortingAlgorithm.groupSize.text=Group Size", "FileGroup.groupSortingAlgorithm.groupName.text=Group Name"}) - enum GroupSortingAlgorithm { + public enum GroupSortingAlgorithm { BY_GROUP_NAME(Bundle.FileGroup_groupSortingAlgorithm_groupName_text()), // Sort using the group key (for example, if grouping by size sort from largest to smallest value) BY_GROUP_SIZE(Bundle.FileGroup_groupSortingAlgorithm_groupSize_text()); // Sort from largest to smallest group @@ -169,7 +168,7 @@ class FileGroup implements Comparable { * * @return List of ResultFile objects */ - List getFiles() { + public List getFiles() { return Collections.unmodifiableList(files); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/FileSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java similarity index 62% rename from Core/src/org/sleuthkit/autopsy/discovery/FileSearch.java rename to Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java index 09dd98882c..aaac8304fb 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java @@ -16,27 +16,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.search; -import org.sleuthkit.autopsy.discovery.ui.VideoThumbnailsWrapper; -import org.sleuthkit.autopsy.discovery.ui.AbstractFilter; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; -import com.google.common.io.Files; -import java.awt.Image; -import java.awt.image.BufferedImage; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; import java.io.IOException; -import java.io.Reader; -import java.nio.file.Paths; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -47,30 +35,15 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.logging.Level; -import javax.imageio.ImageIO; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang.StringUtils; -import org.imgscalr.Scalr; -import org.netbeans.api.progress.ProgressHandle; -import org.opencv.core.Mat; -import org.opencv.highgui.VideoCapture; -import org.openide.util.Lookup; import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.InstanceTableCallback; -import org.sleuthkit.autopsy.corelibs.ScalrWrapper; -import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; -import static org.sleuthkit.autopsy.coreutils.VideoUtils.getVideoFileInTempDir; -import org.sleuthkit.autopsy.datamodel.ContentUtils; -import org.sleuthkit.autopsy.discovery.FileSearchData.FileSize; -import org.sleuthkit.autopsy.discovery.FileSearchData.FileType; -import org.sleuthkit.autopsy.discovery.FileSearchData.Frequency; +import org.sleuthkit.autopsy.discovery.search.FileSearchData.FileType; +import org.sleuthkit.autopsy.discovery.search.FileSearchData.Frequency; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -81,29 +54,22 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; -import org.sleuthkit.autopsy.textextractors.TextExtractor; -import org.sleuthkit.autopsy.textextractors.TextExtractorFactory; +import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; +import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.SearchKey; import org.sleuthkit.autopsy.textsummarizer.TextSummarizer; import org.sleuthkit.autopsy.textsummarizer.TextSummary; -import org.sleuthkit.autopsy.texttranslation.NoServiceProviderException; -import org.sleuthkit.autopsy.texttranslation.TextTranslationService; -import org.sleuthkit.autopsy.texttranslation.TranslationException; /** * Main class to perform the file search. */ -class FileSearch { +public class FileSearch { private final static Logger logger = Logger.getLogger(FileSearch.class.getName()); private static final int MAXIMUM_CACHE_SIZE = 10; - private static final String THUMBNAIL_FORMAT = "png"; //NON-NLS - private static final String VIDEO_THUMBNAIL_DIR = "video-thumbnails"; //NON-NLS private static final Cache>> searchCache = CacheBuilder.newBuilder() .maximumSize(MAXIMUM_CACHE_SIZE) .build(); - private static final int PREVIEW_SIZE = 256; - private static volatile TextSummarizer summarizerToUse = null; - private static final BufferedImage VIDEO_DEFAULT_IMAGE = getDefaultVideoThumbnail(); + /** * Run the file search and returns the SearchResults object for debugging. @@ -175,7 +141,7 @@ class FileSearch { * * @throws FileSearchException */ - static Map getGroupSizes(String userName, + public static Map getGroupSizes(String userName, List filters, AttributeType groupAttributeType, FileGroup.GroupSortingAlgorithm groupSortingType, @@ -212,7 +178,7 @@ class FileSearch { * * @throws FileSearchException */ - static List getFilesInGroup(String userName, + public static List getFilesInGroup(String userName, List filters, AttributeType groupAttributeType, FileGroup.GroupSortingAlgorithm groupSortingType, @@ -269,15 +235,12 @@ class FileSearch { */ @NbBundle.Messages({"FileSearch.documentSummary.noPreview=No preview available.", "FileSearch.documentSummary.noBytes=No bytes read for document, unable to display preview."}) - static TextSummary summarize(AbstractFile file) { + public static TextSummary summarize(AbstractFile file) { TextSummary summary = null; - TextSummarizer localSummarizer = summarizerToUse; - if (localSummarizer == null) { - synchronized (searchCache) { - if (localSummarizer == null) { - localSummarizer = getLocalSummarizer(); - } - } + TextSummarizer localSummarizer; + synchronized (searchCache) { + localSummarizer = SummaryHelpers.getLocalSummarizer(); + } if (localSummarizer != null) { try { @@ -289,184 +252,11 @@ class FileSearch { } if (summary == null || StringUtils.isBlank(summary.getSummaryText())) { //summary text was empty grab the beginning of the file - summary = getDefaultSummary(file); + summary = SummaryHelpers.getDefaultSummary(file); } return summary; } - private static TextSummary getDefaultSummary(AbstractFile file) { - Image image = null; - int countOfImages = 0; - try { - Content largestChild = null; - for (Content child : file.getChildren()) { - if (child instanceof AbstractFile && ImageUtils.isImageThumbnailSupported((AbstractFile) child)) { - countOfImages++; - if (largestChild == null || child.getSize() > largestChild.getSize()) { - largestChild = child; - } - } - } - if (largestChild != null) { - image = ImageUtils.getThumbnail(largestChild, ImageUtils.ICON_SIZE_LARGE); - } - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error getting children for file: " + file.getId(), ex); - } - image = image == null ? image : image.getScaledInstance(ImageUtils.ICON_SIZE_MEDIUM, ImageUtils.ICON_SIZE_MEDIUM, - Image.SCALE_SMOOTH); - String summaryText = null; - if (file.getMd5Hash() != null) { - try { - summaryText = getSavedSummary(Paths.get(Case.getCurrentCaseThrows().getCacheDirectory(), "summaries", file.getMd5Hash() + "-default-" + PREVIEW_SIZE + "-translated.txt").toString()); - } catch (NoCurrentCaseException ex) { - logger.log(Level.WARNING, "Unable to retrieve saved summary. No case is open.", ex); - } - } - if (StringUtils.isBlank(summaryText)) { - String firstLines = getFirstLines(file); - String translatedFirstLines = getTranslatedVersion(firstLines); - if (!StringUtils.isBlank(translatedFirstLines)) { - summaryText = translatedFirstLines; - if (file.getMd5Hash() != null) { - try { - saveSummary(summaryText, Paths.get(Case.getCurrentCaseThrows().getCacheDirectory(), "summaries", file.getMd5Hash() + "-default-" + PREVIEW_SIZE + "-translated.txt").toString()); - } catch (NoCurrentCaseException ex) { - logger.log(Level.WARNING, "Unable to save translated summary. No case is open.", ex); - } - } - } else { - summaryText = firstLines; - } - } - return new TextSummary(summaryText, image, countOfImages); - } - - /** - * Provide an English version of the specified String if it is not English, - * translation is enabled, and it can be translated. - * - * @param documentString The String to provide an English version of. - * - * @return The English version of the provided String, or null if no - * translation occurred. - */ - private static String getTranslatedVersion(String documentString) { - try { - TextTranslationService translatorInstance = TextTranslationService.getInstance(); - if (translatorInstance.hasProvider()) { - String translatedResult = translatorInstance.translate(documentString); - if (translatedResult.isEmpty() == false) { - return translatedResult; - } - } - } catch (NoServiceProviderException | TranslationException ex) { - logger.log(Level.INFO, "Error translating string for summary", ex); - } - return null; - } - - /** - * Find and load a saved summary from the case folder for the specified - * file. - * - * @param summarySavePath The full path for the saved summary file. - * - * @return The summary found given the specified path, null if no summary - * was found. - */ - private static String getSavedSummary(String summarySavePath) { - if (summarySavePath == null) { - return null; - } - File savedFile = new File(summarySavePath); - if (savedFile.exists()) { - try (BufferedReader bReader = new BufferedReader(new FileReader(savedFile))) { - // pass the path to the file as a parameter - StringBuilder sBuilder = new StringBuilder(); - String sCurrentLine = bReader.readLine(); - while (sCurrentLine != null) { - sBuilder.append(sCurrentLine).append('\n'); - sCurrentLine = bReader.readLine(); - } - return sBuilder.toString(); - } catch (IOException ingored) { - //summary file may not exist or may be incomplete in which case return null so a summary can be generated - return null; //no saved summary was able to be found - } - } else { - try { //if the file didn't exist make sure the parent directories exist before we move on to creating a summary - Files.createParentDirs(savedFile); - } catch (IOException ex) { - logger.log(Level.WARNING, "Unable to create summaries directory in case folder for file at: " + summarySavePath, ex); - } - return null; //no saved summary was able to be found - } - - } - - /** - * Save a summary at the specified location. - * - * @param summary The text of the summary being saved. - * @param summarySavePath The full path for the saved summary file. - */ - private static void saveSummary(String summary, String summarySavePath) { - if (summarySavePath == null) { - return; //can't save a summary if we don't have a path - } - try (FileWriter myWriter = new FileWriter(summarySavePath)) { - myWriter.write(summary); - } catch (IOException ex) { - logger.log(Level.WARNING, "Unable to save summary at: " + summarySavePath, ex); - } - } - - /** - * Get the beginning of text from the specified AbstractFile. - * - * @param file The AbstractFile to get text from. - * - * @return The beginning of text from the specified AbstractFile. - */ - private static String getFirstLines(AbstractFile file) { - TextExtractor extractor; - try { - extractor = TextExtractorFactory.getExtractor(file, null); - } catch (TextExtractorFactory.NoTextExtractorFound ignored) { - //no extractor found, use Strings Extractor - extractor = TextExtractorFactory.getStringsExtractor(file, null); - } - - try (Reader reader = extractor.getReader()) { - char[] cbuf = new char[PREVIEW_SIZE]; - reader.read(cbuf, 0, PREVIEW_SIZE); - return new String(cbuf); - } catch (IOException ex) { - return Bundle.FileSearch_documentSummary_noBytes(); - } catch (TextExtractor.InitReaderException ex) { - return Bundle.FileSearch_documentSummary_noPreview(); - } - } - - /** - * Get the first TextSummarizer found by a lookup of TextSummarizers. - * - * @return The first TextSummarizer found by a lookup of TextSummarizers. - * - * @throws IOException - */ - private static TextSummarizer getLocalSummarizer() { - Collection summarizers - = Lookup.getDefault().lookupAll(TextSummarizer.class - ); - if (!summarizers.isEmpty()) { - summarizerToUse = summarizers.iterator().next(); - return summarizerToUse; - } - return null; - } - /** * Run the file search. Caching new results for access at later time. * @@ -593,271 +383,6 @@ class FileSearch { + "AND blackboard_artifacts.obj_id IN (" + objIdList + ") "; // NON-NLS } - /** - * Get the default image to display when a thumbnail is not available. - * - * @return The default video thumbnail. - */ - private static BufferedImage getDefaultVideoThumbnail() { - try { - return ImageIO.read(ImageUtils.class.getResourceAsStream("/org/sleuthkit/autopsy/images/failedToCreateVideoThumb.png"));//NON-NLS - } catch (IOException ex) { - logger.log(Level.SEVERE, "Failed to load 'failed to create video' placeholder.", ex); //NON-NLS - } - return null; - } - - /** - * Get the video thumbnails for a file which exists in a - * VideoThumbnailsWrapper and update the VideoThumbnailsWrapper to include - * them. - * - * @param thumbnailWrapper the object which contains the file to generate - * thumbnails for. - * - */ - @NbBundle.Messages({"# {0} - file name", - "FileSearch.genVideoThumb.progress.text=extracting temporary file {0}"}) - static void getVideoThumbnails(VideoThumbnailsWrapper thumbnailWrapper) { - AbstractFile file = thumbnailWrapper.getResultFile().getFirstInstance(); - String cacheDirectory; - try { - cacheDirectory = Case.getCurrentCaseThrows().getCacheDirectory(); - } catch (NoCurrentCaseException ex) { - cacheDirectory = null; - logger.log(Level.WARNING, "Unable to get cache directory, video thumbnails will not be saved", ex); - } - if (cacheDirectory == null || file.getMd5Hash() == null || !Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash()).toFile().exists()) { - java.io.File tempFile; - try { - tempFile = getVideoFileInTempDir(file); - } catch (NoCurrentCaseException ex) { - logger.log(Level.WARNING, "Exception while getting open case.", ex); //NON-NLS - int[] framePositions = new int[]{ - 0, - 0, - 0, - 0}; - thumbnailWrapper.setThumbnails(createDefaultThumbnailList(VIDEO_DEFAULT_IMAGE), framePositions); - return; - } - if (tempFile.exists() == false || tempFile.length() < file.getSize()) { - ProgressHandle progress = ProgressHandle.createHandle(Bundle.FileSearch_genVideoThumb_progress_text(file.getName())); - progress.start(100); - try { - Files.createParentDirs(tempFile); - if (Thread.interrupted()) { - int[] framePositions = new int[]{ - 0, - 0, - 0, - 0}; - thumbnailWrapper.setThumbnails(createDefaultThumbnailList(VIDEO_DEFAULT_IMAGE), framePositions); - return; - } - ContentUtils.writeToFile(file, tempFile, progress, null, true); - } catch (IOException ex) { - logger.log(Level.WARNING, "Error extracting temporary file for " + file.getParentPath() + "/" + file.getName(), ex); //NON-NLS - } finally { - progress.finish(); - } - } - VideoCapture videoFile = new VideoCapture(); // will contain the video - BufferedImage bufferedImage = null; - - try { - if (!videoFile.open(tempFile.toString())) { - logger.log(Level.WARNING, "Error opening {0} for preview generation.", file.getParentPath() + "/" + file.getName()); //NON-NLS - int[] framePositions = new int[]{ - 0, - 0, - 0, - 0}; - thumbnailWrapper.setThumbnails(createDefaultThumbnailList(VIDEO_DEFAULT_IMAGE), framePositions); - return; - } - double fps = videoFile.get(5); // gets frame per second - double totalFrames = videoFile.get(7); // gets total frames - if (fps <= 0 || totalFrames <= 0) { - logger.log(Level.WARNING, "Error getting fps or total frames for {0}", file.getParentPath() + "/" + file.getName()); //NON-NLS - int[] framePositions = new int[]{ - 0, - 0, - 0, - 0}; - thumbnailWrapper.setThumbnails(createDefaultThumbnailList(VIDEO_DEFAULT_IMAGE), framePositions); - return; - } - if (Thread.interrupted()) { - int[] framePositions = new int[]{ - 0, - 0, - 0, - 0}; - thumbnailWrapper.setThumbnails(createDefaultThumbnailList(VIDEO_DEFAULT_IMAGE), framePositions); - return; - } - - double duration = 1000 * (totalFrames / fps); //total milliseconds - - int[] framePositions = new int[]{ - (int) (duration * .01), - (int) (duration * .25), - (int) (duration * .5), - (int) (duration * .75),}; - - Mat imageMatrix = new Mat(); - List videoThumbnails = new ArrayList<>(); - if (cacheDirectory == null || file.getMd5Hash() == null) { - cacheDirectory = null; - } else { - try { - FileUtils.forceMkdir(Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash()).toFile()); - } catch (IOException ex) { - cacheDirectory = null; - logger.log(Level.WARNING, "Unable to make video thumbnails directory, thumbnails will not be saved", ex); - } - } - for (int i = 0; i < framePositions.length; i++) { - if (!videoFile.set(0, framePositions[i])) { - logger.log(Level.WARNING, "Error seeking to " + framePositions[i] + "ms in {0}", file.getParentPath() + "/" + file.getName()); //NON-NLS - // If we can't set the time, continue to the next frame position and try again. - - videoThumbnails.add(VIDEO_DEFAULT_IMAGE); - if (cacheDirectory != null) { - try { - ImageIO.write(VIDEO_DEFAULT_IMAGE, THUMBNAIL_FORMAT, - Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash(), i + "-" + framePositions[i] + "." + THUMBNAIL_FORMAT).toFile()); //NON-NLS) - } catch (IOException ex) { - logger.log(Level.WARNING, "Unable to save default video thumbnail for " + file.getMd5Hash() + " at frame position " + framePositions[i], ex); - } - } - continue; - } - // Read the frame into the image/matrix. - if (!videoFile.read(imageMatrix)) { - logger.log(Level.WARNING, "Error reading frame at " + framePositions[i] + "ms from {0}", file.getParentPath() + "/" + file.getName()); //NON-NLS - // If the image is bad for some reason, continue to the next frame position and try again. - videoThumbnails.add(VIDEO_DEFAULT_IMAGE); - if (cacheDirectory != null) { - try { - ImageIO.write(VIDEO_DEFAULT_IMAGE, THUMBNAIL_FORMAT, - Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash(), i + "-" + framePositions[i] + "." + THUMBNAIL_FORMAT).toFile()); //NON-NLS) - } catch (IOException ex) { - logger.log(Level.WARNING, "Unable to save default video thumbnail for " + file.getMd5Hash() + " at frame position " + framePositions[i], ex); - } - } - - continue; - } - // If the image is empty, return since no buffered image can be created. - if (imageMatrix.empty()) { - videoThumbnails.add(VIDEO_DEFAULT_IMAGE); - if (cacheDirectory != null) { - try { - ImageIO.write(VIDEO_DEFAULT_IMAGE, THUMBNAIL_FORMAT, - Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash(), i + "-" + framePositions[i] + "." + THUMBNAIL_FORMAT).toFile()); //NON-NLS) - } catch (IOException ex) { - logger.log(Level.WARNING, "Unable to save default video thumbnail for " + file.getMd5Hash() + " at frame position " + framePositions[i], ex); - } - } - continue; - } - - int matrixColumns = imageMatrix.cols(); - int matrixRows = imageMatrix.rows(); - - // Convert the matrix that contains the frame to a buffered image. - if (bufferedImage == null) { - bufferedImage = new BufferedImage(matrixColumns, matrixRows, BufferedImage.TYPE_3BYTE_BGR); - } - - byte[] data = new byte[matrixRows * matrixColumns * (int) (imageMatrix.elemSize())]; - imageMatrix.get(0, 0, data); //copy the image to data - - if (imageMatrix.channels() == 3) { - for (int k = 0; k < data.length; k += 3) { - byte temp = data[k]; - data[k] = data[k + 2]; - data[k + 2] = temp; - } - } - - bufferedImage.getRaster().setDataElements(0, 0, matrixColumns, matrixRows, data); - if (Thread.interrupted()) { - thumbnailWrapper.setThumbnails(videoThumbnails, framePositions); - try { - FileUtils.forceDelete(Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash()).toFile()); - } catch (IOException ex) { - logger.log(Level.WARNING, "Unable to delete directory for cancelled video thumbnail process", ex); - } - return; - } - BufferedImage thumbnail = ScalrWrapper.resize(bufferedImage, Scalr.Method.SPEED, Scalr.Mode.FIT_TO_HEIGHT, ImageUtils.ICON_SIZE_LARGE, ImageUtils.ICON_SIZE_MEDIUM, Scalr.OP_ANTIALIAS); - //We are height limited here so it can be wider than it can be tall.Scalr maintains the aspect ratio. - videoThumbnails.add(thumbnail); - if (cacheDirectory != null) { - try { - ImageIO.write(thumbnail, THUMBNAIL_FORMAT, - Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash(), i + "-" + framePositions[i] + "." + THUMBNAIL_FORMAT).toFile()); //NON-NLS) - } catch (IOException ex) { - logger.log(Level.WARNING, "Unable to save video thumbnail for " + file.getMd5Hash() + " at frame position " + framePositions[i], ex); - } - } - } - thumbnailWrapper.setThumbnails(videoThumbnails, framePositions); - } finally { - videoFile.release(); // close the file} - } - } else { - loadSavedThumbnails(cacheDirectory, thumbnailWrapper, VIDEO_DEFAULT_IMAGE); - } - } - - /** - * Load the thumbnails that exist in the cache directory for the specified - * video file. - * - * @param cacheDirectory The directory which exists for the video - * thumbnails. - * @param thumbnailWrapper The VideoThumbnailWrapper object which contains - * information about the file and the thumbnails - * associated with it. - */ - private static void loadSavedThumbnails(String cacheDirectory, VideoThumbnailsWrapper thumbnailWrapper, BufferedImage failedVideoThumbImage) { - int[] framePositions = new int[4]; - List videoThumbnails = new ArrayList<>(); - int thumbnailNumber = 0; - String md5 = thumbnailWrapper.getResultFile().getFirstInstance().getMd5Hash(); - for (String fileName : Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, md5).toFile().list()) { - try { - videoThumbnails.add(ImageIO.read(Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, md5, fileName).toFile())); - } catch (IOException ex) { - videoThumbnails.add(failedVideoThumbImage); - logger.log(Level.WARNING, "Unable to read saved video thumbnail " + fileName + " for " + md5, ex); - } - int framePos = Integer.valueOf(FilenameUtils.getBaseName(fileName).substring(2)); - framePositions[thumbnailNumber] = framePos; - thumbnailNumber++; - } - thumbnailWrapper.setThumbnails(videoThumbnails, framePositions); - } - - /** - * Private helper method for creating video thumbnails, for use when no - * thumbnails are created. - * - * @return List containing the default thumbnail. - */ - private static List createDefaultThumbnailList(BufferedImage failedVideoThumbImage) { - List videoThumbnails = new ArrayList<>(); - videoThumbnails.add(failedVideoThumbImage); - videoThumbnails.add(failedVideoThumbImage); - videoThumbnails.add(failedVideoThumbImage); - videoThumbnails.add(failedVideoThumbImage); - return videoThumbnails; - } - private FileSearch() { // Class should not be instantiated } @@ -865,7 +390,7 @@ class FileSearch { /** * Base class for the grouping attributes. */ - abstract static class AttributeType { + public abstract static class AttributeType { /** * For a given file, return the key for the group it belongs to for this @@ -875,7 +400,7 @@ class FileSearch { * * @return the key for the group this file goes in */ - abstract GroupKey getGroupKey(ResultFile file); + public abstract GroupKey getGroupKey(ResultFile file); /** * Add any extra data to the ResultFile object from this attribute. @@ -887,60 +412,12 @@ class FileSearch { * * @throws FileSearchException */ - void addAttributeToResultFiles(List files, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws FileSearchException { + public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws FileSearchException { // Default is to do nothing } } - /** - * The key used for grouping for each attribute type. - */ - abstract static class GroupKey implements Comparable { - - /** - * Get the string version of the group key for display. Each display - * name should correspond to a unique GroupKey object. - * - * @return The display name for this key - */ - abstract String getDisplayName(); - - /** - * Subclasses must implement equals(). - * - * @param otherKey - * - * @return true if the keys are equal, false otherwise - */ - @Override - abstract public boolean equals(Object otherKey); - - /** - * Subclasses must implement hashCode(). - * - * @return the hash code - */ - @Override - abstract public int hashCode(); - - /** - * It should not happen with the current setup, but we need to cover the - * case where two different GroupKey subclasses are compared against - * each other. Use a lexicographic comparison on the class names. - * - * @param otherGroupKey The other group key - * - * @return result of alphabetical comparison on the class name - */ - int compareClassNames(GroupKey otherGroupKey) { - return this.getClass().getName().compareTo(otherGroupKey.getClass().getName()); - } - - @Override - public String toString() { - return getDisplayName(); - } - } + /** * Attribute for grouping/sorting by file size @@ -948,75 +425,18 @@ class FileSearch { static class FileSizeAttribute extends AttributeType { @Override - GroupKey getGroupKey(ResultFile file) { + public GroupKey getGroupKey(ResultFile file) { return new FileSizeGroupKey(file); } } - /** - * Key representing a file size group - */ - private static class FileSizeGroupKey extends GroupKey { - - private final FileSize fileSize; - - FileSizeGroupKey(ResultFile file) { - if (file.getFileType() == FileType.VIDEO) { - fileSize = FileSize.fromVideoSize(file.getFirstInstance().getSize()); - } else { - fileSize = FileSize.fromImageSize(file.getFirstInstance().getSize()); - } - } - - @Override - String getDisplayName() { - return getFileSize().toString(); - } - - @Override - public int compareTo(GroupKey otherGroupKey) { - if (otherGroupKey instanceof FileSizeGroupKey) { - FileSizeGroupKey otherFileSizeGroupKey = (FileSizeGroupKey) otherGroupKey; - return Integer.compare(getFileSize().getRanking(), otherFileSizeGroupKey.getFileSize().getRanking()); - } else { - return compareClassNames(otherGroupKey); - } - } - - @Override - public boolean equals(Object otherKey) { - if (otherKey == this) { - return true; - } - - if (!(otherKey instanceof FileSizeGroupKey)) { - return false; - } - - FileSizeGroupKey otherFileSizeGroupKey = (FileSizeGroupKey) otherKey; - return getFileSize().equals(otherFileSizeGroupKey.getFileSize()); - } - - @Override - public int hashCode() { - return Objects.hash(getFileSize().getRanking()); - } - - /** - * @return the fileSize - */ - FileSize getFileSize() { - return fileSize; - } - } - /** * Attribute for grouping/sorting by parent path */ - static class ParentPathAttribute extends AttributeType { + public static class ParentPathAttribute extends AttributeType { @Override - GroupKey getGroupKey(ResultFile file) { + public GroupKey getGroupKey(ResultFile file) { return new ParentPathGroupKey(file); } } @@ -1135,7 +555,7 @@ class FileSearch { static class DataSourceAttribute extends AttributeType { @Override - GroupKey getGroupKey(ResultFile file) { + public GroupKey getGroupKey(ResultFile file) { return new DataSourceGroupKey(file); } } @@ -1215,7 +635,7 @@ class FileSearch { static class FileTypeAttribute extends AttributeType { @Override - GroupKey getGroupKey(ResultFile file) { + public GroupKey getGroupKey(ResultFile file) { return new FileTypeGroupKey(file); } } @@ -1279,12 +699,12 @@ class FileSearch { static class KeywordListAttribute extends AttributeType { @Override - GroupKey getGroupKey(ResultFile file) { + public GroupKey getGroupKey(ResultFile file) { return new KeywordListGroupKey(file); } @Override - void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws FileSearchException { // Get pairs of (object ID, keyword list name) for all files in the list of files that have @@ -1434,12 +854,12 @@ class FileSearch { static final int BATCH_SIZE = 50; // Number of hashes to look up at one time @Override - GroupKey getGroupKey(ResultFile file) { + public GroupKey getGroupKey(ResultFile file) { return new FrequencyGroupKey(file); } @Override - void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws FileSearchException { if (centralRepoDb == null) { for (ResultFile file : files) { @@ -1582,12 +1002,12 @@ class FileSearch { static class HashHitsAttribute extends AttributeType { @Override - GroupKey getGroupKey(ResultFile file) { + public GroupKey getGroupKey(ResultFile file) { return new HashHitsGroupKey(file); } @Override - void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws FileSearchException { // Get pairs of (object ID, hash set name) for all files in the list of files that have @@ -1734,12 +1154,12 @@ class FileSearch { static class InterestingItemAttribute extends AttributeType { @Override - GroupKey getGroupKey(ResultFile file) { + public GroupKey getGroupKey(ResultFile file) { return new InterestingItemGroupKey(file); } @Override - void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws FileSearchException { // Get pairs of (object ID, interesting item set name) for all files in the list of files that have @@ -1888,12 +1308,12 @@ class FileSearch { static class ObjectDetectedAttribute extends AttributeType { @Override - GroupKey getGroupKey(ResultFile file) { + public GroupKey getGroupKey(ResultFile file) { return new ObjectDetectedGroupKey(file); } @Override - void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws FileSearchException { // Get pairs of (object ID, object type name) for all files in the list of files that have @@ -2041,12 +1461,12 @@ class FileSearch { static class FileTagAttribute extends AttributeType { @Override - GroupKey getGroupKey(ResultFile file) { - return new FileTagGroupKey(file); + public GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.FileTagGroupKey(file); } @Override - void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws FileSearchException { try { @@ -2063,202 +1483,7 @@ class FileSearch { } } - /** - * Represents a key for a specific search for a specific user. - */ - private static class SearchKey implements Comparable { - private final String keyString; - - /** - * Construct a new SearchKey with all information that defines a search. - * - * @param userName The name of the user performing the search. - * @param filters The FileFilters being used for the search. - * @param groupAttributeType The AttributeType to group by. - * @param groupSortingType The algorithm to sort the groups by. - * @param fileSortingMethod The method to sort the files by. - */ - SearchKey(String userName, List filters, - AttributeType groupAttributeType, - FileGroup.GroupSortingAlgorithm groupSortingType, - FileSorter.SortingMethod fileSortingMethod) { - StringBuilder searchStringBuilder = new StringBuilder(); - searchStringBuilder.append(userName); - for (AbstractFilter filter : filters) { - searchStringBuilder.append(filter.toString()); - } - searchStringBuilder.append(groupAttributeType).append(groupSortingType).append(fileSortingMethod); - keyString = searchStringBuilder.toString(); - } - - @Override - public int compareTo(SearchKey otherSearchKey) { - return getKeyString().compareTo(otherSearchKey.getKeyString()); - } - - @Override - public boolean equals(Object otherKey) { - if (otherKey == this) { - return true; - } - - if (!(otherKey instanceof SearchKey)) { - return false; - } - - SearchKey otherSearchKey = (SearchKey) otherKey; - return getKeyString().equals(otherSearchKey.getKeyString()); - } - - @Override - public int hashCode() { - int hash = 5; - hash = 79 * hash + Objects.hashCode(getKeyString()); - return hash; - } - - /** - * @return the keyString - */ - String getKeyString() { - return keyString; - } - } - - /** - * Key representing a file tag group - */ - private static class FileTagGroupKey extends GroupKey { - - private final List tagNames; - private final String tagNamesString; - - @NbBundle.Messages({ - "FileSearch.FileTagGroupKey.noSets=None"}) - FileTagGroupKey(ResultFile file) { - tagNames = file.getTagNames(); - - if (tagNames.isEmpty()) { - tagNamesString = Bundle.FileSearch_FileTagGroupKey_noSets(); - } else { - tagNamesString = String.join(",", tagNames); // NON-NLS - } - } - - @Override - String getDisplayName() { - return getTagNamesString(); - } - - @Override - public int compareTo(GroupKey otherGroupKey) { - if (otherGroupKey instanceof FileTagGroupKey) { - FileTagGroupKey otherFileTagGroupKey = (FileTagGroupKey) otherGroupKey; - - // Put the empty list at the end - if (getTagNames().isEmpty()) { - if (otherFileTagGroupKey.getTagNames().isEmpty()) { - return 0; - } else { - return 1; - } - } else if (otherFileTagGroupKey.getTagNames().isEmpty()) { - return -1; - } - - return getTagNamesString().compareTo(otherFileTagGroupKey.getTagNamesString()); - } else { - return compareClassNames(otherGroupKey); - } - } - - @Override - public boolean equals(Object otherKey) { - if (otherKey == this) { - return true; - } - - if (!(otherKey instanceof FileTagGroupKey)) { - return false; - } - - FileTagGroupKey otherFileTagGroupKey = (FileTagGroupKey) otherKey; - return getTagNamesString().equals(otherFileTagGroupKey.getTagNamesString()); - } - - @Override - public int hashCode() { - return Objects.hash(getTagNamesString()); - } - - /** - * @return the tagNames - */ - List getTagNames() { - return Collections.unmodifiableList(tagNames); - } - - /** - * @return the tagNamesString - */ - String getTagNamesString() { - return tagNamesString; - } - } - - /** - * Default attribute used to make one group - */ - static class NoGroupingAttribute extends AttributeType { - - @Override - GroupKey getGroupKey(ResultFile file) { - return new NoGroupingGroupKey(); - } - } - - /** - * Dummy key for when there is no grouping. All files will have the same - * key. - */ - private static class NoGroupingGroupKey extends GroupKey { - - NoGroupingGroupKey() { - // Nothing to save - all files will get the same GroupKey - } - - @NbBundle.Messages({ - "FileSearch.NoGroupingGroupKey.allFiles=All Files"}) - @Override - String getDisplayName() { - return Bundle.FileSearch_NoGroupingGroupKey_allFiles(); - } - - @Override - public int compareTo(GroupKey otherGroupKey) { - // As long as the other key is the same type, they are equal - if (otherGroupKey instanceof NoGroupingGroupKey) { - return 0; - } else { - return compareClassNames(otherGroupKey); - } - } - - @Override - public boolean equals(Object otherKey) { - if (otherKey == this) { - return true; - } - // As long as the other key is the same type, they are equal - return otherKey instanceof NoGroupingGroupKey; - } - - @Override - public int hashCode() { - return 0; - } - } /** * Enum for the attribute types that can be used for grouping. @@ -2275,7 +1500,7 @@ class FileSearch { "FileSearch.GroupingAttributeType.tag.displayName=Tag", "FileSearch.GroupingAttributeType.object.displayName=Object Detected", "FileSearch.GroupingAttributeType.none.displayName=None"}) - enum GroupingAttributeType { + public enum GroupingAttributeType { FILE_SIZE(new FileSizeAttribute(), Bundle.FileSearch_GroupingAttributeType_size_displayName()), FREQUENCY(new FrequencyAttribute(), Bundle.FileSearch_GroupingAttributeType_frequency_displayName()), KEYWORD_LIST_NAME(new KeywordListAttribute(), Bundle.FileSearch_GroupingAttributeType_keywordList_displayName()), @@ -2285,7 +1510,7 @@ class FileSearch { INTERESTING_ITEM_SET(new InterestingItemAttribute(), Bundle.FileSearch_GroupingAttributeType_interestingItem_displayName()), FILE_TAG(new FileTagAttribute(), Bundle.FileSearch_GroupingAttributeType_tag_displayName()), OBJECT_DETECTED(new ObjectDetectedAttribute(), Bundle.FileSearch_GroupingAttributeType_object_displayName()), - NO_GROUPING(new NoGroupingAttribute(), Bundle.FileSearch_GroupingAttributeType_none_displayName()); + NO_GROUPING(new DiscoveryKeyUtils.NoGroupingAttribute(), Bundle.FileSearch_GroupingAttributeType_none_displayName()); private final AttributeType attributeType; private final String displayName; @@ -2300,7 +1525,7 @@ class FileSearch { return displayName; } - AttributeType getAttributeType() { + public AttributeType getAttributeType() { return attributeType; } @@ -2309,7 +1534,7 @@ class FileSearch { * * @return enums that can be used to group images */ - static List getOptionsForGrouping() { + public static List getOptionsForGrouping() { return Arrays.asList(FILE_SIZE, FREQUENCY, PARENT_PATH, OBJECT_DETECTED, HASH_LIST_NAME, INTERESTING_ITEM_SET); } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/FileSearchData.java b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearchData.java similarity index 93% rename from Core/src/org/sleuthkit/autopsy/discovery/FileSearchData.java rename to Core/src/org/sleuthkit/autopsy/discovery/search/FileSearchData.java index a672930966..acd8fae2ea 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/FileSearchData.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearchData.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.search; import com.google.common.collect.ImmutableSet; import java.util.ArrayList; @@ -30,12 +30,12 @@ import org.sleuthkit.autopsy.coreutils.FileTypeUtils; /** * Utility enums for searches made for files with Discovery. */ -final class FileSearchData extends SearchData { +public final class FileSearchData implements SearchData { private final static long BYTES_PER_MB = 1000000; @Override - ResultType getResultType() { + public ResultType getResultType() { return ResultType.FILE; } @@ -49,7 +49,7 @@ final class FileSearchData extends SearchData { "FileSearchData.Frequency.verycommon.displayName=Very Common (100+)", "FileSearchData.Frequency.known.displayName=Known (NSRL)", "FileSearchData.Frequency.unknown.displayName=Unknown",}) - enum Frequency { + public enum Frequency { UNIQUE(0, 1, Bundle.FileSearchData_Frequency_unique_displayName()), RARE(1, 10, Bundle.FileSearchData_Frequency_rare_displayName()), COMMON(2, 100, Bundle.FileSearchData_Frequency_common_displayName()), @@ -72,7 +72,7 @@ final class FileSearchData extends SearchData { * * @return the rank (lower should be displayed first) */ - int getRanking() { + public int getRanking() { return ranking; } @@ -83,7 +83,7 @@ final class FileSearchData extends SearchData { * * @return the corresponding enum */ - static Frequency fromCount(long count) { + public static Frequency fromCount(long count) { if (count <= UNIQUE.getMaxOccur()) { return UNIQUE; } else if (count <= RARE.getMaxOccur()) { @@ -100,7 +100,7 @@ final class FileSearchData extends SearchData { * * @return enums that can be used to filter with a CR. */ - static List getOptionsForFilteringWithCr() { + public static List getOptionsForFilteringWithCr() { return Arrays.asList(UNIQUE, RARE, COMMON, VERY_COMMON, KNOWN); } @@ -110,7 +110,7 @@ final class FileSearchData extends SearchData { * * @return enums that can be used to filter without a CR. */ - static List getOptionsForFilteringWithoutCr() { + public static List getOptionsForFilteringWithoutCr() { return Arrays.asList(KNOWN, UNKNOWN); } @@ -122,7 +122,7 @@ final class FileSearchData extends SearchData { /** * @return the maxOccur */ - int getMaxOccur() { + public int getMaxOccur() { return maxOccur; } } @@ -149,7 +149,7 @@ final class FileSearchData extends SearchData { "FileSearchData.FileSize.16kbto100kb=: 16-100KB", "FileSearchData.FileSize.upTo500kb=: 0-500KB", "FileSearchData.FileSize.upTo16kb=: 0-16KB",}) - enum FileSize { + public enum FileSize { XXLARGE_VIDEO(0, 10000 * BYTES_PER_MB, -1, Bundle.FileSearchData_FileSize_XXLARGE_displayName(), Bundle.FileSearchData_FileSize_10PlusGb()), XLARGE_VIDEO(1, 5000 * BYTES_PER_MB, 10000 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_XLARGE_displayName(), Bundle.FileSearchData_FileSize_5gbto10gb()), LARGE_VIDEO(2, 1000 * BYTES_PER_MB, 5000 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_LARGE_displayName(), Bundle.FileSearchData_FileSize_1gbto5gb()), @@ -190,7 +190,7 @@ final class FileSearchData extends SearchData { * * @return the enum whose range contains the file size */ - static FileSize fromImageSize(long size) { + public static FileSize fromImageSize(long size) { if (size > XXLARGE_IMAGE.getMinBytes()) { return XXLARGE_IMAGE; } else if (size > XLARGE_IMAGE.getMinBytes()) { @@ -214,7 +214,7 @@ final class FileSearchData extends SearchData { * * @return the enum whose range contains the file size */ - static FileSize fromVideoSize(long size) { + public static FileSize fromVideoSize(long size) { if (size > XXLARGE_VIDEO.getMinBytes()) { return XXLARGE_VIDEO; } else if (size > XLARGE_VIDEO.getMinBytes()) { @@ -235,7 +235,7 @@ final class FileSearchData extends SearchData { * * @return the maximum file size that will fit in this range. */ - long getMaxBytes() { + public long getMaxBytes() { return maxBytes; } @@ -244,7 +244,7 @@ final class FileSearchData extends SearchData { * * @return the maximum file size that is not part of this range */ - long getMinBytes() { + public long getMinBytes() { return minBytes; } @@ -253,7 +253,7 @@ final class FileSearchData extends SearchData { * * @return the rank (lower should be displayed first) */ - int getRanking() { + public int getRanking() { return ranking; } @@ -262,7 +262,7 @@ final class FileSearchData extends SearchData { return sizeGroup + displaySize; } - String getSizeGroup() { + public String getSizeGroup() { return sizeGroup; } @@ -272,7 +272,7 @@ final class FileSearchData extends SearchData { * @return Enums that can be used to filter most file including images * by size. */ - static List getDefaultSizeOptions() { + public static List getDefaultSizeOptions() { return Arrays.asList(XXLARGE_IMAGE, XLARGE_IMAGE, LARGE_IMAGE, MEDIUM_IMAGE, SMALL_IMAGE, XSMALL_IMAGE); } @@ -281,7 +281,7 @@ final class FileSearchData extends SearchData { * * @return enums that can be used to filter videos by size. */ - static List getOptionsForVideos() { + public static List getOptionsForVideos() { return Arrays.asList(XXLARGE_VIDEO, XLARGE_VIDEO, LARGE_VIDEO, MEDIUM_VIDEO, SMALL_VIDEO, XSMALL_VIDEO); } } @@ -314,7 +314,7 @@ final class FileSearchData extends SearchData { .add("application/pdf", //NON-NLS "application/xhtml+xml").build(); //NON-NLS - static Collection getDocTypesWithoutImageExtraction() { + public static Collection getDocTypesWithoutImageExtraction() { return Collections.unmodifiableCollection(IMAGE_UNSUPPORTED_DOC_TYPES); } @@ -331,7 +331,7 @@ final class FileSearchData extends SearchData { "FileSearchData.FileType.Documents.displayName=Documents", "FileSearchData.FileType.Executables.displayName=Executables", "FileSearchData.FileType.Other.displayName=Other/Unknown"}) - enum FileType { + public enum FileType { IMAGE(0, Bundle.FileSearchData_FileType_Image_displayName(), FileTypeUtils.FileTypeCategory.IMAGE.getMediaTypes()), AUDIO(1, Bundle.FileSearchData_FileType_Audio_displayName(), FileTypeUtils.FileTypeCategory.AUDIO.getMediaTypes()), @@ -355,7 +355,7 @@ final class FileSearchData extends SearchData { * * @return Collection of MIME type strings */ - Collection getMediaTypes() { + public Collection getMediaTypes() { return Collections.unmodifiableCollection(mediaTypes); } @@ -369,7 +369,7 @@ final class FileSearchData extends SearchData { * * @return the rank (lower should be displayed first) */ - int getRanking() { + public int getRanking() { return ranking; } @@ -380,7 +380,7 @@ final class FileSearchData extends SearchData { * * @return the corresponding enum (will be OTHER if no types matched) */ - static FileType fromMIMEtype(String mimeType) { + public static FileType fromMIMEtype(String mimeType) { for (FileType type : FileType.values()) { if (type.getMediaTypes().contains(mimeType)) { return type; @@ -398,7 +398,7 @@ final class FileSearchData extends SearchData { "FileSearchData.Score.notable.displayName=Notable", "FileSearchData.Score.interesting.displayName=Interesting", "FileSearchData.Score.unknown.displayName=Unknown",}) - enum Score { + public enum Score { NOTABLE(0, Bundle.FileSearchData_Score_notable_displayName()), INTERESTING(1, Bundle.FileSearchData_Score_interesting_displayName()), UNKNOWN(2, Bundle.FileSearchData_Score_unknown_displayName()); @@ -416,7 +416,7 @@ final class FileSearchData extends SearchData { * * @return the rank (lower should be displayed first) */ - int getRanking() { + public int getRanking() { return ranking; } @@ -425,7 +425,7 @@ final class FileSearchData extends SearchData { * * @return enums that can be used to filter */ - static List getOptionsForFiltering() { + public static List getOptionsForFiltering() { return Arrays.asList(NOTABLE, INTERESTING); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/FileSearchException.java b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearchException.java similarity index 96% rename from Core/src/org/sleuthkit/autopsy/discovery/FileSearchException.java rename to Core/src/org/sleuthkit/autopsy/discovery/search/FileSearchException.java index df22e26488..a637bf43eb 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/FileSearchException.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearchException.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.search; /** * Exception type used for FileSearch. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/FileSorter.java b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSorter.java similarity index 97% rename from Core/src/org/sleuthkit/autopsy/discovery/FileSorter.java rename to Core/src/org/sleuthkit/autopsy/discovery/search/FileSorter.java index fc74dd5713..30064b5ce9 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/FileSorter.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSorter.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.search; import java.util.ArrayList; import java.util.Arrays; @@ -29,7 +29,7 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Class used to sort ResultFiles using the supplied method. */ -class FileSorter implements Comparator { +public class FileSorter implements Comparator { private final List> comparators = new ArrayList<>(); @@ -40,7 +40,7 @@ class FileSorter implements Comparator { * * @param method The method that should be used to sort the files */ - FileSorter(SortingMethod method) { + public FileSorter(SortingMethod method) { // Set up the primary comparators that should applied to the files switch (method) { @@ -247,7 +247,7 @@ class FileSorter implements Comparator { "FileSorter.SortingMethod.frequency.displayName=Central Repo Frequency", "FileSorter.SortingMethod.keywordlist.displayName=Keyword List Names", "FileSorter.SortingMethod.fullPath.displayName=Full Path"}) - enum SortingMethod { + public enum SortingMethod { BY_FILE_NAME(new ArrayList<>(), Bundle.FileSorter_SortingMethod_filename_displayName()), // Sort alphabetically by file name BY_DATA_SOURCE(new ArrayList<>(), @@ -276,7 +276,7 @@ class FileSorter implements Comparator { return displayName; } - List getRequiredAttributes() { + public List getRequiredAttributes() { return Collections.unmodifiableList(requiredAttributes); } @@ -285,7 +285,7 @@ class FileSorter implements Comparator { * * @return enums that can be used to ordering images. */ - static List getOptionsForOrdering() { + public static List getOptionsForOrdering() { return Arrays.asList(BY_FILE_SIZE, BY_FULL_PATH, BY_FILE_NAME, BY_DATA_SOURCE); } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ResultFile.java b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultFile.java similarity index 91% rename from Core/src/org/sleuthkit/autopsy/discovery/ResultFile.java rename to Core/src/org/sleuthkit/autopsy/discovery/search/ResultFile.java index 73d57ccf37..5d87a3cf07 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ResultFile.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultFile.java @@ -16,9 +16,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.search; -import org.sleuthkit.autopsy.discovery.FileSearchData.FileType; +import org.sleuthkit.autopsy.discovery.search.FileSearchData.FileType; import org.sleuthkit.datamodel.AbstractFile; import java.util.ArrayList; import java.util.Collections; @@ -39,7 +39,7 @@ import org.sleuthkit.datamodel.TskData; /** * Container for files that holds all necessary data for grouping and sorting. */ -class ResultFile { +public class ResultFile { private final static Logger logger = Logger.getLogger(ResultFile.class.getName()); private FileSearchData.Frequency frequency; @@ -59,7 +59,7 @@ class ResultFile { * * @param abstractFile */ - ResultFile(AbstractFile abstractFile) { + public ResultFile(AbstractFile abstractFile) { try { //call get uniquePath to cache the path abstractFile.getUniquePath(); @@ -86,7 +86,7 @@ class ResultFile { * * @return The Frequency enum */ - FileSearchData.Frequency getFrequency() { + public FileSearchData.Frequency getFrequency() { return frequency; } @@ -95,7 +95,7 @@ class ResultFile { * * @param frequency The frequency of the file as an enum */ - void setFrequency(FileSearchData.Frequency frequency) { + public void setFrequency(FileSearchData.Frequency frequency) { this.frequency = frequency; } @@ -105,7 +105,7 @@ class ResultFile { * * @param duplicate The abstract file to add as a duplicate. */ - void addDuplicate(AbstractFile duplicate) { + public void addDuplicate(AbstractFile duplicate) { if (deleted && !duplicate.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC)) { deleted = false; } @@ -128,7 +128,7 @@ class ResultFile { * * @return The score of this ResultFile. */ - DataResultViewerTable.Score getScore() { + public DataResultViewerTable.Score getScore() { return currentScore; } @@ -137,7 +137,7 @@ class ResultFile { * * @return The score description of this ResultFile. */ - String getScoreDescription() { + public String getScoreDescription() { return scoreDescription; } @@ -147,7 +147,7 @@ class ResultFile { * * @return The deleted status of this ResultFile. */ - boolean isDeleted() { + public boolean isDeleted() { return deleted; } @@ -158,7 +158,7 @@ class ResultFile { * @return The list of AbstractFiles which have been identified as instances * of this file. */ - List getAllInstances() { + public List getAllInstances() { return Collections.unmodifiableList(instances); } @@ -167,7 +167,7 @@ class ResultFile { * * @return The FileType enum. */ - FileType getFileType() { + public FileType getFileType() { return fileType; } @@ -176,7 +176,7 @@ class ResultFile { * * @param keywordListName */ - void addKeywordListName(String keywordListName) { + public void addKeywordListName(String keywordListName) { if (!keywordListNames.contains(keywordListName)) { keywordListNames.add(keywordListName); } @@ -190,7 +190,7 @@ class ResultFile { * * @return the keyword list names that matched this file. */ - List getKeywordListNames() { + public List getKeywordListNames() { return Collections.unmodifiableList(keywordListNames); } @@ -199,7 +199,7 @@ class ResultFile { * * @param hashSetName */ - void addHashSetName(String hashSetName) { + public void addHashSetName(String hashSetName) { if (!hashSetNames.contains(hashSetName)) { hashSetNames.add(hashSetName); } @@ -213,7 +213,7 @@ class ResultFile { * * @return The hash set names that matched this file. */ - List getHashSetNames() { + public List getHashSetNames() { return Collections.unmodifiableList(hashSetNames); } @@ -222,7 +222,7 @@ class ResultFile { * * @param tagName */ - void addTagName(String tagName) { + public void addTagName(String tagName) { if (!tagNames.contains(tagName)) { tagNames.add(tagName); } @@ -236,7 +236,7 @@ class ResultFile { * * @return the tag names that matched this file. */ - List getTagNames() { + public List getTagNames() { return Collections.unmodifiableList(tagNames); } @@ -245,7 +245,7 @@ class ResultFile { * * @param interestingSetName */ - void addInterestingSetName(String interestingSetName) { + public void addInterestingSetName(String interestingSetName) { if (!interestingSetNames.contains(interestingSetName)) { interestingSetNames.add(interestingSetName); } @@ -259,7 +259,7 @@ class ResultFile { * * @return the interesting item set names that matched this file. */ - List getInterestingSetNames() { + public List getInterestingSetNames() { return Collections.unmodifiableList(interestingSetNames); } @@ -268,7 +268,7 @@ class ResultFile { * * @param objectDetectedName */ - void addObjectDetectedName(String objectDetectedName) { + public void addObjectDetectedName(String objectDetectedName) { if (!objectDetectedNames.contains(objectDetectedName)) { objectDetectedNames.add(objectDetectedName); } @@ -282,7 +282,7 @@ class ResultFile { * * @return the objects detected in this file. */ - List getObjectDetectedNames() { + public List getObjectDetectedNames() { return Collections.unmodifiableList(objectDetectedNames); } @@ -291,7 +291,7 @@ class ResultFile { * * @return the AbstractFile object */ - AbstractFile getFirstInstance() { + public AbstractFile getFirstInstance() { return instances.get(0); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/SearchData.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchData.java similarity index 85% rename from Core/src/org/sleuthkit/autopsy/discovery/SearchData.java rename to Core/src/org/sleuthkit/autopsy/discovery/search/SearchData.java index 4368de669b..6807e334dd 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/SearchData.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchData.java @@ -16,17 +16,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.search; /** * Abstract class to contain data that is common to all result types. */ -abstract class SearchData { +public interface SearchData { /** * Enum of the broad result type categories. */ - enum ResultType { + public enum ResultType { FILE, ATTRIBUTE; } @@ -34,6 +34,6 @@ abstract class SearchData { /** * Get the broad result type. */ - abstract ResultType getResultType(); + public abstract ResultType getResultType(); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/SearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java similarity index 89% rename from Core/src/org/sleuthkit/autopsy/discovery/SearchFiltering.java rename to Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java index bf52e38563..fa2dd972fd 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/SearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java @@ -16,16 +16,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.search; -import org.sleuthkit.autopsy.discovery.ui.AbstractFilter; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; -import org.sleuthkit.autopsy.discovery.FileSearchData.FileSize; -import org.sleuthkit.autopsy.discovery.FileSearchData.FileType; -import org.sleuthkit.autopsy.discovery.FileSearchData.Frequency; -import org.sleuthkit.autopsy.discovery.FileSearchData.Score; +import org.sleuthkit.autopsy.discovery.search.FileSearchData.FileSize; +import org.sleuthkit.autopsy.discovery.search.FileSearchData.FileType; +import org.sleuthkit.autopsy.discovery.search.FileSearchData.Frequency; +import org.sleuthkit.autopsy.discovery.search.FileSearchData.Score; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.SleuthkitCase; @@ -43,7 +42,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; /** * Run various filters to return a subset of files from the current case. */ -class SearchFiltering { +public class SearchFiltering { /** * Run the given filters to get a list of matching files. @@ -126,7 +125,7 @@ class SearchFiltering { /** * A filter for specifying the file size */ - static class SizeFilter extends AbstractFilter { + public static class SizeFilter extends AbstractFilter { private final List fileSizes; @@ -135,12 +134,12 @@ class SearchFiltering { * * @param fileSizes the file sizes that should match */ - SizeFilter(List fileSizes) { + public SizeFilter(List fileSizes) { this.fileSizes = fileSizes; } @Override - String getWhereClause() { + public String getWhereClause() { String queryStr = ""; // NON-NLS for (FileSize size : fileSizes) { if (!queryStr.isEmpty()) { @@ -160,7 +159,7 @@ class SearchFiltering { "SearchFiltering.SizeFilter.desc=Size(s): {0}", "SearchFiltering.SizeFilter.or=, "}) @Override - String getDesc() { + public String getDesc() { String desc = ""; // NON-NLS for (FileSize size : fileSizes) { if (!desc.isEmpty()) { @@ -177,7 +176,7 @@ class SearchFiltering { * A utility class for the ParentFilter to store the search string and * whether it is a full path or a substring. */ - static class ParentSearchTerm { + public static class ParentSearchTerm { private final String searchStr; private final boolean fullPath; @@ -192,7 +191,7 @@ class SearchFiltering { * @param isIncluded True if the results must include the path, false if * the path should be excluded from the results. */ - ParentSearchTerm(String searchStr, boolean isFullPath, boolean isIncluded) { + public ParentSearchTerm(String searchStr, boolean isFullPath, boolean isIncluded) { this.searchStr = searchStr; this.fullPath = isFullPath; this.included = isIncluded; @@ -203,7 +202,7 @@ class SearchFiltering { * * @return The SQL for a where clause to search for a matching path */ - String getSQLForTerm() { + public String getSQLForTerm() { // TODO - these should really be prepared statements if (isIncluded()) { if (isFullPath()) { @@ -244,21 +243,21 @@ class SearchFiltering { /** * @return the fullPath */ - boolean isFullPath() { + public boolean isFullPath() { return fullPath; } /** * @return the included */ - boolean isIncluded() { + public boolean isIncluded() { return included; } /** * @return the searchStr */ - String getSearchStr() { + public String getSearchStr() { return searchStr; } } @@ -266,7 +265,7 @@ class SearchFiltering { /** * A filter for specifying parent path (either full path or substring) */ - static class ParentFilter extends AbstractFilter { + public static class ParentFilter extends AbstractFilter { private final List parentSearchTerms; @@ -275,12 +274,12 @@ class SearchFiltering { * * @param parentSearchTerms Full paths or substrings to filter on */ - ParentFilter(List parentSearchTerms) { + public ParentFilter(List parentSearchTerms) { this.parentSearchTerms = parentSearchTerms; } @Override - String getWhereClause() { + public String getWhereClause() { String includeQueryStr = ""; // NON-NLS String excludeQueryStr = ""; for (ParentSearchTerm searchTerm : parentSearchTerms) { @@ -318,7 +317,7 @@ class SearchFiltering { "SearchFiltering.ParentFilter.included=(included)", "SearchFiltering.ParentFilter.excluded=(excluded)"}) @Override - String getDesc() { + public String getDesc() { String desc = ""; // NON-NLS for (ParentSearchTerm searchTerm : parentSearchTerms) { if (!desc.isEmpty()) { @@ -343,7 +342,7 @@ class SearchFiltering { /** * A filter for specifying data sources */ - static class DataSourceFilter extends AbstractFilter { + public static class DataSourceFilter extends AbstractFilter { private final List dataSources; @@ -352,12 +351,12 @@ class SearchFiltering { * * @param dataSources the data sources to filter on */ - DataSourceFilter(List dataSources) { + public DataSourceFilter(List dataSources) { this.dataSources = dataSources; } @Override - String getWhereClause() { + public String getWhereClause() { String queryStr = ""; // NON-NLS for (DataSource ds : dataSources) { if (!queryStr.isEmpty()) { @@ -377,7 +376,7 @@ class SearchFiltering { "# {1} - Data source ID", "SearchFiltering.DataSourceFilter.datasource={0}({1})",}) @Override - String getDesc() { + public String getDesc() { String desc = ""; // NON-NLS for (DataSource ds : dataSources) { if (!desc.isEmpty()) { @@ -394,7 +393,7 @@ class SearchFiltering { * A filter for specifying keyword list names. A file must contain a keyword * from one of the given lists to pass. */ - static class KeywordListFilter extends AbstractFilter { + public static class KeywordListFilter extends AbstractFilter { private final List listNames; @@ -403,12 +402,12 @@ class SearchFiltering { * * @param listNames */ - KeywordListFilter(List listNames) { + public KeywordListFilter(List listNames) { this.listNames = listNames; } @Override - String getWhereClause() { + public String getWhereClause() { String keywordListPart = concatenateNamesForSQL(listNames); String queryStr = "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN " @@ -422,7 +421,7 @@ class SearchFiltering { "# {0} - filters", "SearchFiltering.KeywordListFilter.desc=Keywords in list(s): {0}",}) @Override - String getDesc() { + public String getDesc() { return Bundle.SearchFiltering_KeywordListFilter_desc(concatenateSetNamesForDisplay(listNames)); } } @@ -430,7 +429,7 @@ class SearchFiltering { /** * A filter for specifying file types. */ - static class FileTypeFilter extends AbstractFilter { + public static class FileTypeFilter extends AbstractFilter { private final List categories; @@ -439,7 +438,7 @@ class SearchFiltering { * * @param categories List of file types to filter on */ - FileTypeFilter(List categories) { + public FileTypeFilter(List categories) { this.categories = categories; } @@ -448,13 +447,13 @@ class SearchFiltering { * * @param category the file type to filter on */ - FileTypeFilter(FileType category) { + public FileTypeFilter(FileType category) { this.categories = new ArrayList<>(); this.categories.add(category); } @Override - String getWhereClause() { + public String getWhereClause() { String queryStr = ""; // NON-NLS for (FileType cat : categories) { for (String type : cat.getMediaTypes()) { @@ -473,7 +472,7 @@ class SearchFiltering { "SearchFiltering.FileTypeFilter.desc=Type: {0}", "SearchFiltering.FileTypeFilter.or=, ",}) @Override - String getDesc() { + public String getDesc() { String desc = ""; for (FileType cat : categories) { if (!desc.isEmpty()) { @@ -489,7 +488,7 @@ class SearchFiltering { /** * A filter for specifying frequency in the central repository. */ - static class FrequencyFilter extends AbstractFilter { + public static class FrequencyFilter extends AbstractFilter { private final List frequencies; @@ -498,24 +497,24 @@ class SearchFiltering { * * @param frequencies List of frequencies that will pass the filter */ - FrequencyFilter(List frequencies) { + public FrequencyFilter(List frequencies) { this.frequencies = frequencies; } @Override - String getWhereClause() { + public String getWhereClause() { // Since this relies on the central repository database, there is no // query on the case database. return ""; // NON-NLS } @Override - boolean useAlternateFilter() { + public boolean useAlternateFilter() { return true; } @Override - List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, + public List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws FileSearchException { // We have to have run some kind of SQL filter before getting to this point, @@ -543,7 +542,7 @@ class SearchFiltering { "SearchFiltering.FrequencyFilter.desc=Past occurrences: {0}", "SearchFiltering.FrequencyFilter.or=, ",}) @Override - String getDesc() { + public String getDesc() { String desc = ""; // NON-NLS for (Frequency freq : frequencies) { if (!desc.isEmpty()) { @@ -559,7 +558,7 @@ class SearchFiltering { * A filter for specifying hash set names. A file must match one of the * given sets to pass. */ - static class HashSetFilter extends AbstractFilter { + public static class HashSetFilter extends AbstractFilter { private final List setNames; @@ -568,12 +567,12 @@ class SearchFiltering { * * @param setNames */ - HashSetFilter(List setNames) { + public HashSetFilter(List setNames) { this.setNames = setNames; } @Override - String getWhereClause() { + public String getWhereClause() { String hashSetPart = concatenateNamesForSQL(setNames); String queryStr = "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN " @@ -588,7 +587,7 @@ class SearchFiltering { "# {0} - filters", "FileSearchFiltering.HashSetFilter.desc=Hash set hits in set(s): {0}",}) @Override - String getDesc() { + public String getDesc() { return Bundle.FileSearchFiltering_HashSetFilter_desc(concatenateSetNamesForDisplay(setNames)); } } @@ -597,7 +596,7 @@ class SearchFiltering { * A filter for specifying interesting file set names. A file must match one * of the given sets to pass. */ - static class InterestingFileSetFilter extends AbstractFilter { + public static class InterestingFileSetFilter extends AbstractFilter { private final List setNames; @@ -606,12 +605,12 @@ class SearchFiltering { * * @param setNames */ - InterestingFileSetFilter(List setNames) { + public InterestingFileSetFilter(List setNames) { this.setNames = setNames; } @Override - String getWhereClause() { + public String getWhereClause() { String intItemSetPart = concatenateNamesForSQL(setNames); String queryStr = "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN " @@ -626,7 +625,7 @@ class SearchFiltering { "# {0} - filters", "SearchFiltering.InterestingItemSetFilter.desc=Interesting item hits in set(s): {0}",}) @Override - String getDesc() { + public String getDesc() { return Bundle.SearchFiltering_InterestingItemSetFilter_desc(concatenateSetNamesForDisplay(setNames)); } } @@ -635,7 +634,7 @@ class SearchFiltering { * A filter for specifying object types detected. A file must match one of * the given types to pass. */ - static class ObjectDetectionFilter extends AbstractFilter { + public static class ObjectDetectionFilter extends AbstractFilter { private final List typeNames; @@ -644,12 +643,12 @@ class SearchFiltering { * * @param typeNames */ - ObjectDetectionFilter(List typeNames) { + public ObjectDetectionFilter(List typeNames) { this.typeNames = typeNames; } @Override - String getWhereClause() { + public String getWhereClause() { String objTypePart = concatenateNamesForSQL(typeNames); String queryStr = "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN " @@ -664,7 +663,7 @@ class SearchFiltering { "# {0} - filters", "SearchFiltering.ObjectDetectionFilter.desc=Objects detected in set(s): {0}",}) @Override - String getDesc() { + public String getDesc() { return Bundle.SearchFiltering_ObjectDetectionFilter_desc(concatenateSetNamesForDisplay(typeNames)); } } @@ -673,7 +672,7 @@ class SearchFiltering { * A filter for specifying the score. A file must have one of the given * scores to pass */ - static class ScoreFilter extends AbstractFilter { + public static class ScoreFilter extends AbstractFilter { private final List scores; @@ -682,12 +681,12 @@ class SearchFiltering { * * @param typeNames */ - ScoreFilter(List scores) { + public ScoreFilter(List scores) { this.scores = scores; } @Override - String getWhereClause() { + public String getWhereClause() { // Current algorithm: // "Notable" if the file is a match for a notable hashset or has been tagged with a notable tag. @@ -740,7 +739,7 @@ class SearchFiltering { "# {0} - filters", "SearchFiltering.ScoreFilter.desc=Score(s) of : {0}",}) @Override - String getDesc() { + public String getDesc() { return Bundle.SearchFiltering_ScoreFilter_desc( concatenateSetNamesForDisplay(scores.stream().map(p -> p.toString()).collect(Collectors.toList()))); } @@ -750,7 +749,7 @@ class SearchFiltering { * A filter for specifying tag names. A file must contain one of the given * tags to pass. */ - static class TagsFilter extends AbstractFilter { + public static class TagsFilter extends AbstractFilter { private final List tagNames; @@ -759,12 +758,12 @@ class SearchFiltering { * * @param tagNames */ - TagsFilter(List tagNames) { + public TagsFilter(List tagNames) { this.tagNames = tagNames; } @Override - String getWhereClause() { + public String getWhereClause() { String tagIDs = ""; // NON-NLS for (TagName tagName : tagNames) { if (!tagIDs.isEmpty()) { @@ -783,7 +782,7 @@ class SearchFiltering { "FileSearchFiltering.TagsFilter.desc=Tagged {0}", "FileSearchFiltering.TagsFilter.or=, ",}) @Override - String getDesc() { + public String getDesc() { String desc = ""; // NON-NLS for (TagName name : tagNames) { if (!desc.isEmpty()) { @@ -799,17 +798,10 @@ class SearchFiltering { * A filter for specifying that the file must have user content suspected * data. */ - static class UserCreatedFilter extends AbstractFilter { - - /** - * Create the ExifFilter - */ - UserCreatedFilter() { - // Nothing to save - } + public static class UserCreatedFilter extends AbstractFilter { @Override - String getWhereClause() { + public String getWhereClause() { return "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN " + "(SELECT artifact_id FROM blackboard_attributes WHERE artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_USER_CONTENT_SUSPECTED.getTypeID() + ")))"; @@ -818,7 +810,7 @@ class SearchFiltering { @NbBundle.Messages({ "FileSearchFiltering.UserCreatedFilter.desc=that contain EXIF data",}) @Override - String getDesc() { + public String getDesc() { return Bundle.FileSearchFiltering_UserCreatedFilter_desc(); } } @@ -827,29 +819,22 @@ class SearchFiltering { * A filter for specifying that the file must have been marked as notable in * the CR. */ - static class NotableFilter extends AbstractFilter { - - /** - * Create the NotableFilter - */ - NotableFilter() { - // Nothing to save - } + public static class NotableFilter extends AbstractFilter { @Override - String getWhereClause() { + public String getWhereClause() { // Since this relies on the central repository database, there is no // query on the case database. return ""; // NON-NLS } @Override - boolean useAlternateFilter() { + public boolean useAlternateFilter() { return true; } @Override - List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, + public List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws FileSearchException { if (centralRepoDb == null) { @@ -887,7 +872,7 @@ class SearchFiltering { @NbBundle.Messages({ "FileSearchFiltering.PreviouslyNotableFilter.desc=that were previously marked as notable",}) @Override - String getDesc() { + public String getDesc() { return Bundle.FileSearchFiltering_PreviouslyNotableFilter_desc(); } } @@ -895,17 +880,17 @@ class SearchFiltering { /** * A filter for specifying if known files should be included. */ - static class KnownFilter extends AbstractFilter { + public static class KnownFilter extends AbstractFilter { @Override - String getWhereClause() { + public String getWhereClause() { return "known!=" + TskData.FileKnown.KNOWN.getFileKnownValue(); // NON-NLS } @NbBundle.Messages({ "FileSearchFiltering.KnownFilter.desc=which are not known"}) @Override - String getDesc() { + public String getDesc() { return Bundle.FileSearchFiltering_KnownFilter_desc(); } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/SearchResults.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java similarity index 95% rename from Core/src/org/sleuthkit/autopsy/discovery/SearchResults.java rename to Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java index 29e6eb924d..6484fbf5ae 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/SearchResults.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.discovery; +package org.sleuthkit.autopsy.discovery.search; import java.util.ArrayList; import java.util.Collections; @@ -25,7 +25,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import org.sleuthkit.autopsy.discovery.FileSearch.GroupKey; +import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; /** * Class to hold the results of the filtering/grouping/sorting operations. @@ -36,7 +36,7 @@ class SearchResults { private final FileSearch.AttributeType attrType; private final FileSorter fileSorter; - private final Map groupMap = new HashMap<>(); + private final Map groupMap = new HashMap<>(); private List groupList = new ArrayList<>(); private static final long MAX_OUTPUT_FILES = 2000; // For debug UI - maximum number of lines to print @@ -75,7 +75,7 @@ class SearchResults { void add(List files) { for (ResultFile file : files) { // Add the file to the appropriate group, creating it if necessary - FileSearch.GroupKey groupKey = attrType.getGroupKey(file); + GroupKey groupKey = attrType.getGroupKey(file); if (!groupMap.containsKey(groupKey)) { groupMap.put(groupKey, new FileGroup(groupSortingType, groupKey)); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SummaryHelpers.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SummaryHelpers.java new file mode 100644 index 0000000000..60e7e171ca --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SummaryHelpers.java @@ -0,0 +1,236 @@ +/* + * 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.discovery.search; + +import com.google.common.io.Files; +import java.awt.Image; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Reader; +import java.nio.file.Paths; +import java.util.Collection; +import java.util.logging.Level; +import org.apache.commons.lang.StringUtils; +import org.openide.util.Lookup; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.coreutils.ImageUtils; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.textextractors.TextExtractor; +import org.sleuthkit.autopsy.textextractors.TextExtractorFactory; +import org.sleuthkit.autopsy.textsummarizer.TextSummarizer; +import org.sleuthkit.autopsy.textsummarizer.TextSummary; +import org.sleuthkit.autopsy.texttranslation.NoServiceProviderException; +import org.sleuthkit.autopsy.texttranslation.TextTranslationService; +import org.sleuthkit.autopsy.texttranslation.TranslationException; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Utility class for code which helps create summaries for Discovery. + */ +class SummaryHelpers { + + private static final int PREVIEW_SIZE = 256; + private final static Logger logger = Logger.getLogger(SummaryHelpers.class.getName()); + private static volatile TextSummarizer summarizerToUse = null; + + private SummaryHelpers() { + // Class should not be instantiated + } + + static TextSummary getDefaultSummary(AbstractFile file) { + Image image = null; + int countOfImages = 0; + try { + Content largestChild = null; + for (Content child : file.getChildren()) { + if (child instanceof AbstractFile && ImageUtils.isImageThumbnailSupported((AbstractFile) child)) { + countOfImages++; + if (largestChild == null || child.getSize() > largestChild.getSize()) { + largestChild = child; + } + } + } + if (largestChild != null) { + image = ImageUtils.getThumbnail(largestChild, ImageUtils.ICON_SIZE_LARGE); + } + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Error getting children for file: " + file.getId(), ex); + } + image = image == null ? image : image.getScaledInstance(ImageUtils.ICON_SIZE_MEDIUM, ImageUtils.ICON_SIZE_MEDIUM, + Image.SCALE_SMOOTH); + String summaryText = null; + if (file.getMd5Hash() != null) { + try { + summaryText = getSavedSummary(Paths.get(Case.getCurrentCaseThrows().getCacheDirectory(), "summaries", file.getMd5Hash() + "-default-" + PREVIEW_SIZE + "-translated.txt").toString()); + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Unable to retrieve saved summary. No case is open.", ex); + } + } + if (StringUtils.isBlank(summaryText)) { + String firstLines = getFirstLines(file); + String translatedFirstLines = getTranslatedVersion(firstLines); + if (!StringUtils.isBlank(translatedFirstLines)) { + summaryText = translatedFirstLines; + if (file.getMd5Hash() != null) { + try { + saveSummary(summaryText, Paths.get(Case.getCurrentCaseThrows().getCacheDirectory(), "summaries", file.getMd5Hash() + "-default-" + PREVIEW_SIZE + "-translated.txt").toString()); + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Unable to save translated summary. No case is open.", ex); + } + } + } else { + summaryText = firstLines; + } + } + return new TextSummary(summaryText, image, countOfImages); + } + + /** + * Provide an English version of the specified String if it is not English, + * translation is enabled, and it can be translated. + * + * @param documentString The String to provide an English version of. + * + * @return The English version of the provided String, or null if no + * translation occurred. + */ + static String getTranslatedVersion(String documentString) { + try { + TextTranslationService translatorInstance = TextTranslationService.getInstance(); + if (translatorInstance.hasProvider()) { + String translatedResult = translatorInstance.translate(documentString); + if (translatedResult.isEmpty() == false) { + return translatedResult; + } + } + } catch (NoServiceProviderException | TranslationException ex) { + logger.log(Level.INFO, "Error translating string for summary", ex); + } + return null; + } + + /** + * Find and load a saved summary from the case folder for the specified + * file. + * + * @param summarySavePath The full path for the saved summary file. + * + * @return The summary found given the specified path, null if no summary + * was found. + */ + static String getSavedSummary(String summarySavePath) { + if (summarySavePath == null) { + return null; + } + File savedFile = new File(summarySavePath); + if (savedFile.exists()) { + try (BufferedReader bReader = new BufferedReader(new FileReader(savedFile))) { + // pass the path to the file as a parameter + StringBuilder sBuilder = new StringBuilder(PREVIEW_SIZE); + String sCurrentLine = bReader.readLine(); + while (sCurrentLine != null) { + sBuilder.append(sCurrentLine).append('\n'); + sCurrentLine = bReader.readLine(); + } + return sBuilder.toString(); + } catch (IOException ingored) { + //summary file may not exist or may be incomplete in which case return null so a summary can be generated + return null; //no saved summary was able to be found + } + } else { + try { //if the file didn't exist make sure the parent directories exist before we move on to creating a summary + Files.createParentDirs(savedFile); + } catch (IOException ex) { + logger.log(Level.WARNING, "Unable to create summaries directory in case folder for file at: " + summarySavePath, ex); + } + return null; //no saved summary was able to be found + } + + } + + /** + * Save a summary at the specified location. + * + * @param summary The text of the summary being saved. + * @param summarySavePath The full path for the saved summary file. + */ + static void saveSummary(String summary, String summarySavePath) { + if (summarySavePath == null) { + return; //can't save a summary if we don't have a path + } + try (FileWriter myWriter = new FileWriter(summarySavePath)) { + myWriter.write(summary); + } catch (IOException ex) { + logger.log(Level.WARNING, "Unable to save summary at: " + summarySavePath, ex); + } + } + + /** + * Get the beginning of text from the specified AbstractFile. + * + * @param file The AbstractFile to get text from. + * + * @return The beginning of text from the specified AbstractFile. + */ + static String getFirstLines(AbstractFile file) { + TextExtractor extractor; + try { + extractor = TextExtractorFactory.getExtractor(file, null); + } catch (TextExtractorFactory.NoTextExtractorFound ignored) { + //no extractor found, use Strings Extractor + extractor = TextExtractorFactory.getStringsExtractor(file, null); + } + + try (Reader reader = extractor.getReader()) { + char[] cbuf = new char[PREVIEW_SIZE]; + reader.read(cbuf, 0, PREVIEW_SIZE); + return new String(cbuf); + } catch (IOException ex) { + return Bundle.FileSearch_documentSummary_noBytes(); + } catch (TextExtractor.InitReaderException ex) { + return Bundle.FileSearch_documentSummary_noPreview(); + } + } + + /** + * Get the first TextSummarizer found by a lookup of TextSummarizers. + * + * @return The first TextSummarizer found by a lookup of TextSummarizers. + * + * @throws IOException + */ + static TextSummarizer getLocalSummarizer() { + if (summarizerToUse == null) { + Collection summarizers + = Lookup.getDefault().lookupAll(TextSummarizer.class + ); + if (!summarizers.isEmpty()) { + summarizerToUse = summarizers.iterator().next(); + } + } + return summarizerToUse; + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractDiscoveryFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractDiscoveryFilterPanel.java index 2be3071af6..d3770ef5ac 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractDiscoveryFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractDiscoveryFilterPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.discovery.ui; +import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import java.awt.event.ActionListener; import javax.swing.JCheckBox; import javax.swing.JLabel; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java index eb7d0de8c8..20273e6ae7 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.discovery.ui; +import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import java.awt.Component; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; @@ -31,10 +32,10 @@ import javax.swing.JSplitPane; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import org.apache.commons.lang3.StringUtils; -import org.sleuthkit.autopsy.discovery.AttributeSearchData; -import org.sleuthkit.autopsy.discovery.FileSearchData; -import org.sleuthkit.autopsy.discovery.SearchData; -import org.sleuthkit.autopsy.discovery.SearchFiltering; +import org.sleuthkit.autopsy.discovery.search.AttributeSearchData; +import org.sleuthkit.autopsy.discovery.search.FileSearchData; +import org.sleuthkit.autopsy.discovery.search.SearchData; +import org.sleuthkit.autopsy.discovery.search.SearchFiltering; /** * Abstract class extending JPanel for displaying all the filters associated diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java index c7691cb2b0..4430d793ab 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java @@ -18,11 +18,12 @@ */ package org.sleuthkit.autopsy.discovery.ui; +import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; -import org.sleuthkit.autopsy.discovery.AttributeSearchData; +import org.sleuthkit.autopsy.discovery.search.AttributeSearchData; import org.sleuthkit.datamodel.BlackboardArtifact; /** diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED similarity index 100% rename from Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED rename to Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DataSourceFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DataSourceFilterPanel.java index 6321afa357..f9b4ab9d27 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DataSourceFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DataSourceFilterPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.discovery.ui; +import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import java.util.List; import java.util.logging.Level; import java.util.stream.Collectors; @@ -27,7 +28,7 @@ import javax.swing.JLabel; import javax.swing.JList; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.discovery.SearchFiltering; +import org.sleuthkit.autopsy.discovery.search.SearchFiltering; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DataSourceModulesWrapper.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DataSourceModulesWrapper.java index 170aec7acf..b1981d22aa 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DataSourceModulesWrapper.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DataSourceModulesWrapper.java @@ -19,7 +19,6 @@ package org.sleuthkit.autopsy.discovery.ui; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.discovery.Bundle; import org.sleuthkit.autopsy.modules.exif.ExifParserModuleFactory; import org.sleuthkit.autopsy.modules.filetypeid.FileTypeIdModuleFactory; import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupModuleFactory; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java index 1776e862d4..cf78c5fe7d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java @@ -18,13 +18,13 @@ */ package org.sleuthkit.autopsy.discovery.ui; +import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.SpinnerNumberModel; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.communications.Utils; -import org.sleuthkit.autopsy.discovery.Bundle; /** * Filter panel for allowing the user to filter on date. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DetailsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DetailsPanel.java index 9b30ef3383..1ec4cd26a1 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DetailsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DetailsPanel.java @@ -40,7 +40,7 @@ import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; import org.sleuthkit.autopsy.discovery.Bundle; -import org.sleuthkit.autopsy.discovery.DiscoveryEventUtils; +import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; import org.sleuthkit.autopsy.modules.hashdatabase.AddContentToHashDbAction; import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction; import org.sleuthkit.datamodel.AbstractFile; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index 977a6fa046..0135ad651c 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.discovery.ui; +import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import static java.awt.BorderLayout.CENTER; import java.awt.Color; import java.beans.PropertyChangeEvent; @@ -36,25 +37,24 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.discovery.AttributeSearchData; -import org.sleuthkit.autopsy.discovery.Bundle; -import org.sleuthkit.autopsy.discovery.DiscoveryEventUtils; -import org.sleuthkit.autopsy.discovery.FileGroup; -import org.sleuthkit.autopsy.discovery.FileGroup.GroupSortingAlgorithm; -import org.sleuthkit.autopsy.discovery.FileSearch; -import static org.sleuthkit.autopsy.discovery.FileGroup.GroupSortingAlgorithm.BY_GROUP_SIZE; -import org.sleuthkit.autopsy.discovery.FileSearch.GroupingAttributeType; -import org.sleuthkit.autopsy.discovery.FileSearchData; -import org.sleuthkit.autopsy.discovery.FileSorter; -import static org.sleuthkit.autopsy.discovery.FileSearch.GroupingAttributeType.PARENT_PATH; -import org.sleuthkit.autopsy.discovery.FileSorter.SortingMethod; -import org.sleuthkit.autopsy.discovery.SearchData; +import org.sleuthkit.autopsy.discovery.search.AttributeSearchData; +import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; +import org.sleuthkit.autopsy.discovery.search.FileGroup; +import org.sleuthkit.autopsy.discovery.search.FileGroup.GroupSortingAlgorithm; +import static org.sleuthkit.autopsy.discovery.search.FileGroup.GroupSortingAlgorithm.BY_GROUP_SIZE; +import org.sleuthkit.autopsy.discovery.search.FileSearch; +import org.sleuthkit.autopsy.discovery.search.FileSearch.GroupingAttributeType; +import static org.sleuthkit.autopsy.discovery.search.FileSearch.GroupingAttributeType.PARENT_PATH; +import org.sleuthkit.autopsy.discovery.search.FileSearchData; +import org.sleuthkit.autopsy.discovery.search.FileSorter; +import org.sleuthkit.autopsy.discovery.search.FileSorter.SortingMethod; +import static org.sleuthkit.autopsy.discovery.search.FileSorter.SortingMethod.BY_FILE_NAME; +import org.sleuthkit.autopsy.discovery.search.SearchData; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.TskCoreException; -import static org.sleuthkit.autopsy.discovery.FileSorter.SortingMethod.BY_FILE_NAME; /** * Dialog for displaying the controls and filters for configuration of a diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.form index 4a1f471190..7917b19a1e 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.form @@ -106,7 +106,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java index 010a086b30..30a6a3a49a 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.discovery.ui; +import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import com.google.common.eventbus.Subscribe; import java.awt.BorderLayout; import java.awt.Color; @@ -36,9 +37,8 @@ import org.openide.windows.RetainLocation; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.coreutils.ThreadConfined; -import org.sleuthkit.autopsy.discovery.Bundle; -import org.sleuthkit.autopsy.discovery.DiscoveryEventUtils; -import org.sleuthkit.autopsy.discovery.SearchData.ResultType; +import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; +import org.sleuthkit.autopsy.discovery.search.SearchData.ResultType; /** * Create a dialog for displaying the Discovery results. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryUiUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryUiUtils.java index 72b0d5db3b..1e27e4e939 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryUiUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryUiUtils.java @@ -18,27 +18,43 @@ */ package org.sleuthkit.autopsy.discovery.ui; +import com.google.common.io.Files; import java.awt.Component; import java.awt.Dimension; +import java.awt.Image; import java.awt.Point; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; +import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.JTextPane; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; +import org.imgscalr.Scalr; +import org.netbeans.api.progress.ProgressHandle; +import org.opencv.core.Mat; +import org.opencv.highgui.VideoCapture; import org.openide.util.ImageUtilities; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.corelibs.ScalrWrapper; +import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.discovery.Bundle; -import org.sleuthkit.autopsy.discovery.ResultFile; +import static org.sleuthkit.autopsy.coreutils.VideoUtils.getVideoFileInTempDir; +import org.sleuthkit.autopsy.datamodel.ContentUtils; +import org.sleuthkit.autopsy.discovery.search.ResultFile; +import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.DataSource; @@ -62,6 +78,9 @@ final class DiscoveryUiUtils { private static final ImageIcon NOTABLE_SCORE_ICON = new ImageIcon(ImageUtilities.loadImage(RED_CIRCLE_ICON_PATH, false)); private static final ImageIcon DELETED_ICON = new ImageIcon(ImageUtilities.loadImage(DELETE_ICON_PATH, false)); private static final ImageIcon UNSUPPORTED_DOCUMENT_THUMBNAIL = new ImageIcon(ImageUtilities.loadImage(UNSUPPORTED_DOC_PATH, false)); + private static final String THUMBNAIL_FORMAT = "png"; //NON-NLS + private static final String VIDEO_THUMBNAIL_DIR = "video-thumbnails"; //NON-NLS + private static final BufferedImage VIDEO_DEFAULT_IMAGE = getDefaultVideoThumbnail(); @NbBundle.Messages({"# {0} - fileSize", "# {1} - units", @@ -166,10 +185,11 @@ final class DiscoveryUiUtils { * false otherwise. * @param isDeletedLabel The label to set the icon and tooltip for. */ + @NbBundle.Messages({"DiscoveryUiUtils.isDeleted.text=All instances of file are deleted."}) static void setDeletedIcon(boolean isDeleted, javax.swing.JLabel isDeletedLabel) { if (isDeleted) { isDeletedLabel.setIcon(DELETED_ICON); - isDeletedLabel.setToolTipText(Bundle.ImageThumbnailPanel_isDeleted_text()); + isDeletedLabel.setToolTipText(Bundle.DiscoveryUiUtils_isDeleted_text()); } else { isDeletedLabel.setIcon(null); isDeletedLabel.setToolTipText(null); @@ -246,6 +266,272 @@ final class DiscoveryUiUtils { dialog.validateDialog(); } + /** + * Get the video thumbnails for a file which exists in a + * VideoThumbnailsWrapper and update the VideoThumbnailsWrapper to include + * them. + * + * @param thumbnailWrapper the object which contains the file to generate + * thumbnails for. + * + */ + @NbBundle.Messages({"# {0} - file name", + "DiscoveryUiUtils.genVideoThumb.progress.text=extracting temporary file {0}"}) + static void getVideoThumbnails(VideoThumbnailsWrapper thumbnailWrapper) { + AbstractFile file = thumbnailWrapper.getResultFile().getFirstInstance(); + String cacheDirectory; + try { + cacheDirectory = Case.getCurrentCaseThrows().getCacheDirectory(); + } catch (NoCurrentCaseException ex) { + cacheDirectory = null; + logger.log(Level.WARNING, "Unable to get cache directory, video thumbnails will not be saved", ex); + } + if (cacheDirectory == null || file.getMd5Hash() == null || !Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash()).toFile().exists()) { + java.io.File tempFile; + try { + tempFile = getVideoFileInTempDir(file); + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Exception while getting open case.", ex); //NON-NLS + int[] framePositions = new int[]{ + 0, + 0, + 0, + 0}; + thumbnailWrapper.setThumbnails(createDefaultThumbnailList(VIDEO_DEFAULT_IMAGE), framePositions); + return; + } + if (tempFile.exists() == false || tempFile.length() < file.getSize()) { + ProgressHandle progress = ProgressHandle.createHandle(Bundle.DiscoveryUiUtils_genVideoThumb_progress_text(file.getName())); + progress.start(100); + try { + Files.createParentDirs(tempFile); + if (Thread.interrupted()) { + int[] framePositions = new int[]{ + 0, + 0, + 0, + 0}; + thumbnailWrapper.setThumbnails(createDefaultThumbnailList(VIDEO_DEFAULT_IMAGE), framePositions); + return; + } + ContentUtils.writeToFile(file, tempFile, progress, null, true); + } catch (IOException ex) { + logger.log(Level.WARNING, "Error extracting temporary file for " + file.getParentPath() + "/" + file.getName(), ex); //NON-NLS + } finally { + progress.finish(); + } + } + VideoCapture videoFile = new VideoCapture(); // will contain the video + BufferedImage bufferedImage = null; + + try { + if (!videoFile.open(tempFile.toString())) { + logger.log(Level.WARNING, "Error opening {0} for preview generation.", file.getParentPath() + "/" + file.getName()); //NON-NLS + int[] framePositions = new int[]{ + 0, + 0, + 0, + 0}; + thumbnailWrapper.setThumbnails(createDefaultThumbnailList(VIDEO_DEFAULT_IMAGE), framePositions); + return; + } + double fps = videoFile.get(5); // gets frame per second + double totalFrames = videoFile.get(7); // gets total frames + if (fps <= 0 || totalFrames <= 0) { + logger.log(Level.WARNING, "Error getting fps or total frames for {0}", file.getParentPath() + "/" + file.getName()); //NON-NLS + int[] framePositions = new int[]{ + 0, + 0, + 0, + 0}; + thumbnailWrapper.setThumbnails(createDefaultThumbnailList(VIDEO_DEFAULT_IMAGE), framePositions); + return; + } + if (Thread.interrupted()) { + int[] framePositions = new int[]{ + 0, + 0, + 0, + 0}; + thumbnailWrapper.setThumbnails(createDefaultThumbnailList(VIDEO_DEFAULT_IMAGE), framePositions); + return; + } + + double duration = 1000 * (totalFrames / fps); //total milliseconds + + int[] framePositions = new int[]{ + (int) (duration * .01), + (int) (duration * .25), + (int) (duration * .5), + (int) (duration * .75),}; + + Mat imageMatrix = new Mat(); + List videoThumbnails = new ArrayList<>(); + if (cacheDirectory == null || file.getMd5Hash() == null) { + cacheDirectory = null; + } else { + try { + FileUtils.forceMkdir(Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash()).toFile()); + } catch (IOException ex) { + cacheDirectory = null; + logger.log(Level.WARNING, "Unable to make video thumbnails directory, thumbnails will not be saved", ex); + } + } + for (int i = 0; i < framePositions.length; i++) { + if (!videoFile.set(0, framePositions[i])) { + logger.log(Level.WARNING, "Error seeking to " + framePositions[i] + "ms in {0}", file.getParentPath() + "/" + file.getName()); //NON-NLS + // If we can't set the time, continue to the next frame position and try again. + + videoThumbnails.add(VIDEO_DEFAULT_IMAGE); + if (cacheDirectory != null) { + try { + ImageIO.write(VIDEO_DEFAULT_IMAGE, THUMBNAIL_FORMAT, + Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash(), i + "-" + framePositions[i] + "." + THUMBNAIL_FORMAT).toFile()); //NON-NLS) + } catch (IOException ex) { + logger.log(Level.WARNING, "Unable to save default video thumbnail for " + file.getMd5Hash() + " at frame position " + framePositions[i], ex); + } + } + continue; + } + // Read the frame into the image/matrix. + if (!videoFile.read(imageMatrix)) { + logger.log(Level.WARNING, "Error reading frame at " + framePositions[i] + "ms from {0}", file.getParentPath() + "/" + file.getName()); //NON-NLS + // If the image is bad for some reason, continue to the next frame position and try again. + videoThumbnails.add(VIDEO_DEFAULT_IMAGE); + if (cacheDirectory != null) { + try { + ImageIO.write(VIDEO_DEFAULT_IMAGE, THUMBNAIL_FORMAT, + Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash(), i + "-" + framePositions[i] + "." + THUMBNAIL_FORMAT).toFile()); //NON-NLS) + } catch (IOException ex) { + logger.log(Level.WARNING, "Unable to save default video thumbnail for " + file.getMd5Hash() + " at frame position " + framePositions[i], ex); + } + } + + continue; + } + // If the image is empty, return since no buffered image can be created. + if (imageMatrix.empty()) { + videoThumbnails.add(VIDEO_DEFAULT_IMAGE); + if (cacheDirectory != null) { + try { + ImageIO.write(VIDEO_DEFAULT_IMAGE, THUMBNAIL_FORMAT, + Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash(), i + "-" + framePositions[i] + "." + THUMBNAIL_FORMAT).toFile()); //NON-NLS) + } catch (IOException ex) { + logger.log(Level.WARNING, "Unable to save default video thumbnail for " + file.getMd5Hash() + " at frame position " + framePositions[i], ex); + } + } + continue; + } + + int matrixColumns = imageMatrix.cols(); + int matrixRows = imageMatrix.rows(); + + // Convert the matrix that contains the frame to a buffered image. + if (bufferedImage == null) { + bufferedImage = new BufferedImage(matrixColumns, matrixRows, BufferedImage.TYPE_3BYTE_BGR); + } + + byte[] data = new byte[matrixRows * matrixColumns * (int) (imageMatrix.elemSize())]; + imageMatrix.get(0, 0, data); //copy the image to data + + if (imageMatrix.channels() == 3) { + for (int k = 0; k < data.length; k += 3) { + byte temp = data[k]; + data[k] = data[k + 2]; + data[k + 2] = temp; + } + } + + bufferedImage.getRaster().setDataElements(0, 0, matrixColumns, matrixRows, data); + if (Thread.interrupted()) { + thumbnailWrapper.setThumbnails(videoThumbnails, framePositions); + try { + FileUtils.forceDelete(Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash()).toFile()); + } catch (IOException ex) { + logger.log(Level.WARNING, "Unable to delete directory for cancelled video thumbnail process", ex); + } + return; + } + BufferedImage thumbnail = ScalrWrapper.resize(bufferedImage, Scalr.Method.SPEED, Scalr.Mode.FIT_TO_HEIGHT, ImageUtils.ICON_SIZE_LARGE, ImageUtils.ICON_SIZE_MEDIUM, Scalr.OP_ANTIALIAS); + //We are height limited here so it can be wider than it can be tall.Scalr maintains the aspect ratio. + videoThumbnails.add(thumbnail); + if (cacheDirectory != null) { + try { + ImageIO.write(thumbnail, THUMBNAIL_FORMAT, + Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash(), i + "-" + framePositions[i] + "." + THUMBNAIL_FORMAT).toFile()); //NON-NLS) + } catch (IOException ex) { + logger.log(Level.WARNING, "Unable to save video thumbnail for " + file.getMd5Hash() + " at frame position " + framePositions[i], ex); + } + } + } + thumbnailWrapper.setThumbnails(videoThumbnails, framePositions); + } finally { + videoFile.release(); // close the file} + } + } else { + loadSavedThumbnails(cacheDirectory, thumbnailWrapper, VIDEO_DEFAULT_IMAGE); + } + } + + /** + * Get the default image to display when a thumbnail is not available. + * + * @return The default video thumbnail. + */ + private static BufferedImage getDefaultVideoThumbnail() { + try { + return ImageIO.read(ImageUtils.class + .getResourceAsStream("/org/sleuthkit/autopsy/images/failedToCreateVideoThumb.png"));//NON-NLS + } catch (IOException ex) { + logger.log(Level.SEVERE, "Failed to load 'failed to create video' placeholder.", ex); //NON-NLS + } + return null; + } + + /** + * Load the thumbnails that exist in the cache directory for the specified + * video file. + * + * @param cacheDirectory The directory which exists for the video + * thumbnails. + * @param thumbnailWrapper The VideoThumbnailWrapper object which contains + * information about the file and the thumbnails + * associated with it. + */ + private static void loadSavedThumbnails(String cacheDirectory, VideoThumbnailsWrapper thumbnailWrapper, BufferedImage failedVideoThumbImage) { + int[] framePositions = new int[4]; + List videoThumbnails = new ArrayList<>(); + int thumbnailNumber = 0; + String md5 = thumbnailWrapper.getResultFile().getFirstInstance().getMd5Hash(); + for (String fileName : Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, md5).toFile().list()) { + try { + videoThumbnails.add(ImageIO.read(Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, md5, fileName).toFile())); + } catch (IOException ex) { + videoThumbnails.add(failedVideoThumbImage); + logger.log(Level.WARNING, "Unable to read saved video thumbnail " + fileName + " for " + md5, ex); + } + int framePos = Integer.valueOf(FilenameUtils.getBaseName(fileName).substring(2)); + framePositions[thumbnailNumber] = framePos; + thumbnailNumber++; + } + thumbnailWrapper.setThumbnails(videoThumbnails, framePositions); + } + + /** + * Private helper method for creating video thumbnails, for use when no + * thumbnails are created. + * + * @return List containing the default thumbnail. + */ + private static List createDefaultThumbnailList(BufferedImage failedVideoThumbImage) { + List videoThumbnails = new ArrayList<>(); + videoThumbnails.add(failedVideoThumbImage); + videoThumbnails.add(failedVideoThumbImage); + videoThumbnails.add(failedVideoThumbImage); + videoThumbnails.add(failedVideoThumbImage); + return videoThumbnails; + } + /** * Private constructor for DiscoveryUiUtils utility class. */ diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentFilterPanel.java index 29e29972bd..9c2e5565a1 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentFilterPanel.java @@ -19,9 +19,9 @@ package org.sleuthkit.autopsy.discovery.ui; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; -import org.sleuthkit.autopsy.discovery.AttributeSearchData; -import org.sleuthkit.autopsy.discovery.FileSearchData; -import org.sleuthkit.autopsy.discovery.SearchData; +import org.sleuthkit.autopsy.discovery.search.AttributeSearchData; +import org.sleuthkit.autopsy.discovery.search.FileSearchData; +import org.sleuthkit.autopsy.discovery.search.SearchData; /** * Class which displays all filters available for the Documents search type. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentPanel.java index 78d88e9cb7..68c15ce260 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentPanel.java @@ -29,8 +29,7 @@ import javax.swing.JList; import javax.swing.ListCellRenderer; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.corecomponents.AutoWrappingJTextPane; -import org.sleuthkit.autopsy.discovery.Bundle; -import org.sleuthkit.autopsy.discovery.FileSearchData; +import org.sleuthkit.autopsy.discovery.search.FileSearchData; /** * Class which displays a preview and details about a document. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentWrapper.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentWrapper.java index fb93cc9bd1..1ea0df4ba4 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentWrapper.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentWrapper.java @@ -19,8 +19,7 @@ package org.sleuthkit.autopsy.discovery.ui; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.discovery.Bundle; -import org.sleuthkit.autopsy.discovery.ResultFile; +import org.sleuthkit.autopsy.discovery.search.ResultFile; import org.sleuthkit.autopsy.textsummarizer.TextSummary; /** diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java index 05e0907935..086a249305 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java @@ -19,9 +19,9 @@ package org.sleuthkit.autopsy.discovery.ui; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; -import org.sleuthkit.autopsy.discovery.AttributeSearchData; -import org.sleuthkit.autopsy.discovery.FileSearchData; -import org.sleuthkit.autopsy.discovery.SearchData; +import org.sleuthkit.autopsy.discovery.search.AttributeSearchData; +import org.sleuthkit.autopsy.discovery.search.FileSearchData; +import org.sleuthkit.autopsy.discovery.search.SearchData; /** * Filter panel for searching domain attributes with Discovery. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java index 46de95137c..dad5c1e819 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.discovery.ui; +import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import com.google.common.eventbus.Subscribe; import java.awt.Cursor; import java.util.List; @@ -28,13 +29,12 @@ import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.discovery.Bundle; -import org.sleuthkit.autopsy.discovery.DiscoveryEventUtils; -import org.sleuthkit.autopsy.discovery.FileGroup; -import org.sleuthkit.autopsy.discovery.FileSearch; -import org.sleuthkit.autopsy.discovery.FileSearch.GroupKey; -import org.sleuthkit.autopsy.discovery.FileSearchData.FileType; -import org.sleuthkit.autopsy.discovery.FileSorter; +import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; +import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; +import org.sleuthkit.autopsy.discovery.search.FileGroup; +import org.sleuthkit.autopsy.discovery.search.FileSearch; +import org.sleuthkit.autopsy.discovery.search.FileSearchData.FileType; +import org.sleuthkit.autopsy.discovery.search.FileSorter; /** * Panel to display the list of groups which are provided by a search. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/HashSetFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/HashSetFilterPanel.java index 1703737c1c..a890edcd4e 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/HashSetFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/HashSetFilterPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.discovery.ui; +import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import java.util.List; import java.util.logging.Level; import javax.swing.DefaultListModel; @@ -25,7 +26,7 @@ import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.discovery.SearchFiltering; +import org.sleuthkit.autopsy.discovery.search.SearchFiltering; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.TskCoreException; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageFilterPanel.java index 8008b9a41f..be0419bbd8 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageFilterPanel.java @@ -19,9 +19,9 @@ package org.sleuthkit.autopsy.discovery.ui; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; -import org.sleuthkit.autopsy.discovery.AttributeSearchData; -import org.sleuthkit.autopsy.discovery.FileSearchData; -import org.sleuthkit.autopsy.discovery.SearchData; +import org.sleuthkit.autopsy.discovery.search.AttributeSearchData; +import org.sleuthkit.autopsy.discovery.search.FileSearchData; +import org.sleuthkit.autopsy.discovery.search.SearchData; /** * Panel for displaying all the filters associated with the Image type. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageThumbnailPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageThumbnailPanel.java index 88c2eb9526..d294fa866d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageThumbnailPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageThumbnailPanel.java @@ -28,7 +28,6 @@ import javax.swing.JComponent; import javax.swing.JList; import javax.swing.ListCellRenderer; import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.discovery.Bundle; /** * Class which displays a thumbnail and information for an image file. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageThumbnailWrapper.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageThumbnailWrapper.java index 2dc072b175..67b7e2dab0 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageThumbnailWrapper.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageThumbnailWrapper.java @@ -20,7 +20,7 @@ package org.sleuthkit.autopsy.discovery.ui; import java.awt.Image; import org.sleuthkit.autopsy.coreutils.ImageUtils; -import org.sleuthkit.autopsy.discovery.ResultFile; +import org.sleuthkit.autopsy.discovery.search.ResultFile; /** * Class to wrap all the information necessary for an image thumbnail to be diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/InterestingItemsFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/InterestingItemsFilterPanel.java index 1106391d9b..0d102141f0 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/InterestingItemsFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/InterestingItemsFilterPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.discovery.ui; +import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import java.util.List; import java.util.logging.Level; import javax.swing.DefaultListModel; @@ -25,7 +26,7 @@ import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.discovery.SearchFiltering; +import org.sleuthkit.autopsy.discovery.search.SearchFiltering; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.TskCoreException; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ObjectDetectedFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ObjectDetectedFilterPanel.java index 4dacc11d55..09cc912e69 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ObjectDetectedFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ObjectDetectedFilterPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.discovery.ui; +import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import java.util.List; import java.util.logging.Level; import javax.swing.DefaultListModel; @@ -25,7 +26,7 @@ import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.discovery.SearchFiltering; +import org.sleuthkit.autopsy.discovery.search.SearchFiltering; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.TskCoreException; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/OpenDiscoveryAction.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/OpenDiscoveryAction.java index d1982ab364..74fb716425 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/OpenDiscoveryAction.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/OpenDiscoveryAction.java @@ -31,7 +31,6 @@ import org.openide.util.NbBundle; import org.openide.util.actions.CallableSystemAction; import org.openide.util.actions.Presenter; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.discovery.Bundle; /** * Class to open the Discovery dialog. Allows the user to run searches and see diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java index f9c5415294..2372f01788 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java @@ -18,21 +18,22 @@ */ package org.sleuthkit.autopsy.discovery.ui; +import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import java.util.List; import java.util.ArrayList; import java.util.logging.Level; import javax.swing.SwingWorker; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.discovery.FileSearch.GroupKey; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; -import org.sleuthkit.autopsy.discovery.DiscoveryEventUtils; -import org.sleuthkit.autopsy.discovery.FileGroup; -import org.sleuthkit.autopsy.discovery.FileSearch; -import org.sleuthkit.autopsy.discovery.FileSearchData; -import org.sleuthkit.autopsy.discovery.FileSearchException; -import org.sleuthkit.autopsy.discovery.FileSorter; -import org.sleuthkit.autopsy.discovery.ResultFile; +import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; +import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; +import org.sleuthkit.autopsy.discovery.search.FileGroup; +import org.sleuthkit.autopsy.discovery.search.FileSearch; +import org.sleuthkit.autopsy.discovery.search.FileSearchData; +import org.sleuthkit.autopsy.discovery.search.FileSearchException; +import org.sleuthkit.autopsy.discovery.search.FileSorter; +import org.sleuthkit.autopsy.discovery.search.ResultFile; /** * SwingWorker to retrieve the contents of a page. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ParentFolderFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ParentFolderFilterPanel.java index 841dd910bc..97015abc92 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ParentFolderFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ParentFolderFilterPanel.java @@ -18,14 +18,15 @@ */ package org.sleuthkit.autopsy.discovery.ui; +import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import java.util.ArrayList; import java.util.List; import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; -import org.sleuthkit.autopsy.discovery.SearchFiltering; -import org.sleuthkit.autopsy.discovery.SearchFiltering.ParentSearchTerm; +import org.sleuthkit.autopsy.discovery.search.SearchFiltering; +import org.sleuthkit.autopsy.discovery.search.SearchFiltering.ParentSearchTerm; /** * Panel to allow configuration of the Parent Folder filter. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java index 20fead3473..53a2c48407 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java @@ -23,10 +23,6 @@ import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; -import org.sleuthkit.autopsy.discovery.FileSearchData; -import org.sleuthkit.autopsy.discovery.FileSearchData.Frequency; -import org.sleuthkit.autopsy.discovery.SearchData.ResultType; -import org.sleuthkit.autopsy.discovery.SearchFiltering; /** * Panel to allow configuration of the Past Occurrences filter. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java index e2686c58eb..9cd9cbd78a 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.discovery.ui; +import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import com.google.common.eventbus.Subscribe; import java.awt.Cursor; import java.awt.Image; @@ -35,16 +36,15 @@ import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.discovery.FileSearch.GroupKey; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; -import org.sleuthkit.autopsy.discovery.Bundle; -import org.sleuthkit.autopsy.discovery.DiscoveryEventUtils; -import org.sleuthkit.autopsy.discovery.FileGroup; -import org.sleuthkit.autopsy.discovery.FileSearch; -import org.sleuthkit.autopsy.discovery.FileSearchData; -import org.sleuthkit.autopsy.discovery.FileSorter; -import org.sleuthkit.autopsy.discovery.ResultFile; +import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; +import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; +import org.sleuthkit.autopsy.discovery.search.FileGroup; +import org.sleuthkit.autopsy.discovery.search.FileSearch; +import org.sleuthkit.autopsy.discovery.search.FileSearchData; +import org.sleuthkit.autopsy.discovery.search.FileSorter; +import org.sleuthkit.autopsy.discovery.search.ResultFile; import org.sleuthkit.autopsy.textsummarizer.TextSummary; /** @@ -653,7 +653,7 @@ final class ResultsPanel extends javax.swing.JPanel { @Override protected Void doInBackground() throws Exception { - FileSearch.getVideoThumbnails(thumbnailWrapper); + DiscoveryUiUtils.getVideoThumbnails(thumbnailWrapper); return null; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.java index 6243416325..251ed4cb94 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.java @@ -19,7 +19,7 @@ package org.sleuthkit.autopsy.discovery.ui; import java.awt.Cursor; -import org.sleuthkit.autopsy.discovery.DiscoveryEventUtils; +import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; /** * Panel for separating the results list from the details area. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java index ea14294d95..0013d610dd 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.discovery.ui; +import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import java.util.LinkedHashMap; import javax.swing.SwingWorker; import java.util.List; @@ -25,13 +26,13 @@ import java.util.Map; import java.util.logging.Level; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.discovery.FileSearch.GroupKey; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; -import org.sleuthkit.autopsy.discovery.DiscoveryEventUtils; -import org.sleuthkit.autopsy.discovery.FileGroup; -import org.sleuthkit.autopsy.discovery.FileSearch; -import org.sleuthkit.autopsy.discovery.FileSearchException; -import org.sleuthkit.autopsy.discovery.FileSorter; +import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; +import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; +import org.sleuthkit.autopsy.discovery.search.FileGroup; +import org.sleuthkit.autopsy.discovery.search.FileSearch; +import org.sleuthkit.autopsy.discovery.search.FileSearchException; +import org.sleuthkit.autopsy.discovery.search.FileSorter; /** * SwingWorker to perform search on a background thread. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/SizeFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/SizeFilterPanel.java index 8ca29f0018..65c5330da5 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/SizeFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/SizeFilterPanel.java @@ -18,15 +18,16 @@ */ package org.sleuthkit.autopsy.discovery.ui; +import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import java.util.ArrayList; import java.util.List; import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; -import org.sleuthkit.autopsy.discovery.FileSearchData; -import org.sleuthkit.autopsy.discovery.FileSearchData.FileSize; -import org.sleuthkit.autopsy.discovery.SearchFiltering; +import org.sleuthkit.autopsy.discovery.search.FileSearchData; +import org.sleuthkit.autopsy.discovery.search.FileSearchData.FileSize; +import org.sleuthkit.autopsy.discovery.search.SearchFiltering; /** * Panel to allow configuration of the Size Filter. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/UserCreatedFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/UserCreatedFilterPanel.java index 5d421a0b0d..d65596633a 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/UserCreatedFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/UserCreatedFilterPanel.java @@ -18,10 +18,11 @@ */ package org.sleuthkit.autopsy.discovery.ui; +import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; -import org.sleuthkit.autopsy.discovery.SearchFiltering; +import org.sleuthkit.autopsy.discovery.search.SearchFiltering; /** * Panel to allow configuration of the User Created Filter. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoFilterPanel.java index d1388a45ba..c002fe322f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoFilterPanel.java @@ -19,9 +19,9 @@ package org.sleuthkit.autopsy.discovery.ui; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; -import org.sleuthkit.autopsy.discovery.AttributeSearchData; -import org.sleuthkit.autopsy.discovery.FileSearchData; -import org.sleuthkit.autopsy.discovery.SearchData; +import org.sleuthkit.autopsy.discovery.search.AttributeSearchData; +import org.sleuthkit.autopsy.discovery.search.FileSearchData; +import org.sleuthkit.autopsy.discovery.search.SearchData; /** * Panel for displaying all filters available for the searches of type Video. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailPanel.java index 609904ee2a..7a62937582 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailPanel.java @@ -32,7 +32,6 @@ import javax.swing.JLabel; import javax.swing.JList; import javax.swing.ListCellRenderer; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.discovery.Bundle; /** * Class which displays thumbnails and information for a video file. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailsWrapper.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailsWrapper.java index 429b26d926..6b312bab36 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailsWrapper.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoThumbnailsWrapper.java @@ -22,7 +22,7 @@ import java.awt.Image; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.sleuthkit.autopsy.discovery.ResultFile; +import org.sleuthkit.autopsy.discovery.search.ResultFile; /** * Class to wrap all the information necessary for video thumbnails to be From 1b25df8973a6867552f39a333da6c17cceeafef7 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 17 Aug 2020 13:43:30 -0400 Subject: [PATCH 012/130] 6610 update casemodule import for discovery --- Core/src/org/sleuthkit/autopsy/casemodule/Case.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 8ada5fa596..275e502b8c 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -107,7 +107,7 @@ import org.sleuthkit.autopsy.coreutils.Version; import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.autopsy.events.AutopsyEventException; import org.sleuthkit.autopsy.events.AutopsyEventPublisher; -import org.sleuthkit.autopsy.discovery.OpenDiscoveryAction; +import org.sleuthkit.autopsy.discovery.ui.OpenDiscoveryAction; import org.sleuthkit.autopsy.ingest.IngestJob; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestServices; From 991de39fbfdca1bb48197c3cee536367409c1736 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 17 Aug 2020 13:50:12 -0400 Subject: [PATCH 013/130] 6610 fix imports and typo --- .../autopsy/discovery/ui/ArtifactTypeFilterPanel.java | 2 +- Core/src/org/sleuthkit/autopsy/discovery/ui/DetailsPanel.java | 1 - .../autopsy/discovery/ui/PastOccurrencesFilterPanel.java | 4 ++++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java index 4430d793ab..9771c8ab81 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java @@ -27,7 +27,7 @@ import org.sleuthkit.autopsy.discovery.search.AttributeSearchData; import org.sleuthkit.datamodel.BlackboardArtifact; /** - * Filter for selection of a specific Arrtifact type to limit results to. + * Filter for selection of a specific Artifact type to limit results to. */ class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DetailsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DetailsPanel.java index 1ec4cd26a1..e302669278 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DetailsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DetailsPanel.java @@ -39,7 +39,6 @@ import org.sleuthkit.autopsy.corecomponents.TableFilterNode; import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; -import org.sleuthkit.autopsy.discovery.Bundle; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; import org.sleuthkit.autopsy.modules.hashdatabase.AddContentToHashDbAction; import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java index 53a2c48407..20fead3473 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java @@ -23,6 +23,10 @@ import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.discovery.FileSearchData; +import org.sleuthkit.autopsy.discovery.FileSearchData.Frequency; +import org.sleuthkit.autopsy.discovery.SearchData.ResultType; +import org.sleuthkit.autopsy.discovery.SearchFiltering; /** * Panel to allow configuration of the Past Occurrences filter. From 8b6fef749733752457cc2b60412aa05a4b8448e6 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 17 Aug 2020 14:15:12 -0400 Subject: [PATCH 014/130] 6610 move additional group keys out of filesearch class --- .../discovery/search/Bundle.properties-MERGED | 115 +++ .../discovery/search/DiscoveryKeyUtils.java | 683 +++++++++++++++++- .../autopsy/discovery/search/FileSearch.java | 635 +--------------- .../discovery/ui/Bundle.properties-MERGED | 265 ++----- .../ui/PastOccurrencesFilterPanel.java | 9 +- 5 files changed, 823 insertions(+), 884 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED new file mode 100644 index 0000000000..9924fbae02 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED @@ -0,0 +1,115 @@ +AttributeSearchData.AttributeType.Domain.displayName=Domain +AttributeSearchData.AttributeType.Other.displayName=Other +DiscoveryKeyUtils.FileTagGroupKey.noSets=None +DiscoveryKeyUtils.NoGroupingGroupKey.allFiles=All Files +FileGroup.groupSortingAlgorithm.groupName.text=Group Name +FileGroup.groupSortingAlgorithm.groupSize.text=Group Size +# {0} - Data source name +# {1} - Data source ID +FileSearch.DataSourceGroupKey.datasourceAndID={0}(ID: {1}) +# {0} - Data source ID +FileSearch.DataSourceGroupKey.idOnly=Data source (ID: {0}) +FileSearch.documentSummary.noBytes=No bytes read for document, unable to display preview. +FileSearch.documentSummary.noPreview=No preview available. +FileSearch.GroupingAttributeType.datasource.displayName=Data Source +FileSearch.GroupingAttributeType.fileType.displayName=File Type +FileSearch.GroupingAttributeType.frequency.displayName=Past Occurrences +FileSearch.GroupingAttributeType.hash.displayName=Hash Set +FileSearch.GroupingAttributeType.interestingItem.displayName=Interesting Item +FileSearch.GroupingAttributeType.keywordList.displayName=Keyword +FileSearch.GroupingAttributeType.none.displayName=None +FileSearch.GroupingAttributeType.object.displayName=Object Detected +FileSearch.GroupingAttributeType.parent.displayName=Parent Folder +FileSearch.GroupingAttributeType.size.displayName=File Size +FileSearch.GroupingAttributeType.tag.displayName=Tag +FileSearch.HashHitsGroupKey.noHashHits=None +FileSearch.InterestingItemGroupKey.noSets=None +FileSearch.KeywordListGroupKey.noKeywords=None +FileSearch.ObjectDetectedGroupKey.noSets=None +FileSearchData.FileSize.100kbto1mb=: 100KB-1MB +FileSearchData.FileSize.100mbto1gb=: 100MB-1GB +FileSearchData.FileSize.10PlusGb=: 10GB+ +FileSearchData.FileSize.16kbto100kb=: 16-100KB +FileSearchData.FileSize.1gbto5gb=: 1-5GB +FileSearchData.FileSize.1mbto50mb=: 1-50MB +FileSearchData.FileSize.200PlusMb=: 200MB+ +FileSearchData.FileSize.500kbto100mb=: 500KB-100MB +FileSearchData.FileSize.50mbto200mb=: 50-200MB +FileSearchData.FileSize.5gbto10gb=: 5-10GB +FileSearchData.FileSize.LARGE.displayName=Large +FileSearchData.FileSize.MEDIUM.displayName=Medium +FileSearchData.FileSize.SMALL.displayName=Small +FileSearchData.FileSize.upTo16kb=: 0-16KB +FileSearchData.FileSize.upTo500kb=: 0-500KB +FileSearchData.FileSize.XLARGE.displayName=XLarge +FileSearchData.FileSize.XSMALL.displayName=XSmall +FileSearchData.FileSize.XXLARGE.displayName=XXLarge +FileSearchData.FileType.Audio.displayName=Audio +FileSearchData.FileType.Documents.displayName=Documents +FileSearchData.FileType.Executables.displayName=Executables +FileSearchData.FileType.Image.displayName=Image +FileSearchData.FileType.Other.displayName=Other/Unknown +FileSearchData.FileType.Video.displayName=Video +FileSearchData.Frequency.common.displayName=Common (11 - 100) +FileSearchData.Frequency.known.displayName=Known (NSRL) +FileSearchData.Frequency.rare.displayName=Rare (2-10) +FileSearchData.Frequency.unique.displayName=Unique (1) +FileSearchData.Frequency.unknown.displayName=Unknown +FileSearchData.Frequency.verycommon.displayName=Very Common (100+) +FileSearchData.Score.interesting.displayName=Interesting +FileSearchData.Score.notable.displayName=Notable +FileSearchData.Score.unknown.displayName=Unknown +FileSearchFiltering.concatenateSetNamesForDisplay.comma=, +# {0} - filters +FileSearchFiltering.HashSetFilter.desc=Hash set hits in set(s): {0} +FileSearchFiltering.KnownFilter.desc=which are not known +FileSearchFiltering.PreviouslyNotableFilter.desc=that were previously marked as notable +# {0} - tag names +FileSearchFiltering.TagsFilter.desc=Tagged {0} +FileSearchFiltering.TagsFilter.or=, +FileSearchFiltering.UserCreatedFilter.desc=that contain EXIF data +FileSorter.SortingMethod.datasource.displayName=Data Source +FileSorter.SortingMethod.filename.displayName=File Name +FileSorter.SortingMethod.filesize.displayName=File Size +FileSorter.SortingMethod.filetype.displayName=File Type +FileSorter.SortingMethod.frequency.displayName=Central Repo Frequency +FileSorter.SortingMethod.fullPath.displayName=Full Path +FileSorter.SortingMethod.keywordlist.displayName=Keyword List Names +ResultFile.score.interestingResult.description=At least one instance of the file has an interesting result associated with it. +ResultFile.score.notableFile.description=At least one instance of the file was recognized as notable. +ResultFile.score.notableTaggedFile.description=At least one instance of the file is tagged with a notable tag. +ResultFile.score.taggedFile.description=At least one instance of the file has been tagged. +# {0} - Data source name +# {1} - Data source ID +SearchFiltering.DataSourceFilter.datasource={0}({1}) +# {0} - filters +SearchFiltering.DataSourceFilter.desc=Data source(s): {0} +SearchFiltering.DataSourceFilter.or=, +# {0} - filters +SearchFiltering.FileTypeFilter.desc=Type: {0} +SearchFiltering.FileTypeFilter.or=, +# {0} - filters +SearchFiltering.FrequencyFilter.desc=Past occurrences: {0} +SearchFiltering.FrequencyFilter.or=, +# {0} - filters +SearchFiltering.InterestingItemSetFilter.desc=Interesting item hits in set(s): {0} +# {0} - filters +SearchFiltering.KeywordListFilter.desc=Keywords in list(s): {0} +# {0} - filters +SearchFiltering.ObjectDetectionFilter.desc=Objects detected in set(s): {0} +# {0} - filters +SearchFiltering.ParentFilter.desc=Paths matching: {0} +SearchFiltering.ParentFilter.exact=(exact match) +SearchFiltering.ParentFilter.excluded=(excluded) +SearchFiltering.ParentFilter.included=(included) +SearchFiltering.ParentFilter.or=, +SearchFiltering.ParentFilter.substring=(substring) +SearchFiltering.ParentSearchTerm.excludeString=\ (exclude) +SearchFiltering.ParentSearchTerm.fullString=\ (exact) +SearchFiltering.ParentSearchTerm.includeString=\ (include) +SearchFiltering.ParentSearchTerm.subString=\ (substring) +# {0} - filters +SearchFiltering.ScoreFilter.desc=Score(s) of : {0} +# {0} - filters +SearchFiltering.SizeFilter.desc=Size(s): {0} +SearchFiltering.SizeFilter.or=, diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java index d009ef0133..118dd6e815 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java @@ -21,13 +21,83 @@ package org.sleuthkit.autopsy.discovery.search; import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.logging.Level; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.TskCoreException; /** * Utility class for constructing keys for groups and searches. */ public class DiscoveryKeyUtils { + private final static Logger logger = Logger.getLogger(DiscoveryKeyUtils.class.getName()); + + /** + * Represents a key for a specific search for a specific user. + */ + static class SearchKey implements Comparable { + + private final String keyString; + + /** + * Construct a new SearchKey with all information that defines a search. + * + * @param userName The name of the user performing the search. + * @param filters The FileFilters being used for the search. + * @param groupAttributeType The AttributeType to group by. + * @param groupSortingType The algorithm to sort the groups by. + * @param fileSortingMethod The method to sort the files by. + */ + SearchKey(String userName, List filters, + FileSearch.AttributeType groupAttributeType, + FileGroup.GroupSortingAlgorithm groupSortingType, + FileSorter.SortingMethod fileSortingMethod) { + StringBuilder searchStringBuilder = new StringBuilder(); + searchStringBuilder.append(userName); + for (AbstractFilter filter : filters) { + searchStringBuilder.append(filter.toString()); + } + searchStringBuilder.append(groupAttributeType).append(groupSortingType).append(fileSortingMethod); + keyString = searchStringBuilder.toString(); + } + + @Override + public int compareTo(SearchKey otherSearchKey) { + return getKeyString().compareTo(otherSearchKey.getKeyString()); + } + + @Override + public boolean equals(Object otherKey) { + if (otherKey == this) { + return true; + } + + if (!(otherKey instanceof SearchKey)) { + return false; + } + + SearchKey otherSearchKey = (SearchKey) otherKey; + return getKeyString().equals(otherSearchKey.getKeyString()); + } + + @Override + public int hashCode() { + int hash = 5; + hash = 79 * hash + Objects.hashCode(getKeyString()); + return hash; + } + + /** + * @return the keyString + */ + String getKeyString() { + return keyString; + } + } + /** * The key used for grouping for each attribute type. */ @@ -78,7 +148,7 @@ public class DiscoveryKeyUtils { } } - /** + /** * Key representing a file size group */ static class FileSizeGroupKey extends GroupKey { @@ -134,7 +204,141 @@ public class DiscoveryKeyUtils { return fileSize; } } - + + /** + * Key representing a file type group + */ + static class FileTypeGroupKey extends GroupKey { + + private final FileSearchData.FileType fileType; + + FileTypeGroupKey(ResultFile file) { + fileType = file.getFileType(); + } + + @Override + String getDisplayName() { + return getFileType().toString(); + } + + @Override + public int compareTo(GroupKey otherGroupKey) { + if (otherGroupKey instanceof FileTypeGroupKey) { + FileTypeGroupKey otherFileTypeGroupKey = (FileTypeGroupKey) otherGroupKey; + return Integer.compare(getFileType().getRanking(), otherFileTypeGroupKey.getFileType().getRanking()); + } else { + return compareClassNames(otherGroupKey); + } + } + + @Override + public boolean equals(Object otherKey) { + if (otherKey == this) { + return true; + } + + if (!(otherKey instanceof FileTypeGroupKey)) { + return false; + } + + FileTypeGroupKey otherFileTypeGroupKey = (FileTypeGroupKey) otherKey; + return getFileType().equals(otherFileTypeGroupKey.getFileType()); + } + + @Override + public int hashCode() { + return Objects.hash(getFileType().getRanking()); + } + + /** + * @return the fileType + */ + FileSearchData.FileType getFileType() { + return fileType; + } + } + + /** + * Key representing a keyword list group + */ + static class KeywordListGroupKey extends GroupKey { + + private final List keywordListNames; + private final String keywordListNamesString; + + @NbBundle.Messages({ + "FileSearch.KeywordListGroupKey.noKeywords=None"}) + KeywordListGroupKey(ResultFile file) { + keywordListNames = file.getKeywordListNames(); + + if (keywordListNames.isEmpty()) { + keywordListNamesString = Bundle.FileSearch_KeywordListGroupKey_noKeywords(); + } else { + keywordListNamesString = String.join(",", keywordListNames); // NON-NLS + } + } + + @Override + String getDisplayName() { + return getKeywordListNamesString(); + } + + @Override + public int compareTo(GroupKey otherGroupKey) { + if (otherGroupKey instanceof KeywordListGroupKey) { + KeywordListGroupKey otherKeywordListNamesGroupKey = (KeywordListGroupKey) otherGroupKey; + + // Put the empty list at the end + if (getKeywordListNames().isEmpty()) { + if (otherKeywordListNamesGroupKey.getKeywordListNames().isEmpty()) { + return 0; + } else { + return 1; + } + } else if (otherKeywordListNamesGroupKey.getKeywordListNames().isEmpty()) { + return -1; + } + + return getKeywordListNamesString().compareTo(otherKeywordListNamesGroupKey.getKeywordListNamesString()); + } else { + return compareClassNames(otherGroupKey); + } + } + + @Override + public boolean equals(Object otherKey) { + if (otherKey == this) { + return true; + } + + if (!(otherKey instanceof KeywordListGroupKey)) { + return false; + } + + KeywordListGroupKey otherKeywordListGroupKey = (KeywordListGroupKey) otherKey; + return getKeywordListNamesString().equals(otherKeywordListGroupKey.getKeywordListNamesString()); + } + + @Override + public int hashCode() { + return Objects.hash(getKeywordListNamesString()); + } + + /** + * @return the keywordListNames + */ + List getKeywordListNames() { + return Collections.unmodifiableList(keywordListNames); + } + + /** + * @return the keywordListNamesString + */ + String getKeywordListNamesString() { + return keywordListNamesString; + } + } + /** * Key representing a file tag group */ @@ -217,13 +421,179 @@ public class DiscoveryKeyUtils { } /** - * Default attribute used to make one group + * Key representing a parent path group */ - static class NoGroupingAttribute extends FileSearch.AttributeType { + static class ParentPathGroupKey extends GroupKey { + + private String parentPath; + private Long parentID; + + ParentPathGroupKey(ResultFile file) { + Content parent; + try { + parent = file.getFirstInstance().getParent(); + } catch (TskCoreException ignored) { + parent = null; + } + //Find the directory this file is in if it is an embedded file + while (parent != null && parent instanceof AbstractFile && ((AbstractFile) parent).isFile()) { + try { + parent = parent.getParent(); + } catch (TskCoreException ignored) { + parent = null; + } + } + setParentPathAndID(parent, file); + } + + /** + * Helper method to set the parent path and parent ID. + * + * @param parent The parent content object. + * @param file The ResultFile object. + */ + private void setParentPathAndID(Content parent, ResultFile file) { + if (parent != null) { + try { + parentPath = parent.getUniquePath(); + parentID = parent.getId(); + } catch (TskCoreException ignored) { + //catch block left blank purposefully next if statement will handle case when exception takes place as well as when parent is null + } + + } + if (parentPath == null) { + if (file.getFirstInstance().getParentPath() != null) { + parentPath = file.getFirstInstance().getParentPath(); + } else { + parentPath = ""; // NON-NLS + } + parentID = -1L; + } + } @Override - public GroupKey getGroupKey(ResultFile file) { - return new NoGroupingGroupKey(); + String getDisplayName() { + return getParentPath(); + } + + @Override + public int compareTo(GroupKey otherGroupKey) { + if (otherGroupKey instanceof ParentPathGroupKey) { + ParentPathGroupKey otherParentPathGroupKey = (ParentPathGroupKey) otherGroupKey; + int comparisonResult = getParentPath().compareTo(otherParentPathGroupKey.getParentPath()); + if (comparisonResult == 0) { + comparisonResult = getParentID().compareTo(otherParentPathGroupKey.getParentID()); + } + return comparisonResult; + } else { + return compareClassNames(otherGroupKey); + } + } + + @Override + public boolean equals(Object otherKey) { + if (otherKey == this) { + return true; + } + + if (!(otherKey instanceof ParentPathGroupKey)) { + return false; + } + + ParentPathGroupKey otherParentPathGroupKey = (ParentPathGroupKey) otherKey; + return getParentPath().equals(otherParentPathGroupKey.getParentPath()) && getParentID().equals(otherParentPathGroupKey.getParentID()); + } + + @Override + public int hashCode() { + int hashCode = 11; + hashCode = 61 * hashCode + Objects.hash(getParentPath()); + hashCode = 61 * hashCode + Objects.hash(getParentID()); + return hashCode; + } + + /** + * @return the parentPath + */ + String getParentPath() { + return parentPath; + } + + /** + * @return the parentID + */ + Long getParentID() { + return parentID; + } + } + + /** + * Key representing a data source group + */ + static class DataSourceGroupKey extends GroupKey { + + private final long dataSourceID; + private String displayName; + + @NbBundle.Messages({ + "# {0} - Data source name", + "# {1} - Data source ID", + "FileSearch.DataSourceGroupKey.datasourceAndID={0}(ID: {1})", + "# {0} - Data source ID", + "FileSearch.DataSourceGroupKey.idOnly=Data source (ID: {0})"}) + DataSourceGroupKey(ResultFile file) { + dataSourceID = file.getFirstInstance().getDataSourceObjectId(); + + try { + // The data source should be cached so this won't actually be a database query. + Content ds = file.getFirstInstance().getDataSource(); + displayName = Bundle.FileSearch_DataSourceGroupKey_datasourceAndID(ds.getName(), ds.getId()); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Error looking up data source with ID " + dataSourceID, ex); // NON-NLS + displayName = Bundle.FileSearch_DataSourceGroupKey_idOnly(dataSourceID); + } + } + + @Override + String getDisplayName() { + return displayName; + } + + @Override + public int compareTo(GroupKey otherGroupKey) { + if (otherGroupKey instanceof DataSourceGroupKey) { + DataSourceGroupKey otherDataSourceGroupKey = (DataSourceGroupKey) otherGroupKey; + return Long.compare(getDataSourceID(), otherDataSourceGroupKey.getDataSourceID()); + } else { + return compareClassNames(otherGroupKey); + } + } + + @Override + public boolean equals(Object otherKey) { + if (otherKey == this) { + return true; + } + + if (!(otherKey instanceof DataSourceGroupKey)) { + return false; + } + + DataSourceGroupKey otherDataSourceGroupKey = (DataSourceGroupKey) otherKey; + return getDataSourceID() == otherDataSourceGroupKey.getDataSourceID(); + } + + @Override + public int hashCode() { + return Objects.hash(getDataSourceID()); + } + + /** + * @return the dataSourceID + */ + long getDataSourceID() { + return dataSourceID; } } @@ -270,37 +640,29 @@ public class DiscoveryKeyUtils { } /** - * Represents a key for a specific search for a specific user. + * Key representing a central repository frequency group */ - static class SearchKey implements Comparable { + static class FrequencyGroupKey extends GroupKey { - private final String keyString; + private final FileSearchData.Frequency frequency; - /** - * Construct a new SearchKey with all information that defines a search. - * - * @param userName The name of the user performing the search. - * @param filters The FileFilters being used for the search. - * @param groupAttributeType The AttributeType to group by. - * @param groupSortingType The algorithm to sort the groups by. - * @param fileSortingMethod The method to sort the files by. - */ - SearchKey(String userName, List filters, - FileSearch.AttributeType groupAttributeType, - FileGroup.GroupSortingAlgorithm groupSortingType, - FileSorter.SortingMethod fileSortingMethod) { - StringBuilder searchStringBuilder = new StringBuilder(); - searchStringBuilder.append(userName); - for (AbstractFilter filter : filters) { - searchStringBuilder.append(filter.toString()); - } - searchStringBuilder.append(groupAttributeType).append(groupSortingType).append(fileSortingMethod); - keyString = searchStringBuilder.toString(); + FrequencyGroupKey(ResultFile file) { + frequency = file.getFrequency(); } @Override - public int compareTo(SearchKey otherSearchKey) { - return getKeyString().compareTo(otherSearchKey.getKeyString()); + String getDisplayName() { + return getFrequency().toString(); + } + + @Override + public int compareTo(GroupKey otherGroupKey) { + if (otherGroupKey instanceof FrequencyGroupKey) { + FrequencyGroupKey otherFrequencyGroupKey = (FrequencyGroupKey) otherGroupKey; + return Integer.compare(getFrequency().getRanking(), otherFrequencyGroupKey.getFrequency().getRanking()); + } else { + return compareClassNames(otherGroupKey); + } } @Override @@ -309,26 +671,267 @@ public class DiscoveryKeyUtils { return true; } - if (!(otherKey instanceof SearchKey)) { + if (!(otherKey instanceof FrequencyGroupKey)) { return false; } - SearchKey otherSearchKey = (SearchKey) otherKey; - return getKeyString().equals(otherSearchKey.getKeyString()); + FrequencyGroupKey otherFrequencyGroupKey = (FrequencyGroupKey) otherKey; + return getFrequency().equals(otherFrequencyGroupKey.getFrequency()); } @Override public int hashCode() { - int hash = 5; - hash = 79 * hash + Objects.hashCode(getKeyString()); - return hash; + return Objects.hash(getFrequency().getRanking()); } /** - * @return the keyString + * @return the frequency */ - String getKeyString() { - return keyString; + FileSearchData.Frequency getFrequency() { + return frequency; + } + } + + /** + * Key representing a hash hits group + */ + static class HashHitsGroupKey extends GroupKey { + + private final List hashSetNames; + private final String hashSetNamesString; + + @NbBundle.Messages({ + "FileSearch.HashHitsGroupKey.noHashHits=None"}) + HashHitsGroupKey(ResultFile file) { + hashSetNames = file.getHashSetNames(); + + if (hashSetNames.isEmpty()) { + hashSetNamesString = Bundle.FileSearch_HashHitsGroupKey_noHashHits(); + } else { + hashSetNamesString = String.join(",", hashSetNames); // NON-NLS + } + } + + @Override + String getDisplayName() { + return getHashSetNamesString(); + } + + @Override + public int compareTo(GroupKey otherGroupKey) { + if (otherGroupKey instanceof HashHitsGroupKey) { + HashHitsGroupKey otherHashHitsGroupKey = (HashHitsGroupKey) otherGroupKey; + + // Put the empty list at the end + if (getHashSetNames().isEmpty()) { + if (otherHashHitsGroupKey.getHashSetNames().isEmpty()) { + return 0; + } else { + return 1; + } + } else if (otherHashHitsGroupKey.getHashSetNames().isEmpty()) { + return -1; + } + + return getHashSetNamesString().compareTo(otherHashHitsGroupKey.getHashSetNamesString()); + } else { + return compareClassNames(otherGroupKey); + } + } + + @Override + public boolean equals(Object otherKey) { + if (otherKey == this) { + return true; + } + + if (!(otherKey instanceof HashHitsGroupKey)) { + return false; + } + + HashHitsGroupKey otherHashHitsGroupKey = (HashHitsGroupKey) otherKey; + return getHashSetNamesString().equals(otherHashHitsGroupKey.getHashSetNamesString()); + } + + @Override + public int hashCode() { + return Objects.hash(getHashSetNamesString()); + } + + /** + * @return the hashSetNames + */ + List getHashSetNames() { + return Collections.unmodifiableList(hashSetNames); + } + + /** + * @return the hashSetNamesString + */ + String getHashSetNamesString() { + return hashSetNamesString; + } + } + + /** + * Key representing a interesting item set group + */ + static class InterestingItemGroupKey extends GroupKey { + + private final List interestingItemSetNames; + private final String interestingItemSetNamesString; + + @NbBundle.Messages({ + "FileSearch.InterestingItemGroupKey.noSets=None"}) + InterestingItemGroupKey(ResultFile file) { + interestingItemSetNames = file.getInterestingSetNames(); + + if (interestingItemSetNames.isEmpty()) { + interestingItemSetNamesString = Bundle.FileSearch_InterestingItemGroupKey_noSets(); + } else { + interestingItemSetNamesString = String.join(",", interestingItemSetNames); // NON-NLS + } + } + + @Override + String getDisplayName() { + return getInterestingItemSetNamesString(); + } + + @Override + public int compareTo(GroupKey otherGroupKey) { + if (otherGroupKey instanceof InterestingItemGroupKey) { + InterestingItemGroupKey otherInterestingItemGroupKey = (InterestingItemGroupKey) otherGroupKey; + + // Put the empty list at the end + if (this.getInterestingItemSetNames().isEmpty()) { + if (otherInterestingItemGroupKey.getInterestingItemSetNames().isEmpty()) { + return 0; + } else { + return 1; + } + } else if (otherInterestingItemGroupKey.getInterestingItemSetNames().isEmpty()) { + return -1; + } + + return getInterestingItemSetNamesString().compareTo(otherInterestingItemGroupKey.getInterestingItemSetNamesString()); + } else { + return compareClassNames(otherGroupKey); + } + } + + @Override + public boolean equals(Object otherKey) { + if (otherKey == this) { + return true; + } + + if (!(otherKey instanceof InterestingItemGroupKey)) { + return false; + } + + InterestingItemGroupKey otherInterestingItemGroupKey = (InterestingItemGroupKey) otherKey; + return getInterestingItemSetNamesString().equals(otherInterestingItemGroupKey.getInterestingItemSetNamesString()); + } + + @Override + public int hashCode() { + return Objects.hash(getInterestingItemSetNamesString()); + } + + /** + * @return the interestingItemSetNames + */ + List getInterestingItemSetNames() { + return Collections.unmodifiableList(interestingItemSetNames); + } + + /** + * @return the interestingItemSetNamesString + */ + String getInterestingItemSetNamesString() { + return interestingItemSetNamesString; + } + } + + /** + * Key representing an object detected group + */ + static class ObjectDetectedGroupKey extends GroupKey { + + private final List objectDetectedNames; + private final String objectDetectedNamesString; + + @NbBundle.Messages({ + "FileSearch.ObjectDetectedGroupKey.noSets=None"}) + ObjectDetectedGroupKey(ResultFile file) { + objectDetectedNames = file.getObjectDetectedNames(); + + if (objectDetectedNames.isEmpty()) { + objectDetectedNamesString = Bundle.FileSearch_ObjectDetectedGroupKey_noSets(); + } else { + objectDetectedNamesString = String.join(",", objectDetectedNames); // NON-NLS + } + } + + @Override + String getDisplayName() { + return getObjectDetectedNamesString(); + } + + @Override + public int compareTo(GroupKey otherGroupKey) { + if (otherGroupKey instanceof ObjectDetectedGroupKey) { + ObjectDetectedGroupKey otherObjectDetectedGroupKey = (ObjectDetectedGroupKey) otherGroupKey; + + // Put the empty list at the end + if (this.getObjectDetectedNames().isEmpty()) { + if (otherObjectDetectedGroupKey.getObjectDetectedNames().isEmpty()) { + return 0; + } else { + return 1; + } + } else if (otherObjectDetectedGroupKey.getObjectDetectedNames().isEmpty()) { + return -1; + } + + return getObjectDetectedNamesString().compareTo(otherObjectDetectedGroupKey.getObjectDetectedNamesString()); + } else { + return compareClassNames(otherGroupKey); + } + } + + @Override + public boolean equals(Object otherKey) { + if (otherKey == this) { + return true; + } + + if (!(otherKey instanceof ObjectDetectedGroupKey)) { + return false; + } + + ObjectDetectedGroupKey otherObjectDetectedGroupKey = (ObjectDetectedGroupKey) otherKey; + return getObjectDetectedNamesString().equals(otherObjectDetectedGroupKey.getObjectDetectedNamesString()); + } + + @Override + public int hashCode() { + return Objects.hash(getObjectDetectedNamesString()); + } + + /** + * @return the objectDetectedNames + */ + List getObjectDetectedNames() { + return Collections.unmodifiableList(objectDetectedNames); + } + + /** + * @return the objectDetectedNamesString + */ + String getObjectDetectedNamesString() { + return objectDetectedNamesString; } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java index aaac8304fb..1ba77545de 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java @@ -25,14 +25,12 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.logging.Level; import org.apache.commons.lang.StringUtils; @@ -42,13 +40,11 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.InstanceTableCallback; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.discovery.search.FileSearchData.FileType; import org.sleuthkit.autopsy.discovery.search.FileSearchData.Frequency; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.CaseDbAccessManager; -import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; @@ -70,7 +66,6 @@ public class FileSearch { .maximumSize(MAXIMUM_CACHE_SIZE) .build(); - /** * Run the file search and returns the SearchResults object for debugging. * Caching new results for access at later time. @@ -237,7 +232,7 @@ public class FileSearch { "FileSearch.documentSummary.noBytes=No bytes read for document, unable to display preview."}) public static TextSummary summarize(AbstractFile file) { TextSummary summary = null; - TextSummarizer localSummarizer; + TextSummarizer localSummarizer; synchronized (searchCache) { localSummarizer = SummaryHelpers.getLocalSummarizer(); @@ -417,16 +412,14 @@ public class FileSearch { } } - - /** * Attribute for grouping/sorting by file size */ - static class FileSizeAttribute extends AttributeType { + public static class FileSizeAttribute extends AttributeType { @Override public GroupKey getGroupKey(ResultFile file) { - return new FileSizeGroupKey(file); + return new DiscoveryKeyUtils.FileSizeGroupKey(file); } } @@ -437,115 +430,18 @@ public class FileSearch { @Override public GroupKey getGroupKey(ResultFile file) { - return new ParentPathGroupKey(file); + return new DiscoveryKeyUtils.ParentPathGroupKey(file); } } /** - * Key representing a parent path group + * Default attribute used to make one group */ - private static class ParentPathGroupKey extends GroupKey { - - private String parentPath; - private Long parentID; - - ParentPathGroupKey(ResultFile file) { - Content parent; - try { - parent = file.getFirstInstance().getParent(); - } catch (TskCoreException ignored) { - parent = null; - } - //Find the directory this file is in if it is an embedded file - while (parent != null && parent instanceof AbstractFile && ((AbstractFile) parent).isFile()) { - try { - parent = parent.getParent(); - } catch (TskCoreException ignored) { - parent = null; - } - } - setParentPathAndID(parent, file); - } - - /** - * Helper method to set the parent path and parent ID. - * - * @param parent The parent content object. - * @param file The ResultFile object. - */ - private void setParentPathAndID(Content parent, ResultFile file) { - if (parent != null) { - try { - parentPath = parent.getUniquePath(); - parentID = parent.getId(); - } catch (TskCoreException ignored) { - //catch block left blank purposefully next if statement will handle case when exception takes place as well as when parent is null - } - - } - if (parentPath == null) { - if (file.getFirstInstance().getParentPath() != null) { - parentPath = file.getFirstInstance().getParentPath(); - } else { - parentPath = ""; // NON-NLS - } - parentID = -1L; - } - } + static class NoGroupingAttribute extends FileSearch.AttributeType { @Override - String getDisplayName() { - return getParentPath(); - } - - @Override - public int compareTo(GroupKey otherGroupKey) { - if (otherGroupKey instanceof ParentPathGroupKey) { - ParentPathGroupKey otherParentPathGroupKey = (ParentPathGroupKey) otherGroupKey; - int comparisonResult = getParentPath().compareTo(otherParentPathGroupKey.getParentPath()); - if (comparisonResult == 0) { - comparisonResult = getParentID().compareTo(otherParentPathGroupKey.getParentID()); - } - return comparisonResult; - } else { - return compareClassNames(otherGroupKey); - } - } - - @Override - public boolean equals(Object otherKey) { - if (otherKey == this) { - return true; - } - - if (!(otherKey instanceof ParentPathGroupKey)) { - return false; - } - - ParentPathGroupKey otherParentPathGroupKey = (ParentPathGroupKey) otherKey; - return getParentPath().equals(otherParentPathGroupKey.getParentPath()) && getParentID().equals(otherParentPathGroupKey.getParentID()); - } - - @Override - public int hashCode() { - int hashCode = 11; - hashCode = 61 * hashCode + Objects.hash(getParentPath()); - hashCode = 61 * hashCode + Objects.hash(getParentID()); - return hashCode; - } - - /** - * @return the parentPath - */ - String getParentPath() { - return parentPath; - } - - /** - * @return the parentID - */ - Long getParentID() { - return parentID; + public GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.NoGroupingGroupKey(); } } @@ -556,76 +452,7 @@ public class FileSearch { @Override public GroupKey getGroupKey(ResultFile file) { - return new DataSourceGroupKey(file); - } - } - - /** - * Key representing a data source group - */ - private static class DataSourceGroupKey extends GroupKey { - - private final long dataSourceID; - private String displayName; - - @NbBundle.Messages({ - "# {0} - Data source name", - "# {1} - Data source ID", - "FileSearch.DataSourceGroupKey.datasourceAndID={0}(ID: {1})", - "# {0} - Data source ID", - "FileSearch.DataSourceGroupKey.idOnly=Data source (ID: {0})"}) - DataSourceGroupKey(ResultFile file) { - dataSourceID = file.getFirstInstance().getDataSourceObjectId(); - - try { - // The data source should be cached so this won't actually be a database query. - Content ds = file.getFirstInstance().getDataSource(); - displayName = Bundle.FileSearch_DataSourceGroupKey_datasourceAndID(ds.getName(), ds.getId()); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error looking up data source with ID " + dataSourceID, ex); // NON-NLS - displayName = Bundle.FileSearch_DataSourceGroupKey_idOnly(dataSourceID); - } - } - - @Override - String getDisplayName() { - return displayName; - } - - @Override - public int compareTo(GroupKey otherGroupKey) { - if (otherGroupKey instanceof DataSourceGroupKey) { - DataSourceGroupKey otherDataSourceGroupKey = (DataSourceGroupKey) otherGroupKey; - return Long.compare(getDataSourceID(), otherDataSourceGroupKey.getDataSourceID()); - } else { - return compareClassNames(otherGroupKey); - } - } - - @Override - public boolean equals(Object otherKey) { - if (otherKey == this) { - return true; - } - - if (!(otherKey instanceof DataSourceGroupKey)) { - return false; - } - - DataSourceGroupKey otherDataSourceGroupKey = (DataSourceGroupKey) otherKey; - return getDataSourceID() == otherDataSourceGroupKey.getDataSourceID(); - } - - @Override - public int hashCode() { - return Objects.hash(getDataSourceID()); - } - - /** - * @return the dataSourceID - */ - long getDataSourceID() { - return dataSourceID; + return new DiscoveryKeyUtils.DataSourceGroupKey(file); } } @@ -636,60 +463,7 @@ public class FileSearch { @Override public GroupKey getGroupKey(ResultFile file) { - return new FileTypeGroupKey(file); - } - } - - /** - * Key representing a file type group - */ - private static class FileTypeGroupKey extends GroupKey { - - private final FileType fileType; - - FileTypeGroupKey(ResultFile file) { - fileType = file.getFileType(); - } - - @Override - String getDisplayName() { - return getFileType().toString(); - } - - @Override - public int compareTo(GroupKey otherGroupKey) { - if (otherGroupKey instanceof FileTypeGroupKey) { - FileTypeGroupKey otherFileTypeGroupKey = (FileTypeGroupKey) otherGroupKey; - return Integer.compare(getFileType().getRanking(), otherFileTypeGroupKey.getFileType().getRanking()); - } else { - return compareClassNames(otherGroupKey); - } - } - - @Override - public boolean equals(Object otherKey) { - if (otherKey == this) { - return true; - } - - if (!(otherKey instanceof FileTypeGroupKey)) { - return false; - } - - FileTypeGroupKey otherFileTypeGroupKey = (FileTypeGroupKey) otherKey; - return getFileType().equals(otherFileTypeGroupKey.getFileType()); - } - - @Override - public int hashCode() { - return Objects.hash(getFileType().getRanking()); - } - - /** - * @return the fileType - */ - FileType getFileType() { - return fileType; + return new DiscoveryKeyUtils.FileTypeGroupKey(file); } } @@ -700,7 +474,7 @@ public class FileSearch { @Override public GroupKey getGroupKey(ResultFile file) { - return new KeywordListGroupKey(file); + return new DiscoveryKeyUtils.KeywordListGroupKey(file); } @Override @@ -765,87 +539,6 @@ public class FileSearch { } } - /** - * Key representing a keyword list group - */ - private static class KeywordListGroupKey extends GroupKey { - - private final List keywordListNames; - private final String keywordListNamesString; - - @NbBundle.Messages({ - "FileSearch.KeywordListGroupKey.noKeywords=None"}) - KeywordListGroupKey(ResultFile file) { - keywordListNames = file.getKeywordListNames(); - - if (keywordListNames.isEmpty()) { - keywordListNamesString = Bundle.FileSearch_KeywordListGroupKey_noKeywords(); - } else { - keywordListNamesString = String.join(",", keywordListNames); // NON-NLS - } - } - - @Override - String getDisplayName() { - return getKeywordListNamesString(); - } - - @Override - public int compareTo(GroupKey otherGroupKey) { - if (otherGroupKey instanceof KeywordListGroupKey) { - KeywordListGroupKey otherKeywordListNamesGroupKey = (KeywordListGroupKey) otherGroupKey; - - // Put the empty list at the end - if (getKeywordListNames().isEmpty()) { - if (otherKeywordListNamesGroupKey.getKeywordListNames().isEmpty()) { - return 0; - } else { - return 1; - } - } else if (otherKeywordListNamesGroupKey.getKeywordListNames().isEmpty()) { - return -1; - } - - return getKeywordListNamesString().compareTo(otherKeywordListNamesGroupKey.getKeywordListNamesString()); - } else { - return compareClassNames(otherGroupKey); - } - } - - @Override - public boolean equals(Object otherKey) { - if (otherKey == this) { - return true; - } - - if (!(otherKey instanceof KeywordListGroupKey)) { - return false; - } - - KeywordListGroupKey otherKeywordListGroupKey = (KeywordListGroupKey) otherKey; - return getKeywordListNamesString().equals(otherKeywordListGroupKey.getKeywordListNamesString()); - } - - @Override - public int hashCode() { - return Objects.hash(getKeywordListNamesString()); - } - - /** - * @return the keywordListNames - */ - List getKeywordListNames() { - return Collections.unmodifiableList(keywordListNames); - } - - /** - * @return the keywordListNamesString - */ - String getKeywordListNamesString() { - return keywordListNamesString; - } - } - /** * Attribute for grouping/sorting by frequency in the central repository */ @@ -855,7 +548,7 @@ public class FileSearch { @Override public GroupKey getGroupKey(ResultFile file) { - return new FrequencyGroupKey(file); + return new DiscoveryKeyUtils.FrequencyGroupKey(file); } @Override @@ -943,59 +636,6 @@ public class FileSearch { } } - /** - * Key representing a central repository frequency group - */ - private static class FrequencyGroupKey extends GroupKey { - - private final Frequency frequency; - - FrequencyGroupKey(ResultFile file) { - frequency = file.getFrequency(); - } - - @Override - String getDisplayName() { - return getFrequency().toString(); - } - - @Override - public int compareTo(GroupKey otherGroupKey) { - if (otherGroupKey instanceof FrequencyGroupKey) { - FrequencyGroupKey otherFrequencyGroupKey = (FrequencyGroupKey) otherGroupKey; - return Integer.compare(getFrequency().getRanking(), otherFrequencyGroupKey.getFrequency().getRanking()); - } else { - return compareClassNames(otherGroupKey); - } - } - - @Override - public boolean equals(Object otherKey) { - if (otherKey == this) { - return true; - } - - if (!(otherKey instanceof FrequencyGroupKey)) { - return false; - } - - FrequencyGroupKey otherFrequencyGroupKey = (FrequencyGroupKey) otherKey; - return getFrequency().equals(otherFrequencyGroupKey.getFrequency()); - } - - @Override - public int hashCode() { - return Objects.hash(getFrequency().getRanking()); - } - - /** - * @return the frequency - */ - Frequency getFrequency() { - return frequency; - } - } - /** * Attribute for grouping/sorting by hash set lists */ @@ -1003,7 +643,7 @@ public class FileSearch { @Override public GroupKey getGroupKey(ResultFile file) { - return new HashHitsGroupKey(file); + return new DiscoveryKeyUtils.HashHitsGroupKey(file); } @Override @@ -1067,87 +707,6 @@ public class FileSearch { } } - /** - * Key representing a hash hits group - */ - private static class HashHitsGroupKey extends GroupKey { - - private final List hashSetNames; - private final String hashSetNamesString; - - @NbBundle.Messages({ - "FileSearch.HashHitsGroupKey.noHashHits=None"}) - HashHitsGroupKey(ResultFile file) { - hashSetNames = file.getHashSetNames(); - - if (hashSetNames.isEmpty()) { - hashSetNamesString = Bundle.FileSearch_HashHitsGroupKey_noHashHits(); - } else { - hashSetNamesString = String.join(",", hashSetNames); // NON-NLS - } - } - - @Override - String getDisplayName() { - return getHashSetNamesString(); - } - - @Override - public int compareTo(GroupKey otherGroupKey) { - if (otherGroupKey instanceof HashHitsGroupKey) { - HashHitsGroupKey otherHashHitsGroupKey = (HashHitsGroupKey) otherGroupKey; - - // Put the empty list at the end - if (getHashSetNames().isEmpty()) { - if (otherHashHitsGroupKey.getHashSetNames().isEmpty()) { - return 0; - } else { - return 1; - } - } else if (otherHashHitsGroupKey.getHashSetNames().isEmpty()) { - return -1; - } - - return getHashSetNamesString().compareTo(otherHashHitsGroupKey.getHashSetNamesString()); - } else { - return compareClassNames(otherGroupKey); - } - } - - @Override - public boolean equals(Object otherKey) { - if (otherKey == this) { - return true; - } - - if (!(otherKey instanceof HashHitsGroupKey)) { - return false; - } - - HashHitsGroupKey otherHashHitsGroupKey = (HashHitsGroupKey) otherKey; - return getHashSetNamesString().equals(otherHashHitsGroupKey.getHashSetNamesString()); - } - - @Override - public int hashCode() { - return Objects.hash(getHashSetNamesString()); - } - - /** - * @return the hashSetNames - */ - List getHashSetNames() { - return Collections.unmodifiableList(hashSetNames); - } - - /** - * @return the hashSetNamesString - */ - String getHashSetNamesString() { - return hashSetNamesString; - } - } - /** * Attribute for grouping/sorting by interesting item set lists */ @@ -1155,7 +714,7 @@ public class FileSearch { @Override public GroupKey getGroupKey(ResultFile file) { - return new InterestingItemGroupKey(file); + return new DiscoveryKeyUtils.InterestingItemGroupKey(file); } @Override @@ -1221,87 +780,6 @@ public class FileSearch { } } - /** - * Key representing a interesting item set group - */ - private static class InterestingItemGroupKey extends GroupKey { - - private final List interestingItemSetNames; - private final String interestingItemSetNamesString; - - @NbBundle.Messages({ - "FileSearch.InterestingItemGroupKey.noSets=None"}) - InterestingItemGroupKey(ResultFile file) { - interestingItemSetNames = file.getInterestingSetNames(); - - if (interestingItemSetNames.isEmpty()) { - interestingItemSetNamesString = Bundle.FileSearch_InterestingItemGroupKey_noSets(); - } else { - interestingItemSetNamesString = String.join(",", interestingItemSetNames); // NON-NLS - } - } - - @Override - String getDisplayName() { - return getInterestingItemSetNamesString(); - } - - @Override - public int compareTo(GroupKey otherGroupKey) { - if (otherGroupKey instanceof InterestingItemGroupKey) { - InterestingItemGroupKey otherInterestingItemGroupKey = (InterestingItemGroupKey) otherGroupKey; - - // Put the empty list at the end - if (this.getInterestingItemSetNames().isEmpty()) { - if (otherInterestingItemGroupKey.getInterestingItemSetNames().isEmpty()) { - return 0; - } else { - return 1; - } - } else if (otherInterestingItemGroupKey.getInterestingItemSetNames().isEmpty()) { - return -1; - } - - return getInterestingItemSetNamesString().compareTo(otherInterestingItemGroupKey.getInterestingItemSetNamesString()); - } else { - return compareClassNames(otherGroupKey); - } - } - - @Override - public boolean equals(Object otherKey) { - if (otherKey == this) { - return true; - } - - if (!(otherKey instanceof InterestingItemGroupKey)) { - return false; - } - - InterestingItemGroupKey otherInterestingItemGroupKey = (InterestingItemGroupKey) otherKey; - return getInterestingItemSetNamesString().equals(otherInterestingItemGroupKey.getInterestingItemSetNamesString()); - } - - @Override - public int hashCode() { - return Objects.hash(getInterestingItemSetNamesString()); - } - - /** - * @return the interestingItemSetNames - */ - List getInterestingItemSetNames() { - return Collections.unmodifiableList(interestingItemSetNames); - } - - /** - * @return the interestingItemSetNamesString - */ - String getInterestingItemSetNamesString() { - return interestingItemSetNamesString; - } - } - /** * Attribute for grouping/sorting by objects detected */ @@ -1309,7 +787,7 @@ public class FileSearch { @Override public GroupKey getGroupKey(ResultFile file) { - return new ObjectDetectedGroupKey(file); + return new DiscoveryKeyUtils.ObjectDetectedGroupKey(file); } @Override @@ -1374,87 +852,6 @@ public class FileSearch { } } - /** - * Key representing an object detected group - */ - private static class ObjectDetectedGroupKey extends GroupKey { - - private final List objectDetectedNames; - private final String objectDetectedNamesString; - - @NbBundle.Messages({ - "FileSearch.ObjectDetectedGroupKey.noSets=None"}) - ObjectDetectedGroupKey(ResultFile file) { - objectDetectedNames = file.getObjectDetectedNames(); - - if (objectDetectedNames.isEmpty()) { - objectDetectedNamesString = Bundle.FileSearch_ObjectDetectedGroupKey_noSets(); - } else { - objectDetectedNamesString = String.join(",", objectDetectedNames); // NON-NLS - } - } - - @Override - String getDisplayName() { - return getObjectDetectedNamesString(); - } - - @Override - public int compareTo(GroupKey otherGroupKey) { - if (otherGroupKey instanceof ObjectDetectedGroupKey) { - ObjectDetectedGroupKey otherObjectDetectedGroupKey = (ObjectDetectedGroupKey) otherGroupKey; - - // Put the empty list at the end - if (this.getObjectDetectedNames().isEmpty()) { - if (otherObjectDetectedGroupKey.getObjectDetectedNames().isEmpty()) { - return 0; - } else { - return 1; - } - } else if (otherObjectDetectedGroupKey.getObjectDetectedNames().isEmpty()) { - return -1; - } - - return getObjectDetectedNamesString().compareTo(otherObjectDetectedGroupKey.getObjectDetectedNamesString()); - } else { - return compareClassNames(otherGroupKey); - } - } - - @Override - public boolean equals(Object otherKey) { - if (otherKey == this) { - return true; - } - - if (!(otherKey instanceof ObjectDetectedGroupKey)) { - return false; - } - - ObjectDetectedGroupKey otherObjectDetectedGroupKey = (ObjectDetectedGroupKey) otherKey; - return getObjectDetectedNamesString().equals(otherObjectDetectedGroupKey.getObjectDetectedNamesString()); - } - - @Override - public int hashCode() { - return Objects.hash(getObjectDetectedNamesString()); - } - - /** - * @return the objectDetectedNames - */ - List getObjectDetectedNames() { - return Collections.unmodifiableList(objectDetectedNames); - } - - /** - * @return the objectDetectedNamesString - */ - String getObjectDetectedNamesString() { - return objectDetectedNamesString; - } - } - /** * Attribute for grouping/sorting by tag name */ @@ -1483,8 +880,6 @@ public class FileSearch { } } - - /** * Enum for the attribute types that can be used for grouping. */ diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED index 39b573d24f..2de9ea3e1f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED @@ -1,5 +1,7 @@ -AttributeSearchData.AttributeType.Domain.displayName=Domain -AttributeSearchData.AttributeType.Other.displayName=Other +# To change this license header, choose License Headers in Project Properties. +# To change this template file, choose Tools | Templates +# and open the template in the editor. + CTL_OpenDiscoveryAction=Discovery # {0} - dataSourceName DataSourceModuleWrapper.exifModule.text=Exif Parser module was not run on data source: {0}\n @@ -10,6 +12,16 @@ DataSourceModuleWrapper.hashModule.text=Hash Lookup module was not run on data s # {0} - timeZone DateFilterPanel.dateRange.text=Date Range ({0}): DiscoveryDialog.name.text=Discovery +DiscoveryDialog.sortingPanel.border.title=Step 3: Choose display settings +DiscoveryDialog.searchButton.text=Search +DiscoveryDialog.domainsButton.text=Domains +DiscoveryDialog.groupByLabel.text=Group By: +DiscoveryDialog.step1Label.text=Step 1: Choose result type +DiscoveryDialog.orderByLabel.text=Order Within Groups By: +DiscoveryDialog.documentsButton.text=Documents +DiscoveryDialog.orderGroupsByLabel.text=Order Groups By: +DiscoveryDialog.videosButton.text=Videos +DiscoveryDialog.imagesButton.text=Images DiscoveryTopComponent.cancelButton.text=Cancel Search DiscoveryTopComponent.name=\ Discovery DiscoveryTopComponent.newSearch.text=New Search @@ -27,6 +39,9 @@ DiscoveryUiUtility.megaBytes.text=MB # {1} - units DiscoveryUiUtility.sizeLabel.text=Size: {0} {1} DiscoveryUiUtility.terraBytes.text=TB +# {0} - file name +DiscoveryUiUtils.genVideoThumb.progress.text=extracting temporary file {0} +DiscoveryUiUtils.isDeleted.text=All instances of file are deleted. # {0} - otherInstanceCount DocumentPanel.nameLabel.more.text=\ and {0} more DocumentPanel.noImageExtraction.text=0 of ? images @@ -34,220 +49,26 @@ DocumentPanel.numberOfImages.noImages=No images # {0} - numberOfImages DocumentPanel.numberOfImages.text=1 of {0} images DocumentWrapper.previewInitialValue=Preview not generated yet. -FileGroup.groupSortingAlgorithm.groupName.text=Group Name -FileGroup.groupSortingAlgorithm.groupSize.text=Group Size -# {0} - Data source name -# {1} - Data source ID -FileSearch.DataSourceGroupKey.datasourceAndID={0}(ID: {1}) -# {0} - Data source ID -FileSearch.DataSourceGroupKey.idOnly=Data source (ID: {0}) -FileSearch.documentSummary.noBytes=No bytes read for document, unable to display preview. -FileSearch.documentSummary.noPreview=No preview available. -FileSearch.FileTagGroupKey.noSets=None -# {0} - file name -FileSearch.genVideoThumb.progress.text=extracting temporary file {0} -FileSearch.GroupingAttributeType.datasource.displayName=Data Source -FileSearch.GroupingAttributeType.fileType.displayName=File Type -FileSearch.GroupingAttributeType.frequency.displayName=Past Occurrences -FileSearch.GroupingAttributeType.hash.displayName=Hash Set -FileSearch.GroupingAttributeType.interestingItem.displayName=Interesting Item -FileSearch.GroupingAttributeType.keywordList.displayName=Keyword -FileSearch.GroupingAttributeType.none.displayName=None -FileSearch.GroupingAttributeType.object.displayName=Object Detected -FileSearch.GroupingAttributeType.parent.displayName=Parent Folder -FileSearch.GroupingAttributeType.size.displayName=File Size -FileSearch.GroupingAttributeType.tag.displayName=Tag -FileSearch.HashHitsGroupKey.noHashHits=None -FileSearch.InterestingItemGroupKey.noSets=None -FileSearch.KeywordListGroupKey.noKeywords=None -FileSearch.NoGroupingGroupKey.allFiles=All Files -FileSearch.ObjectDetectedGroupKey.noSets=None -FileSearchData.FileSize.100kbto1mb=: 100KB-1MB -FileSearchData.FileSize.100mbto1gb=: 100MB-1GB -FileSearchData.FileSize.10PlusGb=: 10GB+ -FileSearchData.FileSize.16kbto100kb=: 16-100KB -FileSearchData.FileSize.1gbto5gb=: 1-5GB -FileSearchData.FileSize.1mbto50mb=: 1-50MB -FileSearchData.FileSize.200PlusMb=: 200MB+ -FileSearchData.FileSize.500kbto100mb=: 500KB-100MB -FileSearchData.FileSize.50mbto200mb=: 50-200MB -FileSearchData.FileSize.5gbto10gb=: 5-10GB -FileSearchData.FileSize.LARGE.displayName=Large -FileSearchData.FileSize.MEDIUM.displayName=Medium -FileSearchData.FileSize.SMALL.displayName=Small -FileSearchData.FileSize.upTo16kb=: 0-16KB -FileSearchData.FileSize.upTo500kb=: 0-500KB -FileSearchData.FileSize.XLARGE.displayName=XLarge -FileSearchData.FileSize.XSMALL.displayName=XSmall -FileSearchData.FileSize.XXLARGE.displayName=XXLarge -FileSearchData.FileType.Audio.displayName=Audio -FileSearchData.FileType.Documents.displayName=Documents -FileSearchData.FileType.Executables.displayName=Executables -FileSearchData.FileType.Image.displayName=Image -FileSearchData.FileType.Other.displayName=Other/Unknown -FileSearchData.FileType.Video.displayName=Video -FileSearchData.Frequency.common.displayName=Common (11 - 100) -FileSearchData.Frequency.known.displayName=Known (NSRL) -FileSearchData.Frequency.rare.displayName=Rare (2-10) -FileSearchData.Frequency.unique.displayName=Unique (1) -FileSearchData.Frequency.unknown.displayName=Unknown -FileSearchData.Frequency.verycommon.displayName=Very Common (100+) -FileSearchData.Score.interesting.displayName=Interesting -FileSearchData.Score.notable.displayName=Notable -FileSearchData.Score.unknown.displayName=Unknown -FileSearchDialog.jLabel1.text=File Type -FileSearchDialog.dsCheckBox.text=Data source -FileSearchDialog.cancelButton.text=Cancel -FileSearchDialog.freqCheckBox.text=CR Frequency -FileSearchDialog.sizeCheckBox.text=Size -FileSearchDialog.kwCheckBox.text=Keyword -FileSearchDialog.addParentButton.text=Add -FileSearchDialog.deleteParentButton.text=Delete -FileSearchDialog.parentFullRadioButton.text=Full -FileSearchDialog.parentSubstringRadioButton.text=Substring -FileSearchDialog.jLabel2.text=(All will be used) -FileSearchDialog.jLabel3.text=Group by attribute: -FileSearchDialog.jLabel4.text=Order groups by: -FileSearchDialog.orderAttrRadioButton.text=Attribute -FileSearchDialog.orderSizeRadioButton.text=Group Size -FileSearchDialog.jLabel5.text=Order files by: -FileSearchDialog.parentCheckBox.text=Parent -FileSearchFiltering.concatenateSetNamesForDisplay.comma=, -# {0} - filters -FileSearchFiltering.HashSetFilter.desc=Hash set hits in set(s): {0} -FileSearchFiltering.KnownFilter.desc=which are not known -FileSearchFiltering.PreviouslyNotableFilter.desc=that were previously marked as notable -# {0} - tag names -FileSearchFiltering.TagsFilter.desc=Tagged {0} -FileSearchFiltering.TagsFilter.or=, -FileSearchFiltering.UserCreatedFilter.desc=that contain EXIF data -FileSearchPanel.sortingPanel.border.title=Grouping -FileSearchPanel.addButton.text=Add -FileSearchPanel.substringRadioButton.text=Substring -FileSearchPanel.fullRadioButton.text=Full -FileSearchPanel.parentCheckbox.text=Parent Folder: -FileSearchPanel.keywordCheckbox.text=Keyword: -FileSearchPanel.crFrequencyCheckbox.text=Past Occurrences: -FileSearchPanel.dataSourceCheckbox.text=Data Source: -FileSearchPanel.sizeCheckbox.text=File Size: -FileSearchPanel.orderGroupsByLabel.text=Order Groups By: -FileSearchPanel.filtersScrollPane.border.title=Filters -FileSearchPanel.parentLabel.text=(All will be used) -FileSearchPanel.deleteButton.text=Delete -FileSearchPanel.orderByLabel.text=Order Within Groups By: -FileSearchPanel.groupByLabel.text=Group By: -FileSearchDialog.searchButton.text=Search -FileSearchDialog.hashCheckBox.text=Hash Set -FileSearchDialog.intCheckBox.text=Interesting Items -FileSearchDialog.tagsCheckBox.text=Tags -FileSearchDialog.objCheckBox.text=Objects -FileSearchDialog.exifCheckBox.text=Must contain EXIF data -FileSearchDialog.notableCheckBox.text=Must have been tagged as notable -FileSearchDialog.scoreCheckBox.text=Has score -FileSearchPanel.hashSetCheckbox.text=Hash Set: -FileSearchPanel.tagsCheckbox.text=Tag: -FileSearchPanel.interestingItemsCheckbox.text=Interesting Item: -FileSearchPanel.scoreCheckbox.text=Has Score: -FileSearchPanel.notableCheckbox.text=Must have been tagged as notable -FileSearchPanel.objectsCheckbox.text=Object Detected: -FileSorter.SortingMethod.datasource.displayName=Data Source -FileSorter.SortingMethod.filename.displayName=File Name -FileSorter.SortingMethod.filesize.displayName=File Size -FileSorter.SortingMethod.filetype.displayName=File Type -FileSorter.SortingMethod.frequency.displayName=Central Repo Frequency -FileSorter.SortingMethod.fullPath.displayName=Full Path -FileSorter.SortingMethod.keywordlist.displayName=Keyword List Names GroupsListPanel.noResults.message.text=No results were found for the selected filters.\n\nReminder:\n -The File Type Identification module must be run on each data source you want to find results in.\n -The Hash Lookup module must be run on each data source if you want to filter by past occurrence.\n -The Exif module must be run on each data source if you are filtering by User Created content. GroupsListPanel.noResults.title.text=No results found ImageThumbnailPanel.isDeleted.text=All instances of file are deleted. # {0} - otherInstanceCount ImageThumbnailPanel.nameLabel.more.text=\ and {0} more OpenDiscoveryAction.resultsIncomplete.text=Discovery results may be incomplete -ResultFile.score.interestingResult.description=At least one instance of the file has an interesting result associated with it. -ResultFile.score.notableFile.description=At least one instance of the file was recognized as notable. -ResultFile.score.notableTaggedFile.description=At least one instance of the file is tagged with a notable tag. -ResultFile.score.taggedFile.description=At least one instance of the file has been tagged. # {0} - currentPage # {1} - totalPages ResultsPanel.currentPage.displayValue=Page: {0} of {1} -ResultsPanel.currentPageLabel.text=Page: - ResultsPanel.documentPreview.text=Document preview creation cancelled. # {0} - selectedPage # {1} - maxPage ResultsPanel.invalidPageNumber.message=The selected page number {0} does not exist. Please select a value from 1 to {1}. ResultsPanel.invalidPageNumber.title=Invalid Page Number ResultsPanel.openInExternalViewer.name=Open in External Viewer -ResultsPanel.pageControlsLabel.text=Pages: -ResultsPanel.gotoPageLabel.text=Go to Page: -ResultsPanel.pageSizeLabel.text=Page Size: -DiscoveryExtractAction.title.extractFiles.text=Extract File -FileSearchPanel.includeRadioButton.text=Include -FileSearchPanel.excludeRadioButton.text=Exclude -FileSearchPanel.knownFilesCheckbox.toolTipText= -FileSearchPanel.knownFilesCheckbox.text=Hide known files -GroupListPanel.groupKeyList.border.title=Groups -FileSearchPanel.stepThreeLabel.text=Step 3: Choose display settings -DocumentPanel.fileSizeLabel.toolTipText= -DocumentPanel.isDeletedLabel.toolTipText= -ImageThumbnailPanel.isDeletedLabel.toolTipText= -FileSearchPanel.userCreatedCheckbox.text=Possibly User Created -DiscoveryDialog.documentsButton.text=Documents -DiscoveryDialog.videosButton.text=Videos -DiscoveryDialog.imagesButton.text=Images -DiscoveryDialog.searchButton.text=Search -DetailsPanel.instancesList.border.title=Instances ResultsPanel.unableToCreate.text=Unable to create summary. ResultsPanel.viewFileInDir.name=View File in Directory -# {0} - Data source name -# {1} - Data source ID -SearchFiltering.DataSourceFilter.datasource={0}({1}) -# {0} - filters -SearchFiltering.DataSourceFilter.desc=Data source(s): {0} -SearchFiltering.DataSourceFilter.or=, -# {0} - filters -SearchFiltering.FileTypeFilter.desc=Type: {0} -SearchFiltering.FileTypeFilter.or=, -# {0} - filters -SearchFiltering.FrequencyFilter.desc=Past occurrences: {0} -SearchFiltering.FrequencyFilter.or=, -# {0} - filters -SearchFiltering.InterestingItemSetFilter.desc=Interesting item hits in set(s): {0} -# {0} - filters -SearchFiltering.KeywordListFilter.desc=Keywords in list(s): {0} -# {0} - filters -SearchFiltering.ObjectDetectionFilter.desc=Objects detected in set(s): {0} -# {0} - filters -SearchFiltering.ParentFilter.desc=Paths matching: {0} -SearchFiltering.ParentFilter.exact=(exact match) -SearchFiltering.ParentFilter.excluded=(excluded) -SearchFiltering.ParentFilter.included=(included) -SearchFiltering.ParentFilter.or=, -SearchFiltering.ParentFilter.substring=(substring) -SearchFiltering.ParentSearchTerm.excludeString=\ (exclude) -SearchFiltering.ParentSearchTerm.fullString=\ (exact) -SearchFiltering.ParentSearchTerm.includeString=\ (include) -SearchFiltering.ParentSearchTerm.subString=\ (substring) -# {0} - filters -SearchFiltering.ScoreFilter.desc=Score(s) of : {0} -# {0} - filters -SearchFiltering.SizeFilter.desc=Size(s): {0} -SearchFiltering.SizeFilter.or=, -SizeFilterPanel.sizeCheckbox.text=File Size: +VideoFilterPanel.videoFiltersSplitPane.border.title=Step 2: Filter which videos to show DataSourceFilterPanel.dataSourceCheckbox.text=Data Source: -UserCreatedFilterPanel.userCreatedCheckbox.text=Possibly User Created -# To change this license header, choose License Headers in Project Properties. -# To change this template file, choose Tools | Templates -# and open the template in the editor. -HashSetFilterPanel.hashSetCheckbox.text=Hash Set: -InterestingItemFilterPanel.interestingItemsCheckbox.text=Interesting Item: -ParentFolderFilterPanel.parentCheckbox.text=Parent Folder: -ParentFolderFilterPanel.deleteButton.text=Delete -ParentFolderFilterPanel.excludeRadioButton.text=Exclude -ParentFolderFilterPanel.includeRadioButton.text=Include -ParentFolderFilterPanel.substringRadioButton.text=Substring -ParentFolderFilterPanel.fullRadioButton.text=Full -ParentFolderFilterPanel.parentLabel.text=(All will be used) -ParentFolderFilterPanel.addButton.text=Add +ParentFolderFilterPanel.parentLabel.text_1=(All will be used) ParentFolderFilterPanel.parentCheckbox.text_1=Parent Folder: ParentFolderFilterPanel.addButton.text_1=Add ParentFolderFilterPanel.deleteButton.text_1=Delete @@ -255,33 +76,37 @@ ParentFolderFilterPanel.excludeRadioButton.text_1=Exclude ParentFolderFilterPanel.substringRadioButton.text_1=Substring ParentFolderFilterPanel.includeRadioButton.text_1=Include ParentFolderFilterPanel.fullRadioButton.text_1=Full -ParentFolderFilterPanel.parentLabel.text_1=(All will be used) -InterestingItemsFilterPanel.interestingItemsCheckbox.text=Interesting Item: UserCreatedFilterPanel.userCreatedCheckbox.text_1=Possibly User Created -PastOccurrencesFilterPanel.pastOccurrencesCheckbox.text=Past Occurrences: -ObjectDetectedFilterPanel.text=Object Detected: -DiscoveryDialog.sortingPanel.border.title=Step 3: Choose display settings -DiscoveryDialog.groupByLabel.text=Group By: -DiscoveryDialog.orderByLabel.text=Order Within Groups By: -DiscoveryDialog.orderGroupsByLabel.text=Order Groups By: -ImageFilterPanel.imageFiltersSplitPane.toolTipText= -DocumentFilterPanel.documentsFiltersSplitPane.border.title=Step 2: Filter which documents to show -ImageFilterPanel.imageFiltersSplitPane.border.title=Step 2: Filter which images to show -VideoFilterPanel.videoFiltersSplitPane.border.title=Step 2: Filter which videos to show -DiscoveryDialog.step1Label.text=Step 1: Choose result type -ResultsSplitPaneDivider.hideButton.text= -ResultsSplitPaneDivider.showButton.text= +GroupListPanel.groupKeyList.border.title=Groups ResultsSplitPaneDivider.detailsLabel.text=Details Area -DiscoveryDialog.domainsButton.text=Domains -DomainFilterPanel.domainFiltersSplitPane.border.title=Step 2: Filter which domains to show -DomainFilterPanel.domainFiltersSplitPane.toolTipText= -DateFilterPanel.dateFilterCheckbox.text=Date Filter: +ResultsSplitPaneDivider.showButton.text= +ResultsSplitPaneDivider.hideButton.text= +ImageFilterPanel.imageFiltersSplitPane.toolTipText= +ImageFilterPanel.imageFiltersSplitPane.border.title=Step 2: Filter which images to show ArtifactTypeFilterPanel.artifactTypeCheckbox.text=Artifact Type: -DomainUniquenessFilterPanel.domainUniquenessCheckbox.text=Domain Uniqueness: -DateFilterPanel.mostRecentButton.text=Only last: -DateFilterPanel.daysLabel.text=days of activity +InterestingItemsFilterPanel.interestingItemsCheckbox.text=Interesting Item: +DocumentPanel.fileSizeLabel.toolTipText= +DocumentPanel.isDeletedLabel.toolTipText= +DomainFilterPanel.domainFiltersSplitPane.toolTipText= +DomainFilterPanel.domainFiltersSplitPane.border.title=Step 2: Filter which domains to show +SizeFilterPanel.sizeCheckbox.text=File Size: +DateFilterPanel.dateFilterCheckbox.text=Date Filter: DateFilterPanel.endCheckBox.text=End: DateFilterPanel.startCheckBox.text=Start: +DateFilterPanel.mostRecentButton.text=Only last: +DateFilterPanel.daysLabel.text=days of activity +ImageThumbnailPanel.isDeletedLabel.toolTipText= +ResultsPanel.pageControlsLabel.text=Pages: +ResultsPanel.currentPageLabel.text=Page: - +ResultsPanel.pageSizeLabel.text=Page Size: +ResultsPanel.gotoPageLabel.text=Go to Page: +# To change this license header, choose License Headers in Project Properties. +# To change this template file, choose Tools | Templates +# and open the template in the editor. +HashSetFilterPanel.hashSetCheckbox.text=Hash Set: +PastOccurrencesFilterPanel.pastOccurrencesCheckbox.text=Past Occurrences: +DocumentFilterPanel.documentsFiltersSplitPane.border.title=Step 2: Filter which documents to show +DetailsPanel.instancesList.border.title=Instances VideoThumbnailPanel.bytes.text=bytes VideoThumbnailPanel.deleted.text=All instances of file are deleted. VideoThumbnailPanel.gigaBytes.text=GB diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java index 20fead3473..26de95c390 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java @@ -23,10 +23,11 @@ import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; -import org.sleuthkit.autopsy.discovery.FileSearchData; -import org.sleuthkit.autopsy.discovery.FileSearchData.Frequency; -import org.sleuthkit.autopsy.discovery.SearchData.ResultType; -import org.sleuthkit.autopsy.discovery.SearchFiltering; +import org.sleuthkit.autopsy.discovery.search.AbstractFilter; +import org.sleuthkit.autopsy.discovery.search.FileSearchData; +import org.sleuthkit.autopsy.discovery.search.FileSearchData.Frequency; +import org.sleuthkit.autopsy.discovery.search.SearchData.ResultType; +import org.sleuthkit.autopsy.discovery.search.SearchFiltering; /** * Panel to allow configuration of the Past Occurrences filter. From 8a55650f2f60dbc88799f9ad94cd50c886604777 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 17 Aug 2020 14:16:53 -0400 Subject: [PATCH 015/130] 6610 fix refactoring bug with attribute location --- Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java index 1ba77545de..9df5bd91b7 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java @@ -905,7 +905,7 @@ public class FileSearch { INTERESTING_ITEM_SET(new InterestingItemAttribute(), Bundle.FileSearch_GroupingAttributeType_interestingItem_displayName()), FILE_TAG(new FileTagAttribute(), Bundle.FileSearch_GroupingAttributeType_tag_displayName()), OBJECT_DETECTED(new ObjectDetectedAttribute(), Bundle.FileSearch_GroupingAttributeType_object_displayName()), - NO_GROUPING(new DiscoveryKeyUtils.NoGroupingAttribute(), Bundle.FileSearch_GroupingAttributeType_none_displayName()); + NO_GROUPING(new NoGroupingAttribute(), Bundle.FileSearch_GroupingAttributeType_none_displayName()); private final AttributeType attributeType; private final String displayName; From c6f9d946175a3f687c1e0306fa418cfd49ead55e Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 17 Aug 2020 14:40:02 -0400 Subject: [PATCH 016/130] 6610 attempt to fix moved top component --- .../autopsy/discovery/ui/Bundle.properties | 3 +- .../discovery/ui/Bundle.properties-MERGED | 29 ++++++++++--------- .../discovery/ui/DiscoveryTopComponent.java | 4 +-- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties index a2873c3d89..faa0025da5 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties @@ -1,7 +1,7 @@ # To change this license header, choose License Headers in Project Properties. # To change this template file, choose Tools | Templates # and open the template in the editor. - +ResultsPanel.currentPageLabel.text=Page: - DiscoveryDialog.sortingPanel.border.title=Step 3: Choose display settings DiscoveryDialog.searchButton.text=Search DiscoveryDialog.domainsButton.text=Domains @@ -52,4 +52,5 @@ ResultsPanel.gotoPageLabel.text=Go to Page: HashSetFilterPanel.hashSetCheckbox.text=Hash Set: PastOccurrencesFilterPanel.pastOccurrencesCheckbox.text=Past Occurrences: DocumentFilterPanel.documentsFiltersSplitPane.border.title=Step 2: Filter which documents to show +ObjectDetectedFilterPanel.text=Object Detected: DetailsPanel.instancesList.border.title=Instances diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED index 2de9ea3e1f..57cbd4cf00 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED @@ -1,7 +1,3 @@ -# To change this license header, choose License Headers in Project Properties. -# To change this template file, choose Tools | Templates -# and open the template in the editor. - CTL_OpenDiscoveryAction=Discovery # {0} - dataSourceName DataSourceModuleWrapper.exifModule.text=Exif Parser module was not run on data source: {0}\n @@ -12,16 +8,6 @@ DataSourceModuleWrapper.hashModule.text=Hash Lookup module was not run on data s # {0} - timeZone DateFilterPanel.dateRange.text=Date Range ({0}): DiscoveryDialog.name.text=Discovery -DiscoveryDialog.sortingPanel.border.title=Step 3: Choose display settings -DiscoveryDialog.searchButton.text=Search -DiscoveryDialog.domainsButton.text=Domains -DiscoveryDialog.groupByLabel.text=Group By: -DiscoveryDialog.step1Label.text=Step 1: Choose result type -DiscoveryDialog.orderByLabel.text=Order Within Groups By: -DiscoveryDialog.documentsButton.text=Documents -DiscoveryDialog.orderGroupsByLabel.text=Order Groups By: -DiscoveryDialog.videosButton.text=Videos -DiscoveryDialog.imagesButton.text=Images DiscoveryTopComponent.cancelButton.text=Cancel Search DiscoveryTopComponent.name=\ Discovery DiscoveryTopComponent.newSearch.text=New Search @@ -58,6 +44,20 @@ OpenDiscoveryAction.resultsIncomplete.text=Discovery results may be incomplete # {0} - currentPage # {1} - totalPages ResultsPanel.currentPage.displayValue=Page: {0} of {1} +# To change this license header, choose License Headers in Project Properties. +# To change this template file, choose Tools | Templates +# and open the template in the editor. +ResultsPanel.currentPageLabel.text=Page: - +DiscoveryDialog.sortingPanel.border.title=Step 3: Choose display settings +DiscoveryDialog.searchButton.text=Search +DiscoveryDialog.domainsButton.text=Domains +DiscoveryDialog.groupByLabel.text=Group By: +DiscoveryDialog.step1Label.text=Step 1: Choose result type +DiscoveryDialog.orderByLabel.text=Order Within Groups By: +DiscoveryDialog.documentsButton.text=Documents +DiscoveryDialog.orderGroupsByLabel.text=Order Groups By: +DiscoveryDialog.videosButton.text=Videos +DiscoveryDialog.imagesButton.text=Images ResultsPanel.documentPreview.text=Document preview creation cancelled. # {0} - selectedPage # {1} - maxPage @@ -106,6 +106,7 @@ ResultsPanel.gotoPageLabel.text=Go to Page: HashSetFilterPanel.hashSetCheckbox.text=Hash Set: PastOccurrencesFilterPanel.pastOccurrencesCheckbox.text=Past Occurrences: DocumentFilterPanel.documentsFiltersSplitPane.border.title=Step 2: Filter which documents to show +ObjectDetectedFilterPanel.text=Object Detected: DetailsPanel.instancesList.border.title=Instances VideoThumbnailPanel.bytes.text=bytes VideoThumbnailPanel.deleted.text=All instances of file are deleted. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java index 30a6a3a49a..a264019067 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java @@ -43,14 +43,14 @@ import org.sleuthkit.autopsy.discovery.search.SearchData.ResultType; /** * Create a dialog for displaying the Discovery results. */ -@TopComponent.Description(preferredID = "Discovery", persistenceType = TopComponent.PERSISTENCE_NEVER) +@TopComponent.Description(preferredID = "Discoverytc", persistenceType = TopComponent.PERSISTENCE_NEVER) @TopComponent.Registration(mode = "discovery", openAtStartup = false) @RetainLocation("discovery") @NbBundle.Messages("DiscoveryTopComponent.name= Discovery") public final class DiscoveryTopComponent extends TopComponent { private static final long serialVersionUID = 1L; - private static final String PREFERRED_ID = "Discovery"; // NON-NLS + private static final String PREFERRED_ID = "Discoverytc"; // NON-NLS private static final int ANIMATION_INCREMENT = 30; private volatile static int resultsAreaSize = 250; private final GroupListPanel groupListPanel; From f595bcb26b4ee2d6b5718b32b48a4bb09b038579 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 17 Aug 2020 14:49:10 -0400 Subject: [PATCH 017/130] 6639 specify that Domains arent files in past filter --- Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java index b6f4a0c42b..b1fd4646e2 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DomainFilterPanel.java @@ -41,7 +41,7 @@ public class DomainFilterPanel extends AbstractFiltersPanel { if (CentralRepository.isEnabled()) { pastOccurrencesIndices = new int[]{2, 3, 4}; } - addFilter(new PastOccurrencesFilterPanel(), true, pastOccurrencesIndices, 0); + addFilter(new PastOccurrencesFilterPanel(SearchData.ResultType.ATTRIBUTE), true, pastOccurrencesIndices, 0); addPanelsToScrollPane(domainFiltersSplitPane); } From 7b7391c976de91eb4d0e4c02024647009f9927c2 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 17 Aug 2020 14:54:02 -0400 Subject: [PATCH 018/130] 6639 remove options when past occurrences disabled --- .../autopsy/discovery/PastOccurrencesFilterPanel.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java index b6979fe9e4..9e425af280 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/PastOccurrencesFilterPanel.java @@ -110,9 +110,11 @@ final class PastOccurrencesFilterPanel extends AbstractDiscoveryFilterPanel { int count = 0; DefaultListModel frequencyListModel = (DefaultListModel) crFrequencyList.getModel(); frequencyListModel.removeAllElements(); - if (!CentralRepository.isEnabled() && type != ResultType.ATTRIBUTE) { - for (FileSearchData.Frequency freq : FileSearchData.Frequency.getOptionsForFilteringWithoutCr()) { - frequencyListModel.add(count, freq); + if (!CentralRepository.isEnabled()) { + if (type != ResultType.ATTRIBUTE) { + for (FileSearchData.Frequency freq : FileSearchData.Frequency.getOptionsForFilteringWithoutCr()) { + frequencyListModel.add(count, freq); + } } } else { for (FileSearchData.Frequency freq : FileSearchData.Frequency.getOptionsForFilteringWithCr()) { @@ -134,7 +136,7 @@ final class PastOccurrencesFilterPanel extends AbstractDiscoveryFilterPanel { boolean canBeFilteredOn = type == ResultType.FILE || CentralRepository.isEnabled(); pastOccurrencesCheckbox.setEnabled(canBeFilteredOn); pastOccurrencesCheckbox.setSelected(selected && canBeFilteredOn); - + if (pastOccurrencesCheckbox.isEnabled() && pastOccurrencesCheckbox.isSelected()) { crFrequencyScrollPane.setEnabled(true); crFrequencyList.setEnabled(true); From 744cb3dea6d444cff1eafb02996d4943861e6789 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 17 Aug 2020 16:30:56 -0400 Subject: [PATCH 019/130] 6610 fix topcomponent not found --- .../autopsy/discovery/ui/DiscoveryTopComponent.form | 4 ++-- .../autopsy/discovery/ui/DiscoveryTopComponent.java | 6 +++--- .../autopsy/discovery/ui/ResultsSplitPaneDivider.form | 6 +++--- .../autopsy/discovery/ui/ResultsSplitPaneDivider.java | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.form index 7917b19a1e..54630599ec 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.form @@ -105,8 +105,8 @@ - - + + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java index a264019067..be6edc83ea 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java @@ -43,14 +43,14 @@ import org.sleuthkit.autopsy.discovery.search.SearchData.ResultType; /** * Create a dialog for displaying the Discovery results. */ -@TopComponent.Description(preferredID = "Discoverytc", persistenceType = TopComponent.PERSISTENCE_NEVER) +@TopComponent.Description(preferredID = "Discovery", persistenceType = TopComponent.PERSISTENCE_NEVER) @TopComponent.Registration(mode = "discovery", openAtStartup = false) @RetainLocation("discovery") @NbBundle.Messages("DiscoveryTopComponent.name= Discovery") public final class DiscoveryTopComponent extends TopComponent { private static final long serialVersionUID = 1L; - private static final String PREFERRED_ID = "Discoverytc"; // NON-NLS + private static final String PREFERRED_ID = "Discovery"; // NON-NLS private static final int ANIMATION_INCREMENT = 30; private volatile static int resultsAreaSize = 250; private final GroupListPanel groupListPanel; @@ -184,7 +184,7 @@ public final class DiscoveryTopComponent extends TopComponent { add(mainSplitPane, java.awt.BorderLayout.CENTER); - org.openide.awt.Mnemonics.setLocalizedText(newSearchButton, org.openide.util.NbBundle.getMessage(DiscoveryTopComponent.class, "FileSearchDialog.cancelButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(newSearchButton, Bundle.DiscoveryTopComponent_cancelButton_text()); newSearchButton.setMaximumSize(new java.awt.Dimension(110, 26)); newSearchButton.setMinimumSize(new java.awt.Dimension(110, 26)); newSearchButton.setPreferredSize(new java.awt.Dimension(110, 26)); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.form index a61f5a9c93..864e5d198c 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.form @@ -24,7 +24,7 @@ - + @@ -66,7 +66,7 @@ - + @@ -91,7 +91,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.java index 251ed4cb94..6a08f681e4 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.java @@ -55,7 +55,7 @@ final class ResultsSplitPaneDivider extends javax.swing.JPanel { org.openide.awt.Mnemonics.setLocalizedText(detailsLabel, org.openide.util.NbBundle.getMessage(ResultsSplitPaneDivider.class, "ResultsSplitPaneDivider.detailsLabel.text")); // NOI18N detailsLabel.setFocusable(false); - hideButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/discovery/arrow-down.png"))); // NOI18N + hideButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/discovery/ui/arrow-down.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(hideButton, org.openide.util.NbBundle.getMessage(ResultsSplitPaneDivider.class, "ResultsSplitPaneDivider.hideButton.text")); // NOI18N hideButton.setBorder(null); hideButton.setFocusable(false); @@ -67,7 +67,7 @@ final class ResultsSplitPaneDivider extends javax.swing.JPanel { } }); - showButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/discovery/arrow-up.png"))); // NOI18N + showButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/discovery/ui/arrow-up.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(showButton, org.openide.util.NbBundle.getMessage(ResultsSplitPaneDivider.class, "ResultsSplitPaneDivider.showButton.text")); // NOI18N showButton.setBorder(null); showButton.setFocusable(false); @@ -86,7 +86,7 @@ final class ResultsSplitPaneDivider extends javax.swing.JPanel { .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(detailsLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 251, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 199, Short.MAX_VALUE) .addComponent(showButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(hideButton) From 0ffabe2a6cda8e239acf729a52352b5a4c670576 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 17 Aug 2020 16:50:12 -0400 Subject: [PATCH 020/130] 6610 get top component working again --- .../sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java index be6edc83ea..96bcea63d6 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java @@ -43,14 +43,14 @@ import org.sleuthkit.autopsy.discovery.search.SearchData.ResultType; /** * Create a dialog for displaying the Discovery results. */ -@TopComponent.Description(preferredID = "Discovery", persistenceType = TopComponent.PERSISTENCE_NEVER) +@TopComponent.Description(preferredID = "DiscoveryTc", persistenceType = TopComponent.PERSISTENCE_NEVER) @TopComponent.Registration(mode = "discovery", openAtStartup = false) @RetainLocation("discovery") @NbBundle.Messages("DiscoveryTopComponent.name= Discovery") public final class DiscoveryTopComponent extends TopComponent { private static final long serialVersionUID = 1L; - private static final String PREFERRED_ID = "Discovery"; // NON-NLS + private static final String PREFERRED_ID = "DiscoveryTc"; // NON-NLS private static final int ANIMATION_INCREMENT = 30; private volatile static int resultsAreaSize = 250; private final GroupListPanel groupListPanel; From 9e9d9c7b9fb0e52eb5a35501d69046e1a6812dcf Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 18 Aug 2020 10:18:02 -0400 Subject: [PATCH 021/130] 6610 fix size of discoverydialog --- .../org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.form | 3 +++ .../org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java | 1 + 2 files changed, 4 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.form index 522cd9b43e..e24e6f6a3b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.form @@ -6,6 +6,9 @@ + + + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index 0135ad651c..face0f1c97 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -306,6 +306,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); setMinimumSize(new java.awt.Dimension(600, 300)); + setPreferredSize(new java.awt.Dimension(1000, 650)); imagesButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/pictures-icon.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(imagesButton, org.openide.util.NbBundle.getMessage(DiscoveryDialog.class, "DiscoveryDialog.imagesButton.text")); // NOI18N From 98e790c4e6eef5de353412d276f55e9e4dc9ea46 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 20 Aug 2020 13:21:49 -0400 Subject: [PATCH 022/130] 6711 initial commit for more general data model refactor --- .../discovery/search/AbstractFilter.java | 4 +- .../discovery/search/AttributeSearchData.java | 96 ---- .../discovery/search/DiscoveryEventUtils.java | 58 +-- ...Exception.java => DiscoveryException.java} | 6 +- .../discovery/search/DiscoveryKeyUtils.java | 20 +- .../discovery/search/DomainSearch.java | 30 ++ .../autopsy/discovery/search/FileSearch.java | 58 +-- .../discovery/search/FileSearchData.java | 441 ------------------ .../search/{FileGroup.java => Group.java} | 12 +- .../autopsy/discovery/search/Result.java | 26 ++ .../discovery/search/ResultDomain.java | 24 + .../autopsy/discovery/search/ResultFile.java | 39 +- .../autopsy/discovery/search/SearchData.java | 411 +++++++++++++++- .../discovery/search/SearchFiltering.java | 42 +- .../discovery/search/SearchResults.java | 22 +- .../discovery/ui/AbstractFiltersPanel.java | 28 +- .../discovery/ui/ArtifactTypeFilterPanel.java | 4 +- .../autopsy/discovery/ui/DiscoveryDialog.java | 68 +-- .../discovery/ui/DiscoveryTopComponent.java | 9 +- .../discovery/ui/DocumentFilterPanel.java | 22 +- .../autopsy/discovery/ui/DocumentPanel.java | 4 +- .../discovery/ui/DomainFilterPanel.java | 19 +- .../autopsy/discovery/ui/GroupListPanel.java | 12 +- .../discovery/ui/ImageFilterPanel.java | 21 +- .../autopsy/discovery/ui/PageWorker.java | 16 +- .../ui/PastOccurrencesFilterPanel.java | 31 +- .../autopsy/discovery/ui/ResultsPanel.java | 14 +- .../autopsy/discovery/ui/SearchWorker.java | 10 +- .../autopsy/discovery/ui/SizeFilterPanel.java | 10 +- .../discovery/ui/VideoFilterPanel.java | 22 +- 30 files changed, 696 insertions(+), 883 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/discovery/search/AttributeSearchData.java rename Core/src/org/sleuthkit/autopsy/discovery/search/{FileSearchException.java => DiscoveryException.java} (88%) create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java delete mode 100644 Core/src/org/sleuthkit/autopsy/discovery/search/FileSearchData.java rename Core/src/org/sleuthkit/autopsy/discovery/search/{FileGroup.java => Group.java} (91%) create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/search/Result.java create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/search/ResultDomain.java diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java b/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java index 7ed3d54edd..d31fe246b0 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java @@ -59,10 +59,10 @@ public abstract class AbstractFilter { * @return The list of results that match this filter (and any that came * before it) * - * @throws FileSearchException + * @throws DiscoveryException */ public List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws FileSearchException { + CentralRepository centralRepoDb) throws DiscoveryException { return new ArrayList<>(); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/AttributeSearchData.java b/Core/src/org/sleuthkit/autopsy/discovery/search/AttributeSearchData.java deleted file mode 100644 index 322a11867c..0000000000 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/AttributeSearchData.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Autopsy - * - * 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.discovery.search; - -import java.util.Collection; -import java.util.Collections; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.Set; -import org.openide.util.NbBundle; -import org.sleuthkit.datamodel.BlackboardArtifact; - -/** - * Utility enums for searches made for attributes with Discovery. - */ -public class AttributeSearchData implements SearchData { - - private static final Set DOMAIN_ARTIFACT_TYPES = EnumSet.of(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY, BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG); - - @Override - public ResultType getResultType() { - return ResultType.ATTRIBUTE; - } - - /** - * Enum representing the attribute type. - */ - @NbBundle.Messages({ - "AttributeSearchData.AttributeType.Domain.displayName=Domain", - "AttributeSearchData.AttributeType.Other.displayName=Other"}) - public enum AttributeType { - - DOMAIN(0, Bundle.AttributeSearchData_AttributeType_Domain_displayName(), DOMAIN_ARTIFACT_TYPES), - OTHER(1, Bundle.AttributeSearchData_AttributeType_Other_displayName(), new HashSet<>()); - - private final int ranking; // For ordering in the UI - private final String displayName; - private final Set artifactTypes = new HashSet<>(); - - AttributeType(int value, String displayName, Set types) { - this.ranking = value; - this.displayName = displayName; - this.artifactTypes.addAll(types); - } - - /** - * Get the BlackboardArtifact types matching this category. - * - * @return Collection of BlackboardArtifact types. - */ - public Collection getBlackboardTypes() { - return Collections.unmodifiableCollection(artifactTypes); - } - - @Override - public String toString() { - return displayName; - } - - /** - * Get the rank for sorting. - * - * @return the rank (lower should be displayed first) - */ - public int getRanking() { - return ranking; - } - - public static AttributeType fromBlackboardArtifact(final BlackboardArtifact.ARTIFACT_TYPE type) { - switch (type) { - case TSK_WEB_BOOKMARK: - return DOMAIN; - default: - return OTHER; - } - } - - } - -} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java index 01b2606b42..5bd5d81ef0 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java @@ -22,10 +22,8 @@ import com.google.common.eventbus.EventBus; import java.util.Collections; import java.util.List; import java.util.Map; -import org.sleuthkit.autopsy.discovery.search.AttributeSearchData.AttributeType; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; -import org.sleuthkit.autopsy.discovery.search.FileSearchData.FileType; -import org.sleuthkit.autopsy.discovery.search.SearchData.ResultType; +import org.sleuthkit.autopsy.discovery.search.SearchData.Type; import org.sleuthkit.datamodel.AbstractFile; /** @@ -56,47 +54,27 @@ public final class DiscoveryEventUtils { */ public static final class SearchStartedEvent { - private final ResultType resultType; - private final FileType fileType; - private final AttributeType attributeType; + private final Type type; /** * Construct a new SearchStartedEvent * * @param type The type of file the search event is for. */ - public SearchStartedEvent(ResultType resultType, FileType fileType, AttributeType attributeType) { - this.resultType = resultType; - this.fileType = fileType; - this.attributeType = attributeType; + public SearchStartedEvent(Type type) { + this.type = type; } - /** - * Get the broad search type. - * - * @return The result type, either FILES, or ATTRIBUTES. - */ - public ResultType getResultType() { - return resultType; - } /** * Get the type of file the search is being performed for. * * @return The type of files being searched for. */ - public FileType getFileType() { - return fileType; + public Type getType() { + return type; } - /** - * Get the type of attribute the search is being performed for. - * - * @return The type of attribute being searched for. - */ - public AttributeType getAttributeType() { - return attributeType; - } } /** @@ -142,7 +120,7 @@ public final class DiscoveryEventUtils { private final Map groupMap; private final List searchFilters; private final FileSearch.AttributeType groupingAttribute; - private final FileGroup.GroupSortingAlgorithm groupSort; + private final Group.GroupSortingAlgorithm groupSort; private final FileSorter.SortingMethod fileSortMethod; /** @@ -157,7 +135,7 @@ public final class DiscoveryEventUtils { * @param fileSortMethod The sorting method used for files. */ public SearchCompleteEvent(Map groupMap, List searchfilters, - FileSearch.AttributeType groupingAttribute, FileGroup.GroupSortingAlgorithm groupSort, + FileSearch.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod) { this.groupMap = groupMap; this.searchFilters = searchfilters; @@ -198,7 +176,7 @@ public final class DiscoveryEventUtils { * * @return The sorting algorithm used for groups. */ - public FileGroup.GroupSortingAlgorithm getGroupSort() { + public Group.GroupSortingAlgorithm getGroupSort() { return groupSort; } @@ -221,7 +199,7 @@ public final class DiscoveryEventUtils { private final List results; private final int page; - private final FileType resultType; + private final Type resultType; /** * Construct a new PageRetrievedEvent. @@ -230,7 +208,7 @@ public final class DiscoveryEventUtils { * @param page The number of the page which was retrieved. * @param results The list of files in the page retrieved. */ - public PageRetrievedEvent(FileType resultType, int page, List results) { + public PageRetrievedEvent(Type resultType, int page, List results) { this.results = results; this.page = page; this.resultType = resultType; @@ -259,7 +237,7 @@ public final class DiscoveryEventUtils { * * @return The type of files which exist in the page. */ - public FileType getType() { + public Type getType() { return resultType; } } @@ -296,12 +274,12 @@ public final class DiscoveryEventUtils { */ public static final class GroupSelectedEvent { - private final FileType resultType; + private final Type resultType; private final GroupKey groupKey; private final int groupSize; private final List searchfilters; private final FileSearch.AttributeType groupingAttribute; - private final FileGroup.GroupSortingAlgorithm groupSort; + private final Group.GroupSortingAlgorithm groupSort; private final FileSorter.SortingMethod fileSortMethod; /** @@ -319,8 +297,8 @@ public final class DiscoveryEventUtils { * @param resultType The type of files which exist in the group. */ public GroupSelectedEvent(List searchfilters, - FileSearch.AttributeType groupingAttribute, FileGroup.GroupSortingAlgorithm groupSort, - FileSorter.SortingMethod fileSortMethod, GroupKey groupKey, int groupSize, FileType resultType) { + FileSearch.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, + FileSorter.SortingMethod fileSortMethod, GroupKey groupKey, int groupSize, Type resultType) { this.searchfilters = searchfilters; this.groupingAttribute = groupingAttribute; this.groupSort = groupSort; @@ -335,7 +313,7 @@ public final class DiscoveryEventUtils { * * @return The type of files which exist in the group. */ - public FileType getResultType() { + public Type getResultType() { return resultType; } @@ -364,7 +342,7 @@ public final class DiscoveryEventUtils { * * @return The sorting algorithm used for groups. */ - public FileGroup.GroupSortingAlgorithm getGroupSort() { + public Group.GroupSortingAlgorithm getGroupSort() { return groupSort; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearchException.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryException.java similarity index 88% rename from Core/src/org/sleuthkit/autopsy/discovery/search/FileSearchException.java rename to Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryException.java index a637bf43eb..8616351c21 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearchException.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryException.java @@ -21,7 +21,7 @@ package org.sleuthkit.autopsy.discovery.search; /** * Exception type used for FileSearch. */ -final public class FileSearchException extends Exception { +final public class DiscoveryException extends Exception { private static final long serialVersionUID = 1L; @@ -30,7 +30,7 @@ final public class FileSearchException extends Exception { * * @param message The message to associate with this exception. */ - FileSearchException(String message) { + DiscoveryException(String message) { super(message); } @@ -40,7 +40,7 @@ final public class FileSearchException extends Exception { * @param message The message to associate with this exception. * @param cause The Throwable cause of the exception. */ - FileSearchException(String message, Throwable cause) { + DiscoveryException(String message, Throwable cause) { super(message, cause); } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java index 118dd6e815..481d354b8f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java @@ -53,7 +53,7 @@ public class DiscoveryKeyUtils { */ SearchKey(String userName, List filters, FileSearch.AttributeType groupAttributeType, - FileGroup.GroupSortingAlgorithm groupSortingType, + Group.GroupSortingAlgorithm groupSortingType, FileSorter.SortingMethod fileSortingMethod) { StringBuilder searchStringBuilder = new StringBuilder(); searchStringBuilder.append(userName); @@ -153,13 +153,13 @@ public class DiscoveryKeyUtils { */ static class FileSizeGroupKey extends GroupKey { - private final FileSearchData.FileSize fileSize; + private final SearchData.FileSize fileSize; FileSizeGroupKey(ResultFile file) { - if (file.getFileType() == FileSearchData.FileType.VIDEO) { - fileSize = FileSearchData.FileSize.fromVideoSize(file.getFirstInstance().getSize()); + if (file.getFileType() == SearchData.Type.VIDEO) { + fileSize = SearchData.FileSize.fromVideoSize(file.getFirstInstance().getSize()); } else { - fileSize = FileSearchData.FileSize.fromImageSize(file.getFirstInstance().getSize()); + fileSize = SearchData.FileSize.fromImageSize(file.getFirstInstance().getSize()); } } @@ -200,7 +200,7 @@ public class DiscoveryKeyUtils { /** * @return the fileSize */ - FileSearchData.FileSize getFileSize() { + SearchData.FileSize getFileSize() { return fileSize; } } @@ -210,7 +210,7 @@ public class DiscoveryKeyUtils { */ static class FileTypeGroupKey extends GroupKey { - private final FileSearchData.FileType fileType; + private final SearchData.Type fileType; FileTypeGroupKey(ResultFile file) { fileType = file.getFileType(); @@ -253,7 +253,7 @@ public class DiscoveryKeyUtils { /** * @return the fileType */ - FileSearchData.FileType getFileType() { + SearchData.Type getFileType() { return fileType; } } @@ -644,7 +644,7 @@ public class DiscoveryKeyUtils { */ static class FrequencyGroupKey extends GroupKey { - private final FileSearchData.Frequency frequency; + private final SearchData.Frequency frequency; FrequencyGroupKey(ResultFile file) { frequency = file.getFrequency(); @@ -687,7 +687,7 @@ public class DiscoveryKeyUtils { /** * @return the frequency */ - FileSearchData.Frequency getFrequency() { + SearchData.Frequency getFrequency() { return frequency; } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java new file mode 100644 index 0000000000..69843e0708 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java @@ -0,0 +1,30 @@ +/* + * Autopsy + * + * 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.discovery.search; + +/** + * Main class to perform the domain search. + */ +public class DomainSearch { + + private DomainSearch() { + // Class should not be instantiated + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java index 9df5bd91b7..625f2140bd 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java @@ -40,7 +40,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.InstanceTableCallback; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.discovery.search.FileSearchData.Frequency; +import org.sleuthkit.autopsy.discovery.search.SearchData.Frequency; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -82,14 +82,14 @@ public class FileSearch { * * @return The raw search results * - * @throws FileSearchException + * @throws DiscoveryException */ static SearchResults runFileSearchDebug(String userName, List filters, AttributeType groupAttributeType, - FileGroup.GroupSortingAlgorithm groupSortingType, + Group.GroupSortingAlgorithm groupSortingType, FileSorter.SortingMethod fileSortingMethod, - SleuthkitCase caseDb, CentralRepository centralRepoDb) throws FileSearchException { + SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { // Make a list of attributes that we want to add values for. This ensures the // ResultFile objects will have all needed fields set when it's time to group // and sort them. For example, if we're grouping by central repo frequency, we need @@ -134,14 +134,14 @@ public class FileSearch { * * @return A LinkedHashMap grouped and sorted according to the parameters * - * @throws FileSearchException + * @throws DiscoveryException */ public static Map getGroupSizes(String userName, List filters, AttributeType groupAttributeType, - FileGroup.GroupSortingAlgorithm groupSortingType, + Group.GroupSortingAlgorithm groupSortingType, FileSorter.SortingMethod fileSortingMethod, - SleuthkitCase caseDb, CentralRepository centralRepoDb) throws FileSearchException { + SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { Map> searchResults = runFileSearch(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod, caseDb, centralRepoDb); LinkedHashMap groupSizes = new LinkedHashMap<>(); @@ -171,17 +171,17 @@ public class FileSearch { * * @return A LinkedHashMap grouped and sorted according to the parameters * - * @throws FileSearchException + * @throws DiscoveryException */ public static List getFilesInGroup(String userName, List filters, AttributeType groupAttributeType, - FileGroup.GroupSortingAlgorithm groupSortingType, + Group.GroupSortingAlgorithm groupSortingType, FileSorter.SortingMethod fileSortingMethod, GroupKey groupKey, int startingEntry, int numberOfEntries, - SleuthkitCase caseDb, CentralRepository centralRepoDb) throws FileSearchException { + SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { //the group should be in the cache at this point List filesInGroup = null; SearchKey searchKey = new SearchKey(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod); @@ -267,14 +267,14 @@ public class FileSearch { * * @return A LinkedHashMap grouped and sorted according to the parameters * - * @throws FileSearchException + * @throws DiscoveryException */ private static Map> runFileSearch(String userName, List filters, AttributeType groupAttributeType, - FileGroup.GroupSortingAlgorithm groupSortingType, + Group.GroupSortingAlgorithm groupSortingType, FileSorter.SortingMethod fileSortingMethod, - SleuthkitCase caseDb, CentralRepository centralRepoDb) throws FileSearchException { + SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { // Make a list of attributes that we want to add values for. This ensures the // ResultFile objects will have all needed fields set when it's time to group @@ -313,10 +313,10 @@ public class FileSearch { * @param centralRepoDb The central repository database. Can be null if not * needed. * - * @throws FileSearchException + * @throws DiscoveryException */ private static void addAttributes(List attrs, List resultFiles, SleuthkitCase caseDb, CentralRepository centralRepoDb) - throws FileSearchException { + throws DiscoveryException { for (AttributeType attr : attrs) { attr.addAttributeToResultFiles(resultFiles, caseDb, centralRepoDb); } @@ -357,7 +357,7 @@ public class FileSearch { } private static String createSetNameClause(List files, - int artifactTypeID, int setNameAttrID) throws FileSearchException { + int artifactTypeID, int setNameAttrID) throws DiscoveryException { // Concatenate the object IDs in the list of files String objIdList = ""; // NON-NLS @@ -405,9 +405,9 @@ public class FileSearch { * @param centralRepoDb The central repository database. Can be null if * not needed. * - * @throws FileSearchException + * @throws DiscoveryException */ - public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws FileSearchException { + public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { // Default is to do nothing } } @@ -479,7 +479,7 @@ public class FileSearch { @Override public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws FileSearchException { + CentralRepository centralRepoDb) throws DiscoveryException { // Get pairs of (object ID, keyword list name) for all files in the list of files that have // keyword list hits. @@ -490,7 +490,7 @@ public class FileSearch { try { caseDb.getCaseDbAccessManager().select(selectQuery, callback); } catch (TskCoreException ex) { - throw new FileSearchException("Error looking up keyword list attributes", ex); // NON-NLS + throw new DiscoveryException("Error looking up keyword list attributes", ex); // NON-NLS } } @@ -553,7 +553,7 @@ public class FileSearch { @Override public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws FileSearchException { + CentralRepository centralRepoDb) throws DiscoveryException { if (centralRepoDb == null) { for (ResultFile file : files) { if (file.getFrequency() == Frequency.UNKNOWN && file.getFirstInstance().getKnown() == TskData.FileKnown.KNOWN) { @@ -648,7 +648,7 @@ public class FileSearch { @Override public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws FileSearchException { + CentralRepository centralRepoDb) throws DiscoveryException { // Get pairs of (object ID, hash set name) for all files in the list of files that have // hash set hits. @@ -659,7 +659,7 @@ public class FileSearch { try { caseDb.getCaseDbAccessManager().select(selectQuery, callback); } catch (TskCoreException ex) { - throw new FileSearchException("Error looking up hash set attributes", ex); // NON-NLS + throw new DiscoveryException("Error looking up hash set attributes", ex); // NON-NLS } } @@ -719,7 +719,7 @@ public class FileSearch { @Override public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws FileSearchException { + CentralRepository centralRepoDb) throws DiscoveryException { // Get pairs of (object ID, interesting item set name) for all files in the list of files that have // interesting file set hits. @@ -730,7 +730,7 @@ public class FileSearch { try { caseDb.getCaseDbAccessManager().select(selectQuery, callback); } catch (TskCoreException ex) { - throw new FileSearchException("Error looking up interesting file set attributes", ex); // NON-NLS + throw new DiscoveryException("Error looking up interesting file set attributes", ex); // NON-NLS } } @@ -792,7 +792,7 @@ public class FileSearch { @Override public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws FileSearchException { + CentralRepository centralRepoDb) throws DiscoveryException { // Get pairs of (object ID, object type name) for all files in the list of files that have // objects detected @@ -803,7 +803,7 @@ public class FileSearch { try { caseDb.getCaseDbAccessManager().select(selectQuery, callback); } catch (TskCoreException ex) { - throw new FileSearchException("Error looking up object detected attributes", ex); // NON-NLS + throw new DiscoveryException("Error looking up object detected attributes", ex); // NON-NLS } } @@ -864,7 +864,7 @@ public class FileSearch { @Override public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws FileSearchException { + CentralRepository centralRepoDb) throws DiscoveryException { try { for (ResultFile resultFile : files) { @@ -875,7 +875,7 @@ public class FileSearch { } } } catch (TskCoreException ex) { - throw new FileSearchException("Error looking up file tag attributes", ex); // NON-NLS + throw new DiscoveryException("Error looking up file tag attributes", ex); // NON-NLS } } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearchData.java b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearchData.java deleted file mode 100644 index acd8fae2ea..0000000000 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearchData.java +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2019 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.discovery.search; - -import com.google.common.collect.ImmutableSet; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.coreutils.FileTypeUtils; - -/** - * Utility enums for searches made for files with Discovery. - */ -public final class FileSearchData implements SearchData { - - private final static long BYTES_PER_MB = 1000000; - - @Override - public ResultType getResultType() { - return ResultType.FILE; - } - - /** - * Enum representing how often the file occurs in the Central Repository. - */ - @NbBundle.Messages({ - "FileSearchData.Frequency.unique.displayName=Unique (1)", - "FileSearchData.Frequency.rare.displayName=Rare (2-10)", - "FileSearchData.Frequency.common.displayName=Common (11 - 100)", - "FileSearchData.Frequency.verycommon.displayName=Very Common (100+)", - "FileSearchData.Frequency.known.displayName=Known (NSRL)", - "FileSearchData.Frequency.unknown.displayName=Unknown",}) - public enum Frequency { - UNIQUE(0, 1, Bundle.FileSearchData_Frequency_unique_displayName()), - RARE(1, 10, Bundle.FileSearchData_Frequency_rare_displayName()), - COMMON(2, 100, Bundle.FileSearchData_Frequency_common_displayName()), - VERY_COMMON(3, 0, Bundle.FileSearchData_Frequency_verycommon_displayName()), - KNOWN(4, 0, Bundle.FileSearchData_Frequency_known_displayName()), - UNKNOWN(5, 0, Bundle.FileSearchData_Frequency_unknown_displayName()); - - private final int ranking; - private final String displayName; - private final int maxOccur; - - Frequency(int ranking, int maxOccur, String displayName) { - this.ranking = ranking; - this.maxOccur = maxOccur; - this.displayName = displayName; - } - - /** - * Get the rank for sorting. - * - * @return the rank (lower should be displayed first) - */ - public int getRanking() { - return ranking; - } - - /** - * Get the enum matching the given occurrence count. - * - * @param count Number of times a file is in the Central Repository. - * - * @return the corresponding enum - */ - public static Frequency fromCount(long count) { - if (count <= UNIQUE.getMaxOccur()) { - return UNIQUE; - } else if (count <= RARE.getMaxOccur()) { - return RARE; - } else if (count <= COMMON.getMaxOccur()) { - return COMMON; - } - return VERY_COMMON; - } - - /** - * Get the list of enums that are valid for filtering when a CR is - * enabled. - * - * @return enums that can be used to filter with a CR. - */ - public static List getOptionsForFilteringWithCr() { - return Arrays.asList(UNIQUE, RARE, COMMON, VERY_COMMON, KNOWN); - } - - /** - * Get the list of enums that are valid for filtering when no CR is - * enabled. - * - * @return enums that can be used to filter without a CR. - */ - public static List getOptionsForFilteringWithoutCr() { - return Arrays.asList(KNOWN, UNKNOWN); - } - - @Override - public String toString() { - return displayName; - } - - /** - * @return the maxOccur - */ - public int getMaxOccur() { - return maxOccur; - } - } - - /** - * Enum representing the file size - */ - @NbBundle.Messages({ - "FileSearchData.FileSize.XXLARGE.displayName=XXLarge", - "FileSearchData.FileSize.XLARGE.displayName=XLarge", - "FileSearchData.FileSize.LARGE.displayName=Large", - "FileSearchData.FileSize.MEDIUM.displayName=Medium", - "FileSearchData.FileSize.SMALL.displayName=Small", - "FileSearchData.FileSize.XSMALL.displayName=XSmall", - "FileSearchData.FileSize.10PlusGb=: 10GB+", - "FileSearchData.FileSize.5gbto10gb=: 5-10GB", - "FileSearchData.FileSize.1gbto5gb=: 1-5GB", - "FileSearchData.FileSize.100mbto1gb=: 100MB-1GB", - "FileSearchData.FileSize.200PlusMb=: 200MB+", - "FileSearchData.FileSize.50mbto200mb=: 50-200MB", - "FileSearchData.FileSize.500kbto100mb=: 500KB-100MB", - "FileSearchData.FileSize.1mbto50mb=: 1-50MB", - "FileSearchData.FileSize.100kbto1mb=: 100KB-1MB", - "FileSearchData.FileSize.16kbto100kb=: 16-100KB", - "FileSearchData.FileSize.upTo500kb=: 0-500KB", - "FileSearchData.FileSize.upTo16kb=: 0-16KB",}) - public enum FileSize { - XXLARGE_VIDEO(0, 10000 * BYTES_PER_MB, -1, Bundle.FileSearchData_FileSize_XXLARGE_displayName(), Bundle.FileSearchData_FileSize_10PlusGb()), - XLARGE_VIDEO(1, 5000 * BYTES_PER_MB, 10000 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_XLARGE_displayName(), Bundle.FileSearchData_FileSize_5gbto10gb()), - LARGE_VIDEO(2, 1000 * BYTES_PER_MB, 5000 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_LARGE_displayName(), Bundle.FileSearchData_FileSize_1gbto5gb()), - MEDIUM_VIDEO(3, 100 * BYTES_PER_MB, 1000 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_MEDIUM_displayName(), Bundle.FileSearchData_FileSize_100mbto1gb()), - SMALL_VIDEO(4, 500000, 100 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_SMALL_displayName(), Bundle.FileSearchData_FileSize_500kbto100mb()), - XSMALL_VIDEO(5, 0, 500000, Bundle.FileSearchData_FileSize_XSMALL_displayName(), Bundle.FileSearchData_FileSize_upTo500kb()), - XXLARGE_IMAGE(6, 200 * BYTES_PER_MB, -1, Bundle.FileSearchData_FileSize_XXLARGE_displayName(), Bundle.FileSearchData_FileSize_200PlusMb()), - XLARGE_IMAGE(7, 50 * BYTES_PER_MB, 200 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_XLARGE_displayName(), Bundle.FileSearchData_FileSize_50mbto200mb()), - LARGE_IMAGE(8, 1 * BYTES_PER_MB, 50 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_LARGE_displayName(), Bundle.FileSearchData_FileSize_1mbto50mb()), - MEDIUM_IMAGE(9, 100000, 1 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_MEDIUM_displayName(), Bundle.FileSearchData_FileSize_100kbto1mb()), - SMALL_IMAGE(10, 16000, 100000, Bundle.FileSearchData_FileSize_SMALL_displayName(), Bundle.FileSearchData_FileSize_16kbto100kb()), - XSMALL_IMAGE(11, 0, 16000, Bundle.FileSearchData_FileSize_XSMALL_displayName(), Bundle.FileSearchData_FileSize_upTo16kb()); - - private final int ranking; // Must be unique for each value - private final long minBytes; // Note that the size must be strictly greater than this to match - private final long maxBytes; - private final String sizeGroup; - private final String displaySize; - final static long NO_MAXIMUM = -1; - - FileSize(int ranking, long minB, long maxB, String displayName, String displaySize) { - this.ranking = ranking; - this.minBytes = minB; - if (maxB >= 0) { - this.maxBytes = maxB; - } else { - this.maxBytes = NO_MAXIMUM; - } - this.sizeGroup = displayName; - this.displaySize = displaySize; - } - - /** - * Get the enum corresponding to the given file size for image files. - * The file size must be strictly greater than minBytes. - * - * @param size the file size - * - * @return the enum whose range contains the file size - */ - public static FileSize fromImageSize(long size) { - if (size > XXLARGE_IMAGE.getMinBytes()) { - return XXLARGE_IMAGE; - } else if (size > XLARGE_IMAGE.getMinBytes()) { - return XLARGE_IMAGE; - } else if (size > LARGE_IMAGE.getMinBytes()) { - return LARGE_IMAGE; - } else if (size > MEDIUM_IMAGE.getMinBytes()) { - return MEDIUM_IMAGE; - } else if (size > SMALL_IMAGE.getMinBytes()) { - return SMALL_IMAGE; - } else { - return XSMALL_IMAGE; - } - } - - /** - * Get the enum corresponding to the given file size for video files. - * The file size must be strictly greater than minBytes. - * - * @param size the file size - * - * @return the enum whose range contains the file size - */ - public static FileSize fromVideoSize(long size) { - if (size > XXLARGE_VIDEO.getMinBytes()) { - return XXLARGE_VIDEO; - } else if (size > XLARGE_VIDEO.getMinBytes()) { - return XLARGE_VIDEO; - } else if (size > LARGE_VIDEO.getMinBytes()) { - return LARGE_VIDEO; - } else if (size > MEDIUM_VIDEO.getMinBytes()) { - return MEDIUM_VIDEO; - } else if (size > SMALL_VIDEO.getMinBytes()) { - return SMALL_VIDEO; - } else { - return XSMALL_VIDEO; - } - } - - /** - * Get the upper limit of the range. - * - * @return the maximum file size that will fit in this range. - */ - public long getMaxBytes() { - return maxBytes; - } - - /** - * Get the lower limit of the range. - * - * @return the maximum file size that is not part of this range - */ - public long getMinBytes() { - return minBytes; - } - - /** - * Get the rank for sorting. - * - * @return the rank (lower should be displayed first) - */ - public int getRanking() { - return ranking; - } - - @Override - public String toString() { - return sizeGroup + displaySize; - } - - public String getSizeGroup() { - return sizeGroup; - } - - /** - * Get the list of enums that are valid for most file sizes. - * - * @return Enums that can be used to filter most file including images - * by size. - */ - public static List getDefaultSizeOptions() { - return Arrays.asList(XXLARGE_IMAGE, XLARGE_IMAGE, LARGE_IMAGE, MEDIUM_IMAGE, SMALL_IMAGE, XSMALL_IMAGE); - } - - /** - * Get the list of enums that are valid for video sizes. - * - * @return enums that can be used to filter videos by size. - */ - public static List getOptionsForVideos() { - return Arrays.asList(XXLARGE_VIDEO, XLARGE_VIDEO, LARGE_VIDEO, MEDIUM_VIDEO, SMALL_VIDEO, XSMALL_VIDEO); - } - } - - //Discovery uses a different list of document mime types than FileTypeUtils.FileTypeCategory.DOCUMENTS - private static final ImmutableSet DOCUMENT_MIME_TYPES - = new ImmutableSet.Builder() - .add("text/html", //NON-NLS - "text/csv", //NON-NLS - "application/rtf", //NON-NLS - "application/pdf", //NON-NLS - "application/xhtml+xml", //NON-NLS - "application/x-msoffice", //NON-NLS - "application/msword", //NON-NLS - "application/msword2", //NON-NLS - "application/vnd.wordperfect", //NON-NLS - "application/vnd.openxmlformats-officedocument.wordprocessingml.document", //NON-NLS - "application/vnd.ms-powerpoint", //NON-NLS - "application/vnd.openxmlformats-officedocument.presentationml.presentation", //NON-NLS - "application/vnd.ms-excel", //NON-NLS - "application/vnd.ms-excel.sheet.4", //NON-NLS - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", //NON-NLS - "application/vnd.oasis.opendocument.presentation", //NON-NLS - "application/vnd.oasis.opendocument.spreadsheet", //NON-NLS - "application/vnd.oasis.opendocument.text" //NON-NLS - ).build(); - - private static final ImmutableSet IMAGE_UNSUPPORTED_DOC_TYPES - = new ImmutableSet.Builder() - .add("application/pdf", //NON-NLS - "application/xhtml+xml").build(); //NON-NLS - - public static Collection getDocTypesWithoutImageExtraction() { - return Collections.unmodifiableCollection(IMAGE_UNSUPPORTED_DOC_TYPES); - } - - /** - * Enum representing the file type. We don't simply use - * FileTypeUtils.FileTypeCategory because: - Some file types categories - * overlap - It is convenient to have the "OTHER" option for files that - * don't match the given types - */ - @NbBundle.Messages({ - "FileSearchData.FileType.Audio.displayName=Audio", - "FileSearchData.FileType.Video.displayName=Video", - "FileSearchData.FileType.Image.displayName=Image", - "FileSearchData.FileType.Documents.displayName=Documents", - "FileSearchData.FileType.Executables.displayName=Executables", - "FileSearchData.FileType.Other.displayName=Other/Unknown"}) - public enum FileType { - - IMAGE(0, Bundle.FileSearchData_FileType_Image_displayName(), FileTypeUtils.FileTypeCategory.IMAGE.getMediaTypes()), - AUDIO(1, Bundle.FileSearchData_FileType_Audio_displayName(), FileTypeUtils.FileTypeCategory.AUDIO.getMediaTypes()), - VIDEO(2, Bundle.FileSearchData_FileType_Video_displayName(), FileTypeUtils.FileTypeCategory.VIDEO.getMediaTypes()), - EXECUTABLE(3, Bundle.FileSearchData_FileType_Executables_displayName(), FileTypeUtils.FileTypeCategory.EXECUTABLE.getMediaTypes()), - DOCUMENTS(4, Bundle.FileSearchData_FileType_Documents_displayName(), DOCUMENT_MIME_TYPES), - OTHER(5, Bundle.FileSearchData_FileType_Other_displayName(), new ArrayList<>()); - - private final int ranking; // For ordering in the UI - private final String displayName; - private final Collection mediaTypes; - - FileType(int value, String displayName, Collection mediaTypes) { - this.ranking = value; - this.displayName = displayName; - this.mediaTypes = mediaTypes; - } - - /** - * Get the MIME types matching this category. - * - * @return Collection of MIME type strings - */ - public Collection getMediaTypes() { - return Collections.unmodifiableCollection(mediaTypes); - } - - @Override - public String toString() { - return displayName; - } - - /** - * Get the rank for sorting. - * - * @return the rank (lower should be displayed first) - */ - public int getRanking() { - return ranking; - } - - /** - * Get the enum matching the given MIME type. - * - * @param mimeType The MIME type for the file - * - * @return the corresponding enum (will be OTHER if no types matched) - */ - public static FileType fromMIMEtype(String mimeType) { - for (FileType type : FileType.values()) { - if (type.getMediaTypes().contains(mimeType)) { - return type; - } - } - return OTHER; - } - - } - - /** - * Enum representing the score of the file. - */ - @NbBundle.Messages({ - "FileSearchData.Score.notable.displayName=Notable", - "FileSearchData.Score.interesting.displayName=Interesting", - "FileSearchData.Score.unknown.displayName=Unknown",}) - public enum Score { - NOTABLE(0, Bundle.FileSearchData_Score_notable_displayName()), - INTERESTING(1, Bundle.FileSearchData_Score_interesting_displayName()), - UNKNOWN(2, Bundle.FileSearchData_Score_unknown_displayName()); - - private final int ranking; - private final String displayName; - - Score(int ranking, String displayName) { - this.ranking = ranking; - this.displayName = displayName; - } - - /** - * Get the rank for sorting. - * - * @return the rank (lower should be displayed first) - */ - public int getRanking() { - return ranking; - } - - /** - * Get the list of enums that are valid for filtering. - * - * @return enums that can be used to filter - */ - public static List getOptionsForFiltering() { - return Arrays.asList(NOTABLE, INTERESTING); - } - - @Override - public String toString() { - return displayName; - } - } - - private FileSearchData() { - // Class should not be instantiated - } -} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/FileGroup.java b/Core/src/org/sleuthkit/autopsy/discovery/search/Group.java similarity index 91% rename from Core/src/org/sleuthkit/autopsy/discovery/search/FileGroup.java rename to Core/src/org/sleuthkit/autopsy/discovery/search/Group.java index 173e9c63d1..30738df756 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/FileGroup.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/Group.java @@ -26,9 +26,9 @@ import org.openide.util.NbBundle.Messages; /** * Class for storing files that belong to a particular group. */ -public class FileGroup implements Comparable { +public class Group implements Comparable { - private final FileGroup.GroupSortingAlgorithm groupSortingType; + private final Group.GroupSortingAlgorithm groupSortingType; private final DiscoveryKeyUtils.GroupKey groupKey; private final List files; private final String displayName; @@ -39,7 +39,7 @@ public class FileGroup implements Comparable { * @param groupSortingType The method for sorting the group * @param groupKey The GroupKey for this group */ - public FileGroup(FileGroup.GroupSortingAlgorithm groupSortingType, DiscoveryKeyUtils.GroupKey groupKey) { + public Group(Group.GroupSortingAlgorithm groupSortingType, DiscoveryKeyUtils.GroupKey groupKey) { this.groupSortingType = groupSortingType; this.groupKey = groupKey; files = new ArrayList<>(); @@ -95,7 +95,7 @@ public class FileGroup implements Comparable { * otherwise */ @Override - public int compareTo(FileGroup otherGroup) { + public int compareTo(Group otherGroup) { switch (groupSortingType) { case BY_GROUP_SIZE: @@ -114,7 +114,7 @@ public class FileGroup implements Comparable { * * @return -1 if group1 should be displayed before group2, 1 otherwise */ - private static int compareGroupsByGroupKey(FileGroup group1, FileGroup group2) { + private static int compareGroupsByGroupKey(Group group1, Group group2) { return group1.getGroupKey().compareTo(group2.getGroupKey()); } @@ -127,7 +127,7 @@ public class FileGroup implements Comparable { * * @return -1 if group1 should be displayed before group2, 1 otherwise */ - private static int compareGroupsBySize(FileGroup group1, FileGroup group2) { + private static int compareGroupsBySize(Group group1, Group group2) { if (group1.getFiles().size() != group2.getFiles().size()) { return -1 * Long.compare(group1.getFiles().size(), group2.getFiles().size()); // High to low } else { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/Result.java b/Core/src/org/sleuthkit/autopsy/discovery/search/Result.java new file mode 100644 index 0000000000..5c3ede6971 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/Result.java @@ -0,0 +1,26 @@ +/* + * Autopsy + * + * 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.discovery.search; + +/** + * Interface implemented by all types of results. + */ +public interface Result { + +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultDomain.java b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultDomain.java new file mode 100644 index 0000000000..b3b03ff3e0 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultDomain.java @@ -0,0 +1,24 @@ +/* + * Autopsy + * + * 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.discovery.search; + + +public class ResultDomain implements Result { + +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultFile.java b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultFile.java index 5d87a3cf07..60274310ea 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultFile.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultFile.java @@ -18,7 +18,7 @@ */ package org.sleuthkit.autopsy.discovery.search; -import org.sleuthkit.autopsy.discovery.search.FileSearchData.FileType; +import org.sleuthkit.autopsy.discovery.search.SearchData.Type; import org.sleuthkit.datamodel.AbstractFile; import java.util.ArrayList; import java.util.Collections; @@ -29,6 +29,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; import org.sleuthkit.autopsy.coreutils.Logger; +import static org.sleuthkit.autopsy.discovery.search.SearchData.Type.OTHER; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.HashUtility; @@ -39,10 +40,10 @@ import org.sleuthkit.datamodel.TskData; /** * Container for files that holds all necessary data for grouping and sorting. */ -public class ResultFile { +public class ResultFile implements Result{ private final static Logger logger = Logger.getLogger(ResultFile.class.getName()); - private FileSearchData.Frequency frequency; + private SearchData.Frequency frequency; private final List keywordListNames; private final List hashSetNames; private final List tagNames; @@ -52,7 +53,7 @@ public class ResultFile { private DataResultViewerTable.Score currentScore = DataResultViewerTable.Score.NO_SCORE; private String scoreDescription = null; private boolean deleted = false; - private FileType fileType; + private Type fileType; /** * Create a ResultFile from an AbstractFile @@ -72,13 +73,13 @@ public class ResultFile { deleted = true; } updateScoreAndDescription(abstractFile); - this.frequency = FileSearchData.Frequency.UNKNOWN; + this.frequency = SearchData.Frequency.UNKNOWN; keywordListNames = new ArrayList<>(); hashSetNames = new ArrayList<>(); tagNames = new ArrayList<>(); interestingSetNames = new ArrayList<>(); objectDetectedNames = new ArrayList<>(); - fileType = FileType.fromMIMEtype(abstractFile.getMIMEType()); + fileType = fromMIMEtype(abstractFile.getMIMEType()); } /** @@ -86,7 +87,7 @@ public class ResultFile { * * @return The Frequency enum */ - public FileSearchData.Frequency getFrequency() { + public SearchData.Frequency getFrequency() { return frequency; } @@ -95,7 +96,7 @@ public class ResultFile { * * @param frequency The frequency of the file as an enum */ - public void setFrequency(FileSearchData.Frequency frequency) { + public void setFrequency(SearchData.Frequency frequency) { this.frequency = frequency; } @@ -109,8 +110,8 @@ public class ResultFile { if (deleted && !duplicate.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC)) { deleted = false; } - if (fileType == FileType.OTHER) { - fileType = FileType.fromMIMEtype(duplicate.getMIMEType()); + if (fileType == Type.OTHER) { + fileType = fromMIMEtype(duplicate.getMIMEType()); } updateScoreAndDescription(duplicate); try { @@ -167,7 +168,7 @@ public class ResultFile { * * @return The FileType enum. */ - public FileType getFileType() { + public Type getFileType() { return fileType; } @@ -380,4 +381,20 @@ public class ResultFile { } } } + + /** + * Get the enum matching the given MIME type. + * + * @param mimeType The MIME type for the file. + * + * @return the corresponding enum (will be OTHER if no types matched) + */ + public static Type fromMIMEtype(String mimeType) { + for (Type type : Type.values()) { + if (type.getMediaTypes().contains(mimeType)) { + return type; + } + } + return OTHER; + } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchData.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchData.java index 6807e334dd..eb0ca6e210 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchData.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchData.java @@ -1,7 +1,7 @@ /* - * Autopsy + * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2019 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,22 +18,413 @@ */ package org.sleuthkit.autopsy.discovery.search; +import com.google.common.collect.ImmutableSet; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.coreutils.FileTypeUtils; +import org.sleuthkit.datamodel.BlackboardArtifact; + /** - * Abstract class to contain data that is common to all result types. + * Utility enums for searches made for files with Discovery. */ -public interface SearchData { +public final class SearchData { + + private final static long BYTES_PER_MB = 1000000; + private static final Set DOMAIN_ARTIFACT_TYPES = EnumSet.of(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY, BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG); /** - * Enum of the broad result type categories. + * Enum representing how often the file occurs in the Central Repository. */ - public enum ResultType { - FILE, - ATTRIBUTE; + @NbBundle.Messages({ + "SearchData.Frequency.unique.displayName=Unique (1)", + "SearchData.Frequency.rare.displayName=Rare (2-10)", + "SearchData.Frequency.common.displayName=Common (11 - 100)", + "SearchData.Frequency.verycommon.displayName=Very Common (100+)", + "SearchData.Frequency.known.displayName=Known (NSRL)", + "SearchData.Frequency.unknown.displayName=Unknown",}) + public enum Frequency { + UNIQUE(0, 1, Bundle.SearchData_Frequency_unique_displayName()), + RARE(1, 10, Bundle.SearchData_Frequency_rare_displayName()), + COMMON(2, 100, Bundle.SearchData_Frequency_common_displayName()), + VERY_COMMON(3, 0, Bundle.SearchData_Frequency_verycommon_displayName()), + KNOWN(4, 0, Bundle.SearchData_Frequency_known_displayName()), + UNKNOWN(5, 0, Bundle.SearchData_Frequency_unknown_displayName()); + + private final int ranking; + private final String displayName; + private final int maxOccur; + + Frequency(int ranking, int maxOccur, String displayName) { + this.ranking = ranking; + this.maxOccur = maxOccur; + this.displayName = displayName; + } + + /** + * Get the rank for sorting. + * + * @return the rank (lower should be displayed first) + */ + public int getRanking() { + return ranking; + } + + /** + * Get the enum matching the given occurrence count. + * + * @param count Number of times a file is in the Central Repository. + * + * @return the corresponding enum + */ + public static Frequency fromCount(long count) { + if (count <= UNIQUE.getMaxOccur()) { + return UNIQUE; + } else if (count <= RARE.getMaxOccur()) { + return RARE; + } else if (count <= COMMON.getMaxOccur()) { + return COMMON; + } + return VERY_COMMON; + } + + /** + * Get the list of enums that are valid for filtering when a CR is + * enabled. + * + * @return enums that can be used to filter with a CR. + */ + public static List getOptionsForFilteringWithCr() { + return Arrays.asList(UNIQUE, RARE, COMMON, VERY_COMMON, KNOWN); + } + + /** + * Get the list of enums that are valid for filtering when no CR is + * enabled. + * + * @return enums that can be used to filter without a CR. + */ + public static List getOptionsForFilteringWithoutCr() { + return Arrays.asList(KNOWN, UNKNOWN); + } + + @Override + public String toString() { + return displayName; + } + + /** + * @return the maxOccur + */ + public int getMaxOccur() { + return maxOccur; + } } /** - * Get the broad result type. + * Enum representing the file size */ - public abstract ResultType getResultType(); + @NbBundle.Messages({ + "SearchData.FileSize.XXLARGE.displayName=XXLarge", + "SearchData.FileSize.XLARGE.displayName=XLarge", + "SearchData.FileSize.LARGE.displayName=Large", + "SearchData.FileSize.MEDIUM.displayName=Medium", + "SearchData.FileSize.SMALL.displayName=Small", + "SearchData.FileSize.XSMALL.displayName=XSmall", + "SearchData.FileSize.10PlusGb=: 10GB+", + "SearchData.FileSize.5gbto10gb=: 5-10GB", + "SearchData.FileSize.1gbto5gb=: 1-5GB", + "SearchData.FileSize.100mbto1gb=: 100MB-1GB", + "SearchData.FileSize.200PlusMb=: 200MB+", + "SearchData.FileSize.50mbto200mb=: 50-200MB", + "SearchData.FileSize.500kbto100mb=: 500KB-100MB", + "SearchData.FileSize.1mbto50mb=: 1-50MB", + "SearchData.FileSize.100kbto1mb=: 100KB-1MB", + "SearchData.FileSize.16kbto100kb=: 16-100KB", + "SearchData.FileSize.upTo500kb=: 0-500KB", + "SearchData.FileSize.upTo16kb=: 0-16KB",}) + public enum FileSize { + XXLARGE_VIDEO(0, 10000 * BYTES_PER_MB, -1, Bundle.SearchData_FileSize_XXLARGE_displayName(), Bundle.SearchData_FileSize_10PlusGb()), + XLARGE_VIDEO(1, 5000 * BYTES_PER_MB, 10000 * BYTES_PER_MB, Bundle.SearchData_FileSize_XLARGE_displayName(), Bundle.SearchData_FileSize_5gbto10gb()), + LARGE_VIDEO(2, 1000 * BYTES_PER_MB, 5000 * BYTES_PER_MB, Bundle.SearchData_FileSize_LARGE_displayName(), Bundle.SearchData_FileSize_1gbto5gb()), + MEDIUM_VIDEO(3, 100 * BYTES_PER_MB, 1000 * BYTES_PER_MB, Bundle.SearchData_FileSize_MEDIUM_displayName(), Bundle.SearchData_FileSize_100mbto1gb()), + SMALL_VIDEO(4, 500000, 100 * BYTES_PER_MB, Bundle.SearchData_FileSize_SMALL_displayName(), Bundle.SearchData_FileSize_500kbto100mb()), + XSMALL_VIDEO(5, 0, 500000, Bundle.SearchData_FileSize_XSMALL_displayName(), Bundle.SearchData_FileSize_upTo500kb()), + XXLARGE_IMAGE(6, 200 * BYTES_PER_MB, -1, Bundle.SearchData_FileSize_XXLARGE_displayName(), Bundle.SearchData_FileSize_200PlusMb()), + XLARGE_IMAGE(7, 50 * BYTES_PER_MB, 200 * BYTES_PER_MB, Bundle.SearchData_FileSize_XLARGE_displayName(), Bundle.SearchData_FileSize_50mbto200mb()), + LARGE_IMAGE(8, 1 * BYTES_PER_MB, 50 * BYTES_PER_MB, Bundle.SearchData_FileSize_LARGE_displayName(), Bundle.SearchData_FileSize_1mbto50mb()), + MEDIUM_IMAGE(9, 100000, 1 * BYTES_PER_MB, Bundle.SearchData_FileSize_MEDIUM_displayName(), Bundle.SearchData_FileSize_100kbto1mb()), + SMALL_IMAGE(10, 16000, 100000, Bundle.SearchData_FileSize_SMALL_displayName(), Bundle.SearchData_FileSize_16kbto100kb()), + XSMALL_IMAGE(11, 0, 16000, Bundle.SearchData_FileSize_XSMALL_displayName(), Bundle.SearchData_FileSize_upTo16kb()); + private final int ranking; // Must be unique for each value + private final long minBytes; // Note that the size must be strictly greater than this to match + private final long maxBytes; + private final String sizeGroup; + private final String displaySize; + final static long NO_MAXIMUM = -1; + + FileSize(int ranking, long minB, long maxB, String displayName, String displaySize) { + this.ranking = ranking; + this.minBytes = minB; + if (maxB >= 0) { + this.maxBytes = maxB; + } else { + this.maxBytes = NO_MAXIMUM; + } + this.sizeGroup = displayName; + this.displaySize = displaySize; + } + + /** + * Get the enum corresponding to the given file size for image files. + * The file size must be strictly greater than minBytes. + * + * @param size the file size + * + * @return the enum whose range contains the file size + */ + public static FileSize fromImageSize(long size) { + if (size > XXLARGE_IMAGE.getMinBytes()) { + return XXLARGE_IMAGE; + } else if (size > XLARGE_IMAGE.getMinBytes()) { + return XLARGE_IMAGE; + } else if (size > LARGE_IMAGE.getMinBytes()) { + return LARGE_IMAGE; + } else if (size > MEDIUM_IMAGE.getMinBytes()) { + return MEDIUM_IMAGE; + } else if (size > SMALL_IMAGE.getMinBytes()) { + return SMALL_IMAGE; + } else { + return XSMALL_IMAGE; + } + } + + /** + * Get the enum corresponding to the given file size for video files. + * The file size must be strictly greater than minBytes. + * + * @param size the file size + * + * @return the enum whose range contains the file size + */ + public static FileSize fromVideoSize(long size) { + if (size > XXLARGE_VIDEO.getMinBytes()) { + return XXLARGE_VIDEO; + } else if (size > XLARGE_VIDEO.getMinBytes()) { + return XLARGE_VIDEO; + } else if (size > LARGE_VIDEO.getMinBytes()) { + return LARGE_VIDEO; + } else if (size > MEDIUM_VIDEO.getMinBytes()) { + return MEDIUM_VIDEO; + } else if (size > SMALL_VIDEO.getMinBytes()) { + return SMALL_VIDEO; + } else { + return XSMALL_VIDEO; + } + } + + /** + * Get the upper limit of the range. + * + * @return the maximum file size that will fit in this range. + */ + public long getMaxBytes() { + return maxBytes; + } + + /** + * Get the lower limit of the range. + * + * @return the maximum file size that is not part of this range + */ + public long getMinBytes() { + return minBytes; + } + + /** + * Get the rank for sorting. + * + * @return the rank (lower should be displayed first) + */ + public int getRanking() { + return ranking; + } + + @Override + public String toString() { + return sizeGroup + displaySize; + } + + public String getSizeGroup() { + return sizeGroup; + } + + /** + * Get the list of enums that are valid for most file sizes. + * + * @return Enums that can be used to filter most file including images + * by size. + */ + public static List getDefaultSizeOptions() { + return Arrays.asList(XXLARGE_IMAGE, XLARGE_IMAGE, LARGE_IMAGE, MEDIUM_IMAGE, SMALL_IMAGE, XSMALL_IMAGE); + } + + /** + * Get the list of enums that are valid for video sizes. + * + * @return enums that can be used to filter videos by size. + */ + public static List getOptionsForVideos() { + return Arrays.asList(XXLARGE_VIDEO, XLARGE_VIDEO, LARGE_VIDEO, MEDIUM_VIDEO, SMALL_VIDEO, XSMALL_VIDEO); + } + } + + //Discovery uses a different list of document mime types than FileTypeUtils.FileTypeCategory.DOCUMENTS + private static final ImmutableSet DOCUMENT_MIME_TYPES + = new ImmutableSet.Builder() + .add("text/html", //NON-NLS + "text/csv", //NON-NLS + "application/rtf", //NON-NLS + "application/pdf", //NON-NLS + "application/xhtml+xml", //NON-NLS + "application/x-msoffice", //NON-NLS + "application/msword", //NON-NLS + "application/msword2", //NON-NLS + "application/vnd.wordperfect", //NON-NLS + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", //NON-NLS + "application/vnd.ms-powerpoint", //NON-NLS + "application/vnd.openxmlformats-officedocument.presentationml.presentation", //NON-NLS + "application/vnd.ms-excel", //NON-NLS + "application/vnd.ms-excel.sheet.4", //NON-NLS + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", //NON-NLS + "application/vnd.oasis.opendocument.presentation", //NON-NLS + "application/vnd.oasis.opendocument.spreadsheet", //NON-NLS + "application/vnd.oasis.opendocument.text" //NON-NLS + ).build(); + + private static final ImmutableSet IMAGE_UNSUPPORTED_DOC_TYPES + = new ImmutableSet.Builder() + .add("application/pdf", //NON-NLS + "application/xhtml+xml").build(); //NON-NLS + + public static Collection getDocTypesWithoutImageExtraction() { + return Collections.unmodifiableCollection(IMAGE_UNSUPPORTED_DOC_TYPES); + } + + /** + * Enum representing the type. + */ + @NbBundle.Messages({ + "SearchData.FileType.Audio.displayName=Audio", + "SearchData.FileType.Video.displayName=Video", + "SearchData.FileType.Image.displayName=Image", + "SearchData.FileType.Documents.displayName=Documents", + "SearchData.FileType.Executables.displayName=Executables", + "SearchData.AttributeType.Domain.displayName=Domains", + "SearchData.FileType.Other.displayName=Other/Unknown"}) + public enum Type { + + IMAGE(0, Bundle.SearchData_FileType_Image_displayName(), FileTypeUtils.FileTypeCategory.IMAGE.getMediaTypes(), new ArrayList<>()), + AUDIO(1, Bundle.SearchData_FileType_Audio_displayName(), FileTypeUtils.FileTypeCategory.AUDIO.getMediaTypes(), new ArrayList<>()), + VIDEO(2, Bundle.SearchData_FileType_Video_displayName(), FileTypeUtils.FileTypeCategory.VIDEO.getMediaTypes(), new ArrayList<>()), + EXECUTABLE(3, Bundle.SearchData_FileType_Executables_displayName(), FileTypeUtils.FileTypeCategory.EXECUTABLE.getMediaTypes(),new ArrayList<>()), + DOCUMENTS(4, Bundle.SearchData_FileType_Documents_displayName(), DOCUMENT_MIME_TYPES, new ArrayList<>()), + DOMAIN(6, Bundle.SearchData_AttributeType_Domain_displayName(), new ArrayList<>(), DOMAIN_ARTIFACT_TYPES), + OTHER(5, Bundle.SearchData_FileType_Other_displayName(), new ArrayList<>(), new ArrayList<>()); + + + private final int ranking; // For ordering in the UI + private final String displayName; + private final Collection mediaTypes; + private final Collection artifactTypes; + + Type(int value, String displayName, Collection mediaTypes, Collection artifactTypes) { + this.ranking = value; + this.displayName = displayName; + this.mediaTypes = mediaTypes; + this.artifactTypes = artifactTypes; + } + + /** + * Get the MIME types matching this category. + * + * @return Collection of MIME type strings + */ + public Collection getMediaTypes() { + return Collections.unmodifiableCollection(mediaTypes); + } + + public Collection getArtifactTypes() { + return Collections.unmodifiableCollection(artifactTypes); + } + + @Override + public String toString() { + return displayName; + } + + /** + * Get the rank for sorting. + * + * @return the rank (lower should be displayed first) + */ + public int getRanking() { + return ranking; + } + + } + + /** + * Enum representing the score of the item. + */ + @NbBundle.Messages({ + "SearchData.Score.notable.displayName=Notable", + "SearchData.Score.interesting.displayName=Interesting", + "SearchData.Score.unknown.displayName=Unknown",}) + public enum Score { + NOTABLE(0, Bundle.SearchData_Score_notable_displayName()), + INTERESTING(1, Bundle.SearchData_Score_interesting_displayName()), + UNKNOWN(2, Bundle.SearchData_Score_unknown_displayName()); + + private final int ranking; + private final String displayName; + + Score(int ranking, String displayName) { + this.ranking = ranking; + this.displayName = displayName; + } + + /** + * Get the rank for sorting. + * + * @return the rank (lower should be displayed first) + */ + public int getRanking() { + return ranking; + } + + /** + * Get the list of enums that are valid for filtering. + * + * @return enums that can be used to filter + */ + public static List getOptionsForFiltering() { + return Arrays.asList(NOTABLE, INTERESTING); + } + + @Override + public String toString() { + return displayName; + } + } + + private SearchData() { + // Class should not be instantiated + } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java index fa2dd972fd..9b4374e927 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java @@ -21,10 +21,10 @@ package org.sleuthkit.autopsy.discovery.search; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; -import org.sleuthkit.autopsy.discovery.search.FileSearchData.FileSize; -import org.sleuthkit.autopsy.discovery.search.FileSearchData.FileType; -import org.sleuthkit.autopsy.discovery.search.FileSearchData.Frequency; -import org.sleuthkit.autopsy.discovery.search.FileSearchData.Score; +import org.sleuthkit.autopsy.discovery.search.SearchData.FileSize; +import org.sleuthkit.autopsy.discovery.search.SearchData.Type; +import org.sleuthkit.autopsy.discovery.search.SearchData.Frequency; +import org.sleuthkit.autopsy.discovery.search.SearchData.Score; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.SleuthkitCase; @@ -54,9 +54,9 @@ public class SearchFiltering { * * @return */ - static List runQueries(List filters, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws FileSearchException { + static List runQueries(List filters, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { if (caseDb == null) { - throw new FileSearchException("Case DB parameter is null"); // NON-NLS + throw new DiscoveryException("Case DB parameter is null"); // NON-NLS } // Combine all the SQL queries from the filters into one query String combinedQuery = ""; @@ -71,12 +71,12 @@ public class SearchFiltering { if (combinedQuery.isEmpty()) { // The file search filter is required, so this should never be empty. - throw new FileSearchException("Selected filters do not include a case database query"); + throw new DiscoveryException("Selected filters do not include a case database query"); } try { return getResultList(filters, combinedQuery, caseDb, centralRepoDb); } catch (TskCoreException ex) { - throw new FileSearchException("Error querying case database", ex); // NON-NLS + throw new DiscoveryException("Error querying case database", ex); // NON-NLS } } @@ -92,9 +92,9 @@ public class SearchFiltering { * @return An ArrayList of ResultFiles returned by the query. * * @throws TskCoreException - * @throws FileSearchException + * @throws DiscoveryException */ - private static List getResultList(List filters, String combinedQuery, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws TskCoreException, FileSearchException { + private static List getResultList(List filters, String combinedQuery, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws TskCoreException, DiscoveryException { // Get all matching abstract files List resultList = new ArrayList<>(); List sqlResults = caseDb.findAllFilesWhere(combinedQuery); @@ -431,14 +431,14 @@ public class SearchFiltering { */ public static class FileTypeFilter extends AbstractFilter { - private final List categories; + private final List categories; /** * Create the FileTypeFilter * * @param categories List of file types to filter on */ - public FileTypeFilter(List categories) { + public FileTypeFilter(List categories) { this.categories = categories; } @@ -447,7 +447,7 @@ public class SearchFiltering { * * @param category the file type to filter on */ - public FileTypeFilter(FileType category) { + public FileTypeFilter(Type category) { this.categories = new ArrayList<>(); this.categories.add(category); } @@ -455,7 +455,7 @@ public class SearchFiltering { @Override public String getWhereClause() { String queryStr = ""; // NON-NLS - for (FileType cat : categories) { + for (Type cat : categories) { for (String type : cat.getMediaTypes()) { if (!queryStr.isEmpty()) { queryStr += ","; // NON-NLS @@ -474,7 +474,7 @@ public class SearchFiltering { @Override public String getDesc() { String desc = ""; - for (FileType cat : categories) { + for (Type cat : categories) { if (!desc.isEmpty()) { desc += Bundle.SearchFiltering_FileTypeFilter_or(); } @@ -515,12 +515,12 @@ public class SearchFiltering { @Override public List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws FileSearchException { + CentralRepository centralRepoDb) throws DiscoveryException { // We have to have run some kind of SQL filter before getting to this point, // and should have checked afterward to see if the results were empty. if (currentResults.isEmpty()) { - throw new FileSearchException("Can not run on empty list"); // NON-NLS + throw new DiscoveryException("Can not run on empty list"); // NON-NLS } // Set the frequency for each file @@ -835,16 +835,16 @@ public class SearchFiltering { @Override public List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws FileSearchException { + CentralRepository centralRepoDb) throws DiscoveryException { if (centralRepoDb == null) { - throw new FileSearchException("Can not run Previously Notable filter with null Central Repository DB"); // NON-NLS + throw new DiscoveryException("Can not run Previously Notable filter with null Central Repository DB"); // NON-NLS } // We have to have run some kind of SQL filter before getting to this point, // and should have checked afterward to see if the results were empty. if (currentResults.isEmpty()) { - throw new FileSearchException("Can not run on empty list"); // NON-NLS + throw new DiscoveryException("Can not run on empty list"); // NON-NLS } // The matching files @@ -865,7 +865,7 @@ public class SearchFiltering { } return notableResults; } catch (CentralRepoException | CorrelationAttributeNormalizationException ex) { - throw new FileSearchException("Error querying central repository", ex); // NON-NLS + throw new DiscoveryException("Error querying central repository", ex); // NON-NLS } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java index 6484fbf5ae..77ce01b5c9 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java @@ -32,12 +32,12 @@ import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; */ class SearchResults { - private final FileGroup.GroupSortingAlgorithm groupSortingType; + private final Group.GroupSortingAlgorithm groupSortingType; private final FileSearch.AttributeType attrType; private final FileSorter fileSorter; - private final Map groupMap = new HashMap<>(); - private List groupList = new ArrayList<>(); + private final Map groupMap = new HashMap<>(); + private List groupList = new ArrayList<>(); private static final long MAX_OUTPUT_FILES = 2000; // For debug UI - maximum number of lines to print @@ -50,7 +50,7 @@ class SearchResults { * @param fileSortingMethod The method that should be used to * sortGroupsAndFiles the files in each group. */ - SearchResults(FileGroup.GroupSortingAlgorithm groupSortingType, FileSearch.AttributeType attrType, + SearchResults(Group.GroupSortingAlgorithm groupSortingType, FileSearch.AttributeType attrType, FileSorter.SortingMethod fileSortingMethod) { this.groupSortingType = groupSortingType; this.attrType = attrType; @@ -62,7 +62,7 @@ class SearchResults { * the search is finished. */ SearchResults() { - this.groupSortingType = FileGroup.GroupSortingAlgorithm.BY_GROUP_NAME; + this.groupSortingType = Group.GroupSortingAlgorithm.BY_GROUP_NAME; this.attrType = new FileSearch.FileSizeAttribute(); this.fileSorter = new FileSorter(FileSorter.SortingMethod.BY_FILE_NAME); } @@ -78,7 +78,7 @@ class SearchResults { GroupKey groupKey = attrType.getGroupKey(file); if (!groupMap.containsKey(groupKey)) { - groupMap.put(groupKey, new FileGroup(groupSortingType, groupKey)); + groupMap.put(groupKey, new Group(groupSortingType, groupKey)); } groupMap.get(groupKey).addFile(file); } @@ -91,7 +91,7 @@ class SearchResults { void sortGroupsAndFiles() { // First sortGroupsAndFiles the files - for (FileGroup group : groupMap.values()) { + for (Group group : groupMap.values()) { group.sortFiles(fileSorter); } @@ -108,7 +108,7 @@ class SearchResults { } long count = 0; - for (FileGroup group : groupList) { + for (Group group : groupList) { result += group.getDisplayName() + "\n"; for (ResultFile file : group.getFiles()) { @@ -143,7 +143,7 @@ class SearchResults { if (groupName != null) { final String modifiedGroupName = groupName.replaceAll(" \\([0-9]+\\)$", ""); - java.util.Optional fileGroup = groupList.stream().filter(p -> p.getDisplayName().equals(modifiedGroupName)).findFirst(); + java.util.Optional fileGroup = groupList.stream().filter(p -> p.getDisplayName().equals(modifiedGroupName)).findFirst(); if (fileGroup.isPresent()) { return fileGroup.get().getFiles(); } @@ -156,14 +156,14 @@ class SearchResults { * * @return The grouped and sorted results. */ - Map> toLinkedHashMap() throws FileSearchException { + Map> toLinkedHashMap() throws DiscoveryException { Map> map = new LinkedHashMap<>(); // Sort the groups and files sortGroupsAndFiles(); // groupList is sorted and a LinkedHashMap will preserve that order. - for (FileGroup group : groupList) { + for (Group group : groupList) { map.put(group.getGroupKey(), group.getFiles()); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java index 20273e6ae7..4b4673475c 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java @@ -32,8 +32,6 @@ import javax.swing.JSplitPane; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import org.apache.commons.lang3.StringUtils; -import org.sleuthkit.autopsy.discovery.search.AttributeSearchData; -import org.sleuthkit.autopsy.discovery.search.FileSearchData; import org.sleuthkit.autopsy.discovery.search.SearchData; import org.sleuthkit.autopsy.discovery.search.SearchFiltering; @@ -67,25 +65,11 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li } /** - * Get the broad ResultType, such as files or attributes. + * Get the type of results this filters panel is for. * - * @return + * @return The type of results this panel filters. */ - abstract SearchData.ResultType getResultType(); - - /** - * Get the file type of results this filters panel is for. - * - * @return The file type of results this panel filters. - */ - abstract FileSearchData.FileType getFileType(); - - /** - * Get the attribute type of results this filters panel is for. - * - * @return The attribute type of results this panel filters. - */ - abstract AttributeSearchData.AttributeType getArtifactType(); + abstract SearchData.Type getType(); /** * Add a DiscoveryFilterPanel to the specified column with the specified @@ -264,10 +248,10 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li synchronized List getFilters() { List filtersToUse = new ArrayList<>(); - if (getResultType().equals(SearchData.ResultType.FILE)) { - filtersToUse.add(new SearchFiltering.FileTypeFilter(getFileType())); - } else if (getResultType().equals(SearchData.ResultType.ATTRIBUTE)) { + if (getType().equals(SearchData.Type.DOMAIN)) { + } else { + filtersToUse.add(new SearchFiltering.FileTypeFilter(getType())); } for (AbstractDiscoveryFilterPanel filterPanel : filters) { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java index 9771c8ab81..eba7fbe1f1 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java @@ -23,7 +23,7 @@ import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; -import org.sleuthkit.autopsy.discovery.search.AttributeSearchData; +import org.sleuthkit.autopsy.discovery.search.SearchData; import org.sleuthkit.datamodel.BlackboardArtifact; /** @@ -49,7 +49,7 @@ class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { int count = 0; DefaultListModel artifactTypeModel = (DefaultListModel) jList1.getModel(); artifactTypeModel.removeAllElements(); - for (BlackboardArtifact.ARTIFACT_TYPE artifactType : AttributeSearchData.AttributeType.DOMAIN.getBlackboardTypes()) { + for (BlackboardArtifact.ARTIFACT_TYPE artifactType : SearchData.Type.DOMAIN.getArtifactTypes()) { artifactTypeModel.add(count, new ArtifactTypeItem(artifactType)); count++; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index face0f1c97..dc0f8cc6de 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -37,15 +37,13 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.discovery.search.AttributeSearchData; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; -import org.sleuthkit.autopsy.discovery.search.FileGroup; -import org.sleuthkit.autopsy.discovery.search.FileGroup.GroupSortingAlgorithm; -import static org.sleuthkit.autopsy.discovery.search.FileGroup.GroupSortingAlgorithm.BY_GROUP_SIZE; +import org.sleuthkit.autopsy.discovery.search.Group; +import org.sleuthkit.autopsy.discovery.search.Group.GroupSortingAlgorithm; +import static org.sleuthkit.autopsy.discovery.search.Group.GroupSortingAlgorithm.BY_GROUP_SIZE; import org.sleuthkit.autopsy.discovery.search.FileSearch; import org.sleuthkit.autopsy.discovery.search.FileSearch.GroupingAttributeType; import static org.sleuthkit.autopsy.discovery.search.FileSearch.GroupingAttributeType.PARENT_PATH; -import org.sleuthkit.autopsy.discovery.search.FileSearchData; import org.sleuthkit.autopsy.discovery.search.FileSorter; import org.sleuthkit.autopsy.discovery.search.FileSorter.SortingMethod; import static org.sleuthkit.autopsy.discovery.search.FileSorter.SortingMethod.BY_FILE_NAME; @@ -76,9 +74,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { private SearchWorker searchWorker = null; private static DiscoveryDialog discDialog; private static volatile boolean shouldUpdate = false; - private SearchData.ResultType resultType = SearchData.ResultType.FILE; - private FileSearchData.FileType fileType = FileSearchData.FileType.IMAGE; - private AttributeSearchData.AttributeType artifactType = null; + private SearchData.Type type = SearchData.Type.IMAGE; private final PropertyChangeListener listener; private final Set objectsDetected = new HashSet<>(); private final Set interestingItems = new HashSet<>(); @@ -140,9 +136,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { imagesButton.setEnabled(false); imagesButton.setBackground(SELECTED_COLOR); imagesButton.setForeground(Color.BLACK); - resultType = SearchData.ResultType.FILE; - fileType = FileSearchData.FileType.IMAGE; - artifactType = null; + type = SearchData.Type.IMAGE; add(imageFilterPanel, CENTER); imageFilterPanel.addPropertyChangeListener(listener); updateComboBoxes(); @@ -175,8 +169,8 @@ final class DiscoveryDialog extends javax.swing.JDialog { private void updateComboBoxes() { groupByCombobox.removeAllItems(); // Set up the grouping attributes - for (FileSearch.GroupingAttributeType type : FileSearch.GroupingAttributeType.getOptionsForGrouping()) { - addTypeToGroupByComboBox(type); + for (FileSearch.GroupingAttributeType groupingType : FileSearch.GroupingAttributeType.getOptionsForGrouping()) { + addTypeToGroupByComboBox(groupingType); } groupByCombobox.setSelectedItem(PARENT_PATH); orderByCombobox.removeAllItems(); @@ -223,25 +217,11 @@ final class DiscoveryDialog extends javax.swing.JDialog { groupByCombobox.addItem(type); } - /** - * Validate the current filter settings of the selected type. - */ - synchronized void validateDialog() { - switch (resultType) { - case FILE: - validateFileDialog(); - break; - case ATTRIBUTE: - validateArtifactDialog(); - break; - } - } - /** * Validate the filter settings for File type filters. */ - private synchronized void validateFileDialog() { - switch (fileType) { + synchronized void validateDialog() { + switch (type) { case IMAGE: if (imageFilterPanel != null) { imageFilterPanel.validateFields(); @@ -257,16 +237,6 @@ final class DiscoveryDialog extends javax.swing.JDialog { documentFilterPanel.validateFields(); } break; - default: - break; - } - } - - /** - * Validate the filter settings for Artifact type filters. - */ - private synchronized void validateArtifactDialog() { - switch (artifactType) { case DOMAIN: if (domainFilterPanel != null) { domainFilterPanel.validateFields(); @@ -497,9 +467,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { imagesButton.setEnabled(false); imagesButton.setBackground(SELECTED_COLOR); imagesButton.setForeground(Color.BLACK); - resultType = SearchData.ResultType.FILE; - artifactType = null; - fileType = FileSearchData.FileType.IMAGE; + type = SearchData.Type.IMAGE; imageFilterPanel.addPropertyChangeListener(listener); validateDialog(); pack(); @@ -515,9 +483,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { videosButton.setBackground(SELECTED_COLOR); videosButton.setForeground(Color.BLACK); videoFilterPanel.addPropertyChangeListener(listener); - resultType = SearchData.ResultType.FILE; - artifactType = null; - fileType = FileSearchData.FileType.VIDEO; + type = SearchData.Type.VIDEO; validateDialog(); pack(); repaint(); @@ -531,9 +497,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { documentsButton.setEnabled(false); documentsButton.setBackground(SELECTED_COLOR); documentsButton.setForeground(Color.BLACK); - resultType = SearchData.ResultType.FILE; - artifactType = null; - fileType = FileSearchData.FileType.DOCUMENTS; + type = SearchData.Type.DOCUMENTS; documentFilterPanel.addPropertyChangeListener(listener); validateDialog(); pack(); @@ -587,11 +551,11 @@ final class DiscoveryDialog extends javax.swing.JDialog { filters = new ArrayList<>(); } - DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.SearchStartedEvent(resultType, fileType, artifactType)); + DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.SearchStartedEvent(type)); // Get the grouping attribute and group sorting method FileSearch.AttributeType groupingAttr = groupByCombobox.getItemAt(groupByCombobox.getSelectedIndex()).getAttributeType(); - FileGroup.GroupSortingAlgorithm groupSortAlgorithm = groupSortingComboBox.getItemAt(groupSortingComboBox.getSelectedIndex()); + Group.GroupSortingAlgorithm groupSortAlgorithm = groupSortingComboBox.getItemAt(groupSortingComboBox.getSelectedIndex()); // Get the file sorting method FileSorter.SortingMethod fileSort = (FileSorter.SortingMethod) orderByCombobox.getSelectedItem(); @@ -619,9 +583,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { domainsButton.setEnabled(false); domainsButton.setBackground(SELECTED_COLOR); domainsButton.setForeground(Color.BLACK); - resultType = SearchData.ResultType.ATTRIBUTE; - artifactType = AttributeSearchData.AttributeType.DOMAIN; - fileType = null; + type = SearchData.Type.DOMAIN; documentFilterPanel.addPropertyChangeListener(listener); validateDialog(); pack(); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java index 96bcea63d6..41351c652f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java @@ -38,7 +38,6 @@ import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; -import org.sleuthkit.autopsy.discovery.search.SearchData.ResultType; /** * Create a dialog for displaying the Discovery results. @@ -286,13 +285,7 @@ public final class DiscoveryTopComponent extends TopComponent { void handleSearchStartedEvent(DiscoveryEventUtils.SearchStartedEvent searchStartedEvent) { newSearchButton.setText(Bundle.DiscoveryTopComponent_cancelButton_text()); progressMessageTextArea.setForeground(Color.red); - String text = Bundle.DiscoveryTopComponent_searchError_text(); - if (searchStartedEvent.getResultType() == ResultType.FILE) { - text = Bundle.DiscoveryTopComponent_searchInProgress_text(searchStartedEvent.getFileType().name()); - } else if (searchStartedEvent.getResultType() == ResultType.ATTRIBUTE) { - text = Bundle.DiscoveryTopComponent_searchInProgress_text(searchStartedEvent.getAttributeType().name()); - } - progressMessageTextArea.setText(text); + progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchInProgress_text(searchStartedEvent.getType().name())); } /** diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentFilterPanel.java index 9c2e5565a1..888f7285d5 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentFilterPanel.java @@ -19,8 +19,6 @@ package org.sleuthkit.autopsy.discovery.ui; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; -import org.sleuthkit.autopsy.discovery.search.AttributeSearchData; -import org.sleuthkit.autopsy.discovery.search.FileSearchData; import org.sleuthkit.autopsy.discovery.search.SearchData; /** @@ -29,7 +27,7 @@ import org.sleuthkit.autopsy.discovery.search.SearchData; final class DocumentFilterPanel extends AbstractFiltersPanel { private static final long serialVersionUID = 1L; - private static final FileSearchData.FileType FILE_TYPE = FileSearchData.FileType.DOCUMENTS; + private static final SearchData.Type TYPE = SearchData.Type.DOCUMENTS; /** * Constructs a new DocumentFilterPanel. @@ -37,7 +35,7 @@ final class DocumentFilterPanel extends AbstractFiltersPanel { DocumentFilterPanel() { super(); initComponents(); - SizeFilterPanel sizeFilterPanel = new SizeFilterPanel(FILE_TYPE); + SizeFilterPanel sizeFilterPanel = new SizeFilterPanel(TYPE); int[] sizeIndicesSelected = {3, 4, 5}; addFilter(sizeFilterPanel, true, sizeIndicesSelected, 0); addFilter(new DataSourceFilterPanel(), false, null, 0); @@ -47,7 +45,7 @@ final class DocumentFilterPanel extends AbstractFiltersPanel { } else { pastOccurrencesIndices = new int[]{2, 3, 4}; } - addFilter(new PastOccurrencesFilterPanel(), true, pastOccurrencesIndices, 0); + addFilter(new PastOccurrencesFilterPanel(TYPE), true, pastOccurrencesIndices, 0); addFilter(new HashSetFilterPanel(), false, null, 1); addFilter(new InterestingItemsFilterPanel(), false, null, 1); addFilter(new ParentFolderFilterPanel(), false, null, 1); @@ -94,21 +92,11 @@ final class DocumentFilterPanel extends AbstractFiltersPanel { add(documentFiltersScrollPane, java.awt.BorderLayout.CENTER); }// //GEN-END:initComponents @Override - FileSearchData.FileType getFileType() { - return FILE_TYPE; + SearchData.Type getType() { + return TYPE; } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JSplitPane documentsFiltersSplitPane; // End of variables declaration//GEN-END:variables - @Override - SearchData.ResultType getResultType() { - return SearchData.ResultType.FILE; - } - - @Override - AttributeSearchData.AttributeType getArtifactType() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentPanel.java index 68c15ce260..08bdd70791 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentPanel.java @@ -29,7 +29,7 @@ import javax.swing.JList; import javax.swing.ListCellRenderer; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.corecomponents.AutoWrappingJTextPane; -import org.sleuthkit.autopsy.discovery.search.FileSearchData; +import org.sleuthkit.autopsy.discovery.search.SearchData; /** * Class which displays a preview and details about a document. @@ -164,7 +164,7 @@ class DocumentPanel extends javax.swing.JPanel implements ListCellRenderer 0) { numberOfImagesLabel.setText(Bundle.DocumentPanel_numberOfImages_text(value.getSummary().getNumberOfImages())); sampleImageLabel.setIcon(new ImageIcon(value.getSummary().getSampleImage())); - } else if (FileSearchData.getDocTypesWithoutImageExtraction().contains(value.getResultFile().getFirstInstance().getMIMEType())) { + } else if (SearchData.getDocTypesWithoutImageExtraction().contains(value.getResultFile().getFirstInstance().getMIMEType())) { numberOfImagesLabel.setText(Bundle.DocumentPanel_noImageExtraction_text()); sampleImageLabel.setIcon(DiscoveryUiUtils.getUnsupportedImageThumbnail()); } else { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java index 41abf48f2c..45ba72338c 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java @@ -19,8 +19,6 @@ package org.sleuthkit.autopsy.discovery.ui; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; -import org.sleuthkit.autopsy.discovery.search.AttributeSearchData; -import org.sleuthkit.autopsy.discovery.search.FileSearchData; import org.sleuthkit.autopsy.discovery.search.SearchData; /** @@ -29,7 +27,7 @@ import org.sleuthkit.autopsy.discovery.search.SearchData; public class DomainFilterPanel extends AbstractFiltersPanel { private static final long serialVersionUID = 1L; - private static final AttributeSearchData.AttributeType ARTIFACT_TYPE = AttributeSearchData.AttributeType.DOMAIN; + private static final SearchData.Type TYPE = SearchData.Type.DOMAIN; /** * Creates new form DomainFilterPanel. @@ -44,7 +42,7 @@ public class DomainFilterPanel extends AbstractFiltersPanel { if (CentralRepository.isEnabled()) { pastOccurrencesIndices = new int[]{2, 3, 4}; } - addFilter(new PastOccurrencesFilterPanel(SearchData.ResultType.ATTRIBUTE), true, pastOccurrencesIndices, 0); + addFilter(new PastOccurrencesFilterPanel(TYPE), true, pastOccurrencesIndices, 0); addPanelsToScrollPane(domainFiltersSplitPane); } @@ -91,19 +89,10 @@ public class DomainFilterPanel extends AbstractFiltersPanel { }// //GEN-END:initComponents @Override - FileSearchData.FileType getFileType() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + SearchData.Type getType() { + return TYPE; } - @Override - SearchData.ResultType getResultType() { - return SearchData.ResultType.ATTRIBUTE; - } - - @Override - AttributeSearchData.AttributeType getArtifactType() { - return ARTIFACT_TYPE; - } // Variables declaration - do not modify//GEN-BEGIN:variables diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java index dad5c1e819..ddca7c785e 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java @@ -31,9 +31,9 @@ import javax.swing.SwingUtilities; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; -import org.sleuthkit.autopsy.discovery.search.FileGroup; +import org.sleuthkit.autopsy.discovery.search.Group; import org.sleuthkit.autopsy.discovery.search.FileSearch; -import org.sleuthkit.autopsy.discovery.search.FileSearchData.FileType; +import org.sleuthkit.autopsy.discovery.search.SearchData.Type; import org.sleuthkit.autopsy.discovery.search.FileSorter; /** @@ -42,11 +42,11 @@ import org.sleuthkit.autopsy.discovery.search.FileSorter; final class GroupListPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; - private FileType fileType = null; + private Type type = null; private Map groupMap = null; private List searchfilters; private FileSearch.AttributeType groupingAttribute; - private FileGroup.GroupSortingAlgorithm groupSort; + private Group.GroupSortingAlgorithm groupSort; private FileSorter.SortingMethod fileSortMethod; private GroupKey selectedGroupKey; @@ -64,7 +64,7 @@ final class GroupListPanel extends javax.swing.JPanel { */ @Subscribe void handleSearchStartedEvent(DiscoveryEventUtils.SearchStartedEvent searchStartedEvent) { - fileType = searchStartedEvent.getFileType(); + type = searchStartedEvent.getType(); groupKeyList.setListData(new GroupKey[0]); } @@ -175,7 +175,7 @@ final class GroupListPanel extends javax.swing.JPanel { if (selectedGroup.equals(groupKey)) { selectedGroupKey = groupKey; DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.GroupSelectedEvent( - searchfilters, groupingAttribute, groupSort, fileSortMethod, selectedGroupKey, groupMap.get(selectedGroupKey), fileType)); + searchfilters, groupingAttribute, groupSort, fileSortMethod, selectedGroupKey, groupMap.get(selectedGroupKey), type)); break; } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageFilterPanel.java index be0419bbd8..308cdd569b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ImageFilterPanel.java @@ -19,8 +19,6 @@ package org.sleuthkit.autopsy.discovery.ui; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; -import org.sleuthkit.autopsy.discovery.search.AttributeSearchData; -import org.sleuthkit.autopsy.discovery.search.FileSearchData; import org.sleuthkit.autopsy.discovery.search.SearchData; /** @@ -29,7 +27,7 @@ import org.sleuthkit.autopsy.discovery.search.SearchData; final class ImageFilterPanel extends AbstractFiltersPanel { private static final long serialVersionUID = 1L; - private static final FileSearchData.FileType FILE_TYPE = FileSearchData.FileType.IMAGE; + private static final SearchData.Type TYPE = SearchData.Type.IMAGE; /** * Creates new form ImageFilterPanel. @@ -37,7 +35,7 @@ final class ImageFilterPanel extends AbstractFiltersPanel { ImageFilterPanel() { super(); initComponents(); - SizeFilterPanel sizeFilterPanel = new SizeFilterPanel(FILE_TYPE); + SizeFilterPanel sizeFilterPanel = new SizeFilterPanel(TYPE); int[] sizeIndicesSelected = {3, 4, 5}; addFilter(sizeFilterPanel, true, sizeIndicesSelected, 0); addFilter(new DataSourceFilterPanel(), false, null, 0); @@ -47,7 +45,7 @@ final class ImageFilterPanel extends AbstractFiltersPanel { } else { pastOccurrencesIndices = new int[]{2, 3, 4}; } - addFilter(new PastOccurrencesFilterPanel(), true, pastOccurrencesIndices, 0); + addFilter(new PastOccurrencesFilterPanel(TYPE), true, pastOccurrencesIndices, 0); addFilter(new UserCreatedFilterPanel(), false, null, 1); addFilter(new HashSetFilterPanel(), false, null, 1); addFilter(new InterestingItemsFilterPanel(), false, null, 1); @@ -99,21 +97,12 @@ final class ImageFilterPanel extends AbstractFiltersPanel { }// //GEN-END:initComponents @Override - FileSearchData.FileType getFileType() { - return FILE_TYPE; + SearchData.Type getType() { + return TYPE; } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JSplitPane imageFiltersSplitPane; // End of variables declaration//GEN-END:variables - @Override - SearchData.ResultType getResultType() { - return SearchData.ResultType.FILE; - } - - @Override - AttributeSearchData.AttributeType getArtifactType() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java index 2372f01788..1139366cf0 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java @@ -28,10 +28,10 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; -import org.sleuthkit.autopsy.discovery.search.FileGroup; +import org.sleuthkit.autopsy.discovery.search.Group; import org.sleuthkit.autopsy.discovery.search.FileSearch; -import org.sleuthkit.autopsy.discovery.search.FileSearchData; -import org.sleuthkit.autopsy.discovery.search.FileSearchException; +import org.sleuthkit.autopsy.discovery.search.SearchData; +import org.sleuthkit.autopsy.discovery.search.DiscoveryException; import org.sleuthkit.autopsy.discovery.search.FileSorter; import org.sleuthkit.autopsy.discovery.search.ResultFile; @@ -44,12 +44,12 @@ final class PageWorker extends SwingWorker { private static final String USER_NAME_PROPERTY = "user.name"; //NON-NLS private final List searchfilters; private final FileSearch.AttributeType groupingAttribute; - private final FileGroup.GroupSortingAlgorithm groupSort; + private final Group.GroupSortingAlgorithm groupSort; private final FileSorter.SortingMethod fileSortMethod; private final GroupKey groupKey; private final int startingEntry; private final int pageSize; - private final FileSearchData.FileType resultType; + private final SearchData.Type resultType; private final CentralRepository centralRepo; private final List results = new ArrayList<>(); @@ -70,8 +70,8 @@ final class PageWorker extends SwingWorker { * @param centralRepo The central repository to be used. */ PageWorker(List searchfilters, FileSearch.AttributeType groupingAttribute, - FileGroup.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod, GroupKey groupKey, - int startingEntry, int pageSize, FileSearchData.FileType resultType, CentralRepository centralRepo) { + Group.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod, GroupKey groupKey, + int startingEntry, int pageSize, SearchData.Type resultType, CentralRepository centralRepo) { this.searchfilters = searchfilters; this.groupingAttribute = groupingAttribute; this.groupSort = groupSort; @@ -93,7 +93,7 @@ final class PageWorker extends SwingWorker { groupSort, fileSortMethod, groupKey, startingEntry, pageSize, Case.getCurrentCase().getSleuthkitCase(), centralRepo)); - } catch (FileSearchException ex) { + } catch (DiscoveryException ex) { logger.log(Level.SEVERE, "Error running file search test", ex); cancel(true); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java index 15d20aa6e8..648566a69f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java @@ -24,9 +24,9 @@ import javax.swing.JLabel; import javax.swing.JList; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.discovery.search.AbstractFilter; -import org.sleuthkit.autopsy.discovery.search.FileSearchData; -import org.sleuthkit.autopsy.discovery.search.FileSearchData.Frequency; -import org.sleuthkit.autopsy.discovery.search.SearchData.ResultType; +import org.sleuthkit.autopsy.discovery.search.SearchData; +import org.sleuthkit.autopsy.discovery.search.SearchData.Frequency; +import org.sleuthkit.autopsy.discovery.search.SearchData.Type; import org.sleuthkit.autopsy.discovery.search.SearchFiltering; /** @@ -35,21 +35,12 @@ import org.sleuthkit.autopsy.discovery.search.SearchFiltering; final class PastOccurrencesFilterPanel extends AbstractDiscoveryFilterPanel { private static final long serialVersionUID = 1L; - private final ResultType type; + private final Type type; /** * Creates new form PastOccurrencesFilterPanel. */ - PastOccurrencesFilterPanel() { - initComponents(); - type = ResultType.FILE; - setUpFrequencyFilter(); - } - - /** - * Creates new form PastOccurrencesFilterPanel. - */ - PastOccurrencesFilterPanel(ResultType type) { + PastOccurrencesFilterPanel(Type type) { initComponents(); this.type = type; setUpFrequencyFilter(); @@ -111,17 +102,17 @@ final class PastOccurrencesFilterPanel extends AbstractDiscoveryFilterPanel { */ private void setUpFrequencyFilter() { int count = 0; - DefaultListModel frequencyListModel = (DefaultListModel) crFrequencyList.getModel(); + DefaultListModel frequencyListModel = (DefaultListModel) crFrequencyList.getModel(); frequencyListModel.removeAllElements(); if (!CentralRepository.isEnabled()) { - if (type != ResultType.ATTRIBUTE) { - for (FileSearchData.Frequency freq : FileSearchData.Frequency.getOptionsForFilteringWithoutCr()) { + if (type != Type.DOMAIN) { + for (SearchData.Frequency freq : SearchData.Frequency.getOptionsForFilteringWithoutCr()) { frequencyListModel.add(count, freq); } } } else { - for (FileSearchData.Frequency freq : FileSearchData.Frequency.getOptionsForFilteringWithCr()) { - if (type == ResultType.FILE || freq != FileSearchData.Frequency.KNOWN) { + for (SearchData.Frequency freq : SearchData.Frequency.getOptionsForFilteringWithCr()) { + if (type != Type.DOMAIN || freq != SearchData.Frequency.KNOWN) { frequencyListModel.add(count, freq); } } @@ -136,7 +127,7 @@ final class PastOccurrencesFilterPanel extends AbstractDiscoveryFilterPanel { @Override void configurePanel(boolean selected, int[] indicesSelected) { - boolean canBeFilteredOn = type == ResultType.FILE || CentralRepository.isEnabled(); + boolean canBeFilteredOn = type != Type.DOMAIN || CentralRepository.isEnabled(); pastOccurrencesCheckbox.setEnabled(canBeFilteredOn); pastOccurrencesCheckbox.setSelected(selected && canBeFilteredOn); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java index 9cd9cbd78a..c6551d7706 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java @@ -40,9 +40,9 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; -import org.sleuthkit.autopsy.discovery.search.FileGroup; +import org.sleuthkit.autopsy.discovery.search.Group; import org.sleuthkit.autopsy.discovery.search.FileSearch; -import org.sleuthkit.autopsy.discovery.search.FileSearchData; +import org.sleuthkit.autopsy.discovery.search.SearchData; import org.sleuthkit.autopsy.discovery.search.FileSorter; import org.sleuthkit.autopsy.discovery.search.ResultFile; import org.sleuthkit.autopsy.textsummarizer.TextSummary; @@ -60,12 +60,12 @@ final class ResultsPanel extends javax.swing.JPanel { private final DocumentPreviewViewer documentPreviewViewer; private List searchFilters; private FileSearch.AttributeType groupingAttribute; - private FileGroup.GroupSortingAlgorithm groupSort; + private Group.GroupSortingAlgorithm groupSort; private FileSorter.SortingMethod fileSortMethod; private GroupKey selectedGroupKey; private int currentPage = 0; private int previousPageSize = 10; - private FileSearchData.FileType resultType; + private SearchData.Type resultType; private int groupSize = 0; private PageWorker pageWorker; private final List> resultContentWorkers = new ArrayList<>(); @@ -81,7 +81,7 @@ final class ResultsPanel extends javax.swing.JPanel { videoThumbnailViewer = new VideoThumbnailViewer(); documentPreviewViewer = new DocumentPreviewViewer(); videoThumbnailViewer.addListSelectionListener((e) -> { - if (resultType == FileSearchData.FileType.VIDEO) { + if (resultType == SearchData.Type.VIDEO) { if (!e.getValueIsAdjusting()) { //send populateMesage DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.PopulateInstancesListEvent(getInstancesForSelected())); @@ -92,7 +92,7 @@ final class ResultsPanel extends javax.swing.JPanel { } }); imageThumbnailViewer.addListSelectionListener((e) -> { - if (resultType == FileSearchData.FileType.IMAGE) { + if (resultType == SearchData.Type.IMAGE) { if (!e.getValueIsAdjusting()) { //send populateMesage DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.PopulateInstancesListEvent(getInstancesForSelected())); @@ -104,7 +104,7 @@ final class ResultsPanel extends javax.swing.JPanel { } }); documentPreviewViewer.addListSelectionListener((e) -> { - if (resultType == FileSearchData.FileType.DOCUMENTS) { + if (resultType == SearchData.Type.DOCUMENTS) { if (!e.getValueIsAdjusting()) { //send populateMesage DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.PopulateInstancesListEvent(getInstancesForSelected())); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java index 0013d610dd..49b2de3d71 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java @@ -29,9 +29,9 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; -import org.sleuthkit.autopsy.discovery.search.FileGroup; +import org.sleuthkit.autopsy.discovery.search.Group; import org.sleuthkit.autopsy.discovery.search.FileSearch; -import org.sleuthkit.autopsy.discovery.search.FileSearchException; +import org.sleuthkit.autopsy.discovery.search.DiscoveryException; import org.sleuthkit.autopsy.discovery.search.FileSorter; /** @@ -44,7 +44,7 @@ final class SearchWorker extends SwingWorker { private final List filters; private final FileSearch.AttributeType groupingAttr; private final FileSorter.SortingMethod fileSort; - private final FileGroup.GroupSortingAlgorithm groupSortAlgorithm; + private final Group.GroupSortingAlgorithm groupSortAlgorithm; private final CentralRepository centralRepoDb; private final Map results = new LinkedHashMap<>(); @@ -58,7 +58,7 @@ final class SearchWorker extends SwingWorker { * @param groupSort The Algorithm to sort groups by. * @param fileSortMethod The SortingMethod to use for files. */ - SearchWorker(CentralRepository centralRepo, List searchfilters, FileSearch.AttributeType groupingAttribute, FileGroup.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod) { + SearchWorker(CentralRepository centralRepo, List searchfilters, FileSearch.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod) { centralRepoDb = centralRepo; filters = searchfilters; groupingAttr = groupingAttribute; @@ -75,7 +75,7 @@ final class SearchWorker extends SwingWorker { groupSortAlgorithm, fileSort, Case.getCurrentCase().getSleuthkitCase(), centralRepoDb)); - } catch (FileSearchException ex) { + } catch (DiscoveryException ex) { logger.log(Level.SEVERE, "Error running file search test", ex); cancel(true); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/SizeFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/SizeFilterPanel.java index 65c5330da5..b0a71fbd25 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/SizeFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/SizeFilterPanel.java @@ -25,8 +25,8 @@ import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; -import org.sleuthkit.autopsy.discovery.search.FileSearchData; -import org.sleuthkit.autopsy.discovery.search.FileSearchData.FileSize; +import org.sleuthkit.autopsy.discovery.search.SearchData; +import org.sleuthkit.autopsy.discovery.search.SearchData.FileSize; import org.sleuthkit.autopsy.discovery.search.SearchFiltering; /** @@ -41,7 +41,7 @@ final class SizeFilterPanel extends AbstractDiscoveryFilterPanel { * * @param type The type of result being searched for. */ - SizeFilterPanel(FileSearchData.FileType type) { + SizeFilterPanel(SearchData.Type type) { initComponents(); setUpSizeFilter(type); } @@ -136,7 +136,7 @@ final class SizeFilterPanel extends AbstractDiscoveryFilterPanel { /** * Initialize the file size filter. */ - private void setUpSizeFilter(FileSearchData.FileType fileType) { + private void setUpSizeFilter(SearchData.Type fileType) { int count = 0; DefaultListModel sizeListModel = (DefaultListModel) sizeList.getModel(); sizeListModel.removeAllElements(); @@ -145,7 +145,7 @@ final class SizeFilterPanel extends AbstractDiscoveryFilterPanel { sizeListModel.add(count, size); } } else { - List sizes; + List sizes; switch (fileType) { case VIDEO: sizes = FileSize.getOptionsForVideos(); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoFilterPanel.java index c002fe322f..82b0d030bc 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/VideoFilterPanel.java @@ -19,8 +19,6 @@ package org.sleuthkit.autopsy.discovery.ui; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; -import org.sleuthkit.autopsy.discovery.search.AttributeSearchData; -import org.sleuthkit.autopsy.discovery.search.FileSearchData; import org.sleuthkit.autopsy.discovery.search.SearchData; /** @@ -29,7 +27,7 @@ import org.sleuthkit.autopsy.discovery.search.SearchData; final class VideoFilterPanel extends AbstractFiltersPanel { private static final long serialVersionUID = 1L; - private static final FileSearchData.FileType FILE_TYPE = FileSearchData.FileType.VIDEO; + private static final SearchData.Type TYPE = SearchData.Type.VIDEO; /** * Creates new form VideoFilterPanel. @@ -37,7 +35,7 @@ final class VideoFilterPanel extends AbstractFiltersPanel { VideoFilterPanel() { super(); initComponents(); - SizeFilterPanel sizeFilterPanel = new SizeFilterPanel(FILE_TYPE); + SizeFilterPanel sizeFilterPanel = new SizeFilterPanel(TYPE); int[] sizeIndicesSelected = {3, 4, 5}; addFilter(sizeFilterPanel, true, sizeIndicesSelected, 0); addFilter(new DataSourceFilterPanel(), false, null, 0); @@ -47,7 +45,7 @@ final class VideoFilterPanel extends AbstractFiltersPanel { } else { pastOccurrencesIndices = new int[]{2, 3, 4}; } - addFilter(new PastOccurrencesFilterPanel(), true, pastOccurrencesIndices, 0); + addFilter(new PastOccurrencesFilterPanel(TYPE), true, pastOccurrencesIndices, 0); addFilter(new UserCreatedFilterPanel(), false, null, 1); addFilter(new HashSetFilterPanel(), false, null, 1); addFilter(new InterestingItemsFilterPanel(), false, null, 1); @@ -100,22 +98,12 @@ final class VideoFilterPanel extends AbstractFiltersPanel { add(videoFiltersScrollPane, java.awt.BorderLayout.CENTER); }// //GEN-END:initComponents @Override - FileSearchData.FileType getFileType() { - return FILE_TYPE; + SearchData.Type getType() { + return TYPE; } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JSplitPane videoFiltersSplitPane; // End of variables declaration//GEN-END:variables - @Override - SearchData.ResultType getResultType() { - return SearchData.ResultType.FILE; - } - - @Override - AttributeSearchData.AttributeType getArtifactType() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - } From 1b73edee7d3a0f110d408744dc8874ed1e6fb62e Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 20 Aug 2020 13:37:12 -0400 Subject: [PATCH 023/130] 6711 move attributes out of file search class --- .../discovery/search/Bundle.properties-MERGED | 69 +- .../discovery/search/DiscoveryAttributes.java | 653 ++++++++++++++++++ .../discovery/search/DiscoveryEventUtils.java | 12 +- .../discovery/search/DiscoveryKeyUtils.java | 2 +- .../autopsy/discovery/search/FileSearch.java | 625 +---------------- .../autopsy/discovery/search/FileSorter.java | 12 +- .../discovery/search/SearchFiltering.java | 2 +- .../discovery/search/SearchResults.java | 6 +- .../autopsy/discovery/ui/DiscoveryDialog.java | 10 +- .../autopsy/discovery/ui/GroupListPanel.java | 6 +- .../autopsy/discovery/ui/PageWorker.java | 5 +- .../autopsy/discovery/ui/ResultsPanel.java | 3 +- .../autopsy/discovery/ui/SearchWorker.java | 5 +- 13 files changed, 721 insertions(+), 689 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED index 9924fbae02..41cab2b5c2 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED @@ -1,5 +1,3 @@ -AttributeSearchData.AttributeType.Domain.displayName=Domain -AttributeSearchData.AttributeType.Other.displayName=Other DiscoveryKeyUtils.FileTagGroupKey.noSets=None DiscoveryKeyUtils.NoGroupingGroupKey.allFiles=All Files FileGroup.groupSortingAlgorithm.groupName.text=Group Name @@ -26,39 +24,6 @@ FileSearch.HashHitsGroupKey.noHashHits=None FileSearch.InterestingItemGroupKey.noSets=None FileSearch.KeywordListGroupKey.noKeywords=None FileSearch.ObjectDetectedGroupKey.noSets=None -FileSearchData.FileSize.100kbto1mb=: 100KB-1MB -FileSearchData.FileSize.100mbto1gb=: 100MB-1GB -FileSearchData.FileSize.10PlusGb=: 10GB+ -FileSearchData.FileSize.16kbto100kb=: 16-100KB -FileSearchData.FileSize.1gbto5gb=: 1-5GB -FileSearchData.FileSize.1mbto50mb=: 1-50MB -FileSearchData.FileSize.200PlusMb=: 200MB+ -FileSearchData.FileSize.500kbto100mb=: 500KB-100MB -FileSearchData.FileSize.50mbto200mb=: 50-200MB -FileSearchData.FileSize.5gbto10gb=: 5-10GB -FileSearchData.FileSize.LARGE.displayName=Large -FileSearchData.FileSize.MEDIUM.displayName=Medium -FileSearchData.FileSize.SMALL.displayName=Small -FileSearchData.FileSize.upTo16kb=: 0-16KB -FileSearchData.FileSize.upTo500kb=: 0-500KB -FileSearchData.FileSize.XLARGE.displayName=XLarge -FileSearchData.FileSize.XSMALL.displayName=XSmall -FileSearchData.FileSize.XXLARGE.displayName=XXLarge -FileSearchData.FileType.Audio.displayName=Audio -FileSearchData.FileType.Documents.displayName=Documents -FileSearchData.FileType.Executables.displayName=Executables -FileSearchData.FileType.Image.displayName=Image -FileSearchData.FileType.Other.displayName=Other/Unknown -FileSearchData.FileType.Video.displayName=Video -FileSearchData.Frequency.common.displayName=Common (11 - 100) -FileSearchData.Frequency.known.displayName=Known (NSRL) -FileSearchData.Frequency.rare.displayName=Rare (2-10) -FileSearchData.Frequency.unique.displayName=Unique (1) -FileSearchData.Frequency.unknown.displayName=Unknown -FileSearchData.Frequency.verycommon.displayName=Very Common (100+) -FileSearchData.Score.interesting.displayName=Interesting -FileSearchData.Score.notable.displayName=Notable -FileSearchData.Score.unknown.displayName=Unknown FileSearchFiltering.concatenateSetNamesForDisplay.comma=, # {0} - filters FileSearchFiltering.HashSetFilter.desc=Hash set hits in set(s): {0} @@ -79,6 +44,40 @@ ResultFile.score.interestingResult.description=At least one instance of the file ResultFile.score.notableFile.description=At least one instance of the file was recognized as notable. ResultFile.score.notableTaggedFile.description=At least one instance of the file is tagged with a notable tag. ResultFile.score.taggedFile.description=At least one instance of the file has been tagged. +SearchData.AttributeType.Domain.displayName=Domains +SearchData.FileSize.100kbto1mb=: 100KB-1MB +SearchData.FileSize.100mbto1gb=: 100MB-1GB +SearchData.FileSize.10PlusGb=: 10GB+ +SearchData.FileSize.16kbto100kb=: 16-100KB +SearchData.FileSize.1gbto5gb=: 1-5GB +SearchData.FileSize.1mbto50mb=: 1-50MB +SearchData.FileSize.200PlusMb=: 200MB+ +SearchData.FileSize.500kbto100mb=: 500KB-100MB +SearchData.FileSize.50mbto200mb=: 50-200MB +SearchData.FileSize.5gbto10gb=: 5-10GB +SearchData.FileSize.LARGE.displayName=Large +SearchData.FileSize.MEDIUM.displayName=Medium +SearchData.FileSize.SMALL.displayName=Small +SearchData.FileSize.upTo16kb=: 0-16KB +SearchData.FileSize.upTo500kb=: 0-500KB +SearchData.FileSize.XLARGE.displayName=XLarge +SearchData.FileSize.XSMALL.displayName=XSmall +SearchData.FileSize.XXLARGE.displayName=XXLarge +SearchData.FileType.Audio.displayName=Audio +SearchData.FileType.Documents.displayName=Documents +SearchData.FileType.Executables.displayName=Executables +SearchData.FileType.Image.displayName=Image +SearchData.FileType.Other.displayName=Other/Unknown +SearchData.FileType.Video.displayName=Video +SearchData.Frequency.common.displayName=Common (11 - 100) +SearchData.Frequency.known.displayName=Known (NSRL) +SearchData.Frequency.rare.displayName=Rare (2-10) +SearchData.Frequency.unique.displayName=Unique (1) +SearchData.Frequency.unknown.displayName=Unknown +SearchData.Frequency.verycommon.displayName=Very Common (100+) +SearchData.Score.interesting.displayName=Interesting +SearchData.Score.notable.displayName=Notable +SearchData.Score.unknown.displayName=Unknown # {0} - Data source name # {1} - Data source ID SearchFiltering.DataSourceFilter.datasource={0}({1}) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java new file mode 100644 index 0000000000..54123077e8 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java @@ -0,0 +1,653 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.discovery.search; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbUtil; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; +import org.sleuthkit.autopsy.centralrepository.datamodel.InstanceTableCallback; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.CaseDbAccessManager; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; + +/** + * + * @author wschaefer + */ +public class DiscoveryAttributes { + + private final static Logger logger = Logger.getLogger(DiscoveryAttributes.class.getName()); + + /** + * Base class for the grouping attributes. + */ + public abstract static class AttributeType { + + /** + * For a given file, return the key for the group it belongs to for this + * attribute type. + * + * @param file the result file to be grouped + * + * @return the key for the group this file goes in + */ + public abstract DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file); + + /** + * Add any extra data to the ResultFile object from this attribute. + * + * @param files The list of files to enhance + * @param caseDb The case database + * @param centralRepoDb The central repository database. Can be null if + * not needed. + * + * @throws DiscoveryException + */ + public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { + // Default is to do nothing + } + } + + /** + * Attribute for grouping/sorting by file size + */ + public static class FileSizeAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.FileSizeGroupKey(file); + } + } + + /** + * Attribute for grouping/sorting by parent path + */ + public static class ParentPathAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.ParentPathGroupKey(file); + } + } + + /** + * Default attribute used to make one group + */ + static class NoGroupingAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.NoGroupingGroupKey(); + } + } + + /** + * Attribute for grouping/sorting by data source + */ + static class DataSourceAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.DataSourceGroupKey(file); + } + } + + /** + * Attribute for grouping/sorting by file type + */ + static class FileTypeAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.FileTypeGroupKey(file); + } + } + + /** + * Attribute for grouping/sorting by keyword lists + */ + static class KeywordListAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.KeywordListGroupKey(file); + } + + @Override + public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + CentralRepository centralRepoDb) throws DiscoveryException { + + // Get pairs of (object ID, keyword list name) for all files in the list of files that have + // keyword list hits. + String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID(), + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()); + + SetKeywordListNamesCallback callback = new SetKeywordListNamesCallback(files); + try { + caseDb.getCaseDbAccessManager().select(selectQuery, callback); + } catch (TskCoreException ex) { + throw new DiscoveryException("Error looking up keyword list attributes", ex); // NON-NLS + } + } + + /** + * Callback to process the results of the CaseDbAccessManager select + * query. Will add the keyword list names to the list of ResultFile + * objects. + */ + private static class SetKeywordListNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { + + List resultFiles; + + /** + * Create the callback. + * + * @param resultFiles List of files to add keyword list names to + */ + SetKeywordListNamesCallback(List resultFiles) { + this.resultFiles = resultFiles; + } + + @Override + public void process(ResultSet rs) { + try { + // Create a temporary map of object ID to ResultFile + Map tempMap = new HashMap<>(); + for (ResultFile file : resultFiles) { + tempMap.put(file.getFirstInstance().getId(), file); + } + + while (rs.next()) { + try { + Long objId = rs.getLong("object_id"); // NON-NLS + String keywordListName = rs.getString("set_name"); // NON-NLS + + tempMap.get(objId).addKeywordListName(keywordListName); + + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Unable to get object_id or set_name from result set", ex); // NON-NLS + } + } + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Failed to get keyword list names", ex); // NON-NLS + } + } + } + } + + /** + * Attribute for grouping/sorting by frequency in the central repository + */ + static class FrequencyAttribute extends AttributeType { + + static final int BATCH_SIZE = 50; // Number of hashes to look up at one time + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.FrequencyGroupKey(file); + } + + @Override + public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + CentralRepository centralRepoDb) throws DiscoveryException { + if (centralRepoDb == null) { + for (ResultFile file : files) { + if (file.getFrequency() == SearchData.Frequency.UNKNOWN && file.getFirstInstance().getKnown() == TskData.FileKnown.KNOWN) { + file.setFrequency(SearchData.Frequency.KNOWN); + } + } + } else { + processResultFilesForCR(files, centralRepoDb); + } + } + + /** + * Private helper method for adding Frequency attribute when CR is + * enabled. + * + * @param files The list of ResultFiles to caluclate frequency + * for. + * @param centralRepoDb The central repository currently in use. + */ + private void processResultFilesForCR(List files, + CentralRepository centralRepoDb) { + List currentFiles = new ArrayList<>(); + Set hashesToLookUp = new HashSet<>(); + for (ResultFile file : files) { + if (file.getFirstInstance().getKnown() == TskData.FileKnown.KNOWN) { + file.setFrequency(SearchData.Frequency.KNOWN); + } + if (file.getFrequency() == SearchData.Frequency.UNKNOWN + && file.getFirstInstance().getMd5Hash() != null + && !file.getFirstInstance().getMd5Hash().isEmpty()) { + hashesToLookUp.add(file.getFirstInstance().getMd5Hash()); + currentFiles.add(file); + } + if (hashesToLookUp.size() >= BATCH_SIZE) { + computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); + + hashesToLookUp.clear(); + currentFiles.clear(); + } + } + computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); + } + } + + /** + * Callback to use with findInterCaseValuesByCount which generates a list of + * values for common property search + */ + private static class FrequencyCallback implements InstanceTableCallback { + + private final List files; + + private FrequencyCallback(List files) { + this.files = new ArrayList<>(files); + } + + @Override + public void process(ResultSet resultSet) { + try { + + while (resultSet.next()) { + String hash = resultSet.getString(1); + int count = resultSet.getInt(2); + for (Iterator iterator = files.iterator(); iterator.hasNext();) { + ResultFile file = iterator.next(); + if (file.getFirstInstance().getMd5Hash().equalsIgnoreCase(hash)) { + file.setFrequency(SearchData.Frequency.fromCount(count)); + iterator.remove(); + } + } + } + + // The files left had no matching entries in the CR, so mark them as unique + for (ResultFile file : files) { + file.setFrequency(SearchData.Frequency.UNIQUE); + } + } catch (SQLException ex) { + logger.log(Level.WARNING, "Error getting frequency counts from Central Repository", ex); // NON-NLS + } + } + } + + /** + * Attribute for grouping/sorting by hash set lists + */ + static class HashHitsAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.HashHitsGroupKey(file); + } + + @Override + public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + CentralRepository centralRepoDb) throws DiscoveryException { + + // Get pairs of (object ID, hash set name) for all files in the list of files that have + // hash set hits. + String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(), + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()); + + HashSetNamesCallback callback = new HashSetNamesCallback(files); + try { + caseDb.getCaseDbAccessManager().select(selectQuery, callback); + } catch (TskCoreException ex) { + throw new DiscoveryException("Error looking up hash set attributes", ex); // NON-NLS + } + } + + /** + * Callback to process the results of the CaseDbAccessManager select + * query. Will add the hash set names to the list of ResultFile objects. + */ + private static class HashSetNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { + + List resultFiles; + + /** + * Create the callback. + * + * @param resultFiles List of files to add hash set names to + */ + HashSetNamesCallback(List resultFiles) { + this.resultFiles = resultFiles; + } + + @Override + public void process(ResultSet rs) { + try { + // Create a temporary map of object ID to ResultFile + Map tempMap = new HashMap<>(); + for (ResultFile file : resultFiles) { + tempMap.put(file.getFirstInstance().getId(), file); + } + + while (rs.next()) { + try { + Long objId = rs.getLong("object_id"); // NON-NLS + String hashSetName = rs.getString("set_name"); // NON-NLS + + tempMap.get(objId).addHashSetName(hashSetName); + + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Unable to get object_id or set_name from result set", ex); // NON-NLS + } + } + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Failed to get hash set names", ex); // NON-NLS + } + } + } + } + + /** + * Attribute for grouping/sorting by interesting item set lists + */ + static class InterestingItemAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.InterestingItemGroupKey(file); + } + + @Override + public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + CentralRepository centralRepoDb) throws DiscoveryException { + + // Get pairs of (object ID, interesting item set name) for all files in the list of files that have + // interesting file set hits. + String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(), + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()); + + InterestingFileSetNamesCallback callback = new InterestingFileSetNamesCallback(files); + try { + caseDb.getCaseDbAccessManager().select(selectQuery, callback); + } catch (TskCoreException ex) { + throw new DiscoveryException("Error looking up interesting file set attributes", ex); // NON-NLS + } + } + + /** + * Callback to process the results of the CaseDbAccessManager select + * query. Will add the interesting file set names to the list of + * ResultFile objects. + */ + private static class InterestingFileSetNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { + + List resultFiles; + + /** + * Create the callback. + * + * @param resultFiles List of files to add interesting file set + * names to + */ + InterestingFileSetNamesCallback(List resultFiles) { + this.resultFiles = resultFiles; + } + + @Override + public void process(ResultSet rs) { + try { + // Create a temporary map of object ID to ResultFile + Map tempMap = new HashMap<>(); + for (ResultFile file : resultFiles) { + tempMap.put(file.getFirstInstance().getId(), file); + } + + while (rs.next()) { + try { + Long objId = rs.getLong("object_id"); // NON-NLS + String setName = rs.getString("set_name"); // NON-NLS + + tempMap.get(objId).addInterestingSetName(setName); + + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Unable to get object_id or set_name from result set", ex); // NON-NLS + } + } + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Failed to get interesting file set names", ex); // NON-NLS + } + } + } + } + + /** + * Attribute for grouping/sorting by objects detected + */ + static class ObjectDetectedAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.ObjectDetectedGroupKey(file); + } + + @Override + public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + CentralRepository centralRepoDb) throws DiscoveryException { + + // Get pairs of (object ID, object type name) for all files in the list of files that have + // objects detected + String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID(), + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID()); + + ObjectDetectedNamesCallback callback = new ObjectDetectedNamesCallback(files); + try { + caseDb.getCaseDbAccessManager().select(selectQuery, callback); + } catch (TskCoreException ex) { + throw new DiscoveryException("Error looking up object detected attributes", ex); // NON-NLS + } + } + + /** + * Callback to process the results of the CaseDbAccessManager select + * query. Will add the object type names to the list of ResultFile + * objects. + */ + private static class ObjectDetectedNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { + + List resultFiles; + + /** + * Create the callback. + * + * @param resultFiles List of files to add object detected names to + */ + ObjectDetectedNamesCallback(List resultFiles) { + this.resultFiles = resultFiles; + } + + @Override + public void process(ResultSet rs) { + try { + // Create a temporary map of object ID to ResultFile + Map tempMap = new HashMap<>(); + for (ResultFile file : resultFiles) { + tempMap.put(file.getFirstInstance().getId(), file); + } + + while (rs.next()) { + try { + Long objId = rs.getLong("object_id"); // NON-NLS + String setName = rs.getString("set_name"); // NON-NLS + + tempMap.get(objId).addObjectDetectedName(setName); + + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Unable to get object_id or set_name from result set", ex); // NON-NLS + } + } + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Failed to get object detected names", ex); // NON-NLS + } + } + } + } + + /** + * Attribute for grouping/sorting by tag name + */ + static class FileTagAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.FileTagGroupKey(file); + } + + @Override + public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + CentralRepository centralRepoDb) throws DiscoveryException { + + try { + for (ResultFile resultFile : files) { + List contentTags = caseDb.getContentTagsByContent(resultFile.getFirstInstance()); + + for (ContentTag tag : contentTags) { + resultFile.addTagName(tag.getName().getDisplayName()); + } + } + } catch (TskCoreException ex) { + throw new DiscoveryException("Error looking up file tag attributes", ex); // NON-NLS + } + } + } + + /** + * Enum for the attribute types that can be used for grouping. + */ + @NbBundle.Messages({ + "DiscoveryAttributes.GroupingAttributeType.fileType.displayName=File Type", + "DiscoveryAttributes.GroupingAttributeType.frequency.displayName=Past Occurrences", + "DiscoveryAttributes.GroupingAttributeType.keywordList.displayName=Keyword", + "DiscoveryAttributes.GroupingAttributeType.size.displayName=File Size", + "DiscoveryAttributes.GroupingAttributeType.datasource.displayName=Data Source", + "DiscoveryAttributes.GroupingAttributeType.parent.displayName=Parent Folder", + "DiscoveryAttributes.GroupingAttributeType.hash.displayName=Hash Set", + "DiscoveryAttributes.GroupingAttributeType.interestingItem.displayName=Interesting Item", + "DiscoveryAttributes.GroupingAttributeType.tag.displayName=Tag", + "DiscoveryAttributes.GroupingAttributeType.object.displayName=Object Detected", + "DiscoveryAttributes.GroupingAttributeType.none.displayName=None"}) + public enum GroupingAttributeType { + FILE_SIZE(new FileSizeAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_size_displayName()), + FREQUENCY(new FrequencyAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_frequency_displayName()), + KEYWORD_LIST_NAME(new KeywordListAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_keywordList_displayName()), + DATA_SOURCE(new DataSourceAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_datasource_displayName()), + PARENT_PATH(new ParentPathAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_parent_displayName()), + HASH_LIST_NAME(new HashHitsAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_hash_displayName()), + INTERESTING_ITEM_SET(new InterestingItemAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_interestingItem_displayName()), + FILE_TAG(new FileTagAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_tag_displayName()), + OBJECT_DETECTED(new ObjectDetectedAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_object_displayName()), + NO_GROUPING(new NoGroupingAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_none_displayName()); + + private final AttributeType attributeType; + private final String displayName; + + GroupingAttributeType(AttributeType attributeType, String displayName) { + this.attributeType = attributeType; + this.displayName = displayName; + } + + @Override + public String toString() { + return displayName; + } + + public AttributeType getAttributeType() { + return attributeType; + } + + /** + * Get the list of enums that are valid for grouping images. + * + * @return enums that can be used to group images + */ + public static List getOptionsForGrouping() { + return Arrays.asList(FILE_SIZE, FREQUENCY, PARENT_PATH, OBJECT_DETECTED, HASH_LIST_NAME, INTERESTING_ITEM_SET); + } + } + + /** + * Computes the CR frequency of all the given hashes and updates the list of + * files. + * + * @param hashesToLookUp Hashes to find the frequency of + * @param currentFiles List of files to update with frequencies + */ + private static void computeFrequency(Set hashesToLookUp, List currentFiles, CentralRepository centralRepoDb) { + + if (hashesToLookUp.isEmpty()) { + return; + } + + String hashes = String.join("','", hashesToLookUp); + hashes = "'" + hashes + "'"; + try { + CorrelationAttributeInstance.Type attributeType = centralRepoDb.getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID); + String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(attributeType); + + String selectClause = " value, COUNT(value) FROM " + + "(SELECT DISTINCT case_id, value FROM " + tableName + + " WHERE value IN (" + + hashes + + ")) AS foo GROUP BY value"; + + FrequencyCallback callback = new FrequencyCallback(currentFiles); + centralRepoDb.processSelectClause(selectClause, callback); + + } catch (CentralRepoException ex) { + logger.log(Level.WARNING, "Error getting frequency counts from Central Repository", ex); // NON-NLS + } + + } + + private static String createSetNameClause(List files, + int artifactTypeID, int setNameAttrID) throws DiscoveryException { + + // Concatenate the object IDs in the list of files + String objIdList = ""; // NON-NLS + for (ResultFile file : files) { + if (!objIdList.isEmpty()) { + objIdList += ","; // NON-NLS + } + objIdList += "\'" + file.getFirstInstance().getId() + "\'"; // NON-NLS + } + + // Get pairs of (object ID, set name) for all files in the list of files that have + // the given artifact type. + return "blackboard_artifacts.obj_id AS object_id, blackboard_attributes.value_text AS set_name " + + "FROM blackboard_artifacts " + + "INNER JOIN blackboard_attributes ON blackboard_artifacts.artifact_id=blackboard_attributes.artifact_id " + + "WHERE blackboard_attributes.artifact_type_id=\'" + artifactTypeID + "\' " + + "AND blackboard_attributes.attribute_type_id=\'" + setNameAttrID + "\' " + + "AND blackboard_artifacts.obj_id IN (" + objIdList + ") "; // NON-NLS + } + + private DiscoveryAttributes() { + // Class should not be instantiated + } +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java index 5bd5d81ef0..f58a6eb08b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java @@ -119,7 +119,7 @@ public final class DiscoveryEventUtils { private final Map groupMap; private final List searchFilters; - private final FileSearch.AttributeType groupingAttribute; + private final DiscoveryAttributes.AttributeType groupingAttribute; private final Group.GroupSortingAlgorithm groupSort; private final FileSorter.SortingMethod fileSortMethod; @@ -135,7 +135,7 @@ public final class DiscoveryEventUtils { * @param fileSortMethod The sorting method used for files. */ public SearchCompleteEvent(Map groupMap, List searchfilters, - FileSearch.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, + DiscoveryAttributes.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod) { this.groupMap = groupMap; this.searchFilters = searchfilters; @@ -167,7 +167,7 @@ public final class DiscoveryEventUtils { * * @return The grouping attribute used by the search. */ - public FileSearch.AttributeType getGroupingAttr() { + public DiscoveryAttributes.AttributeType getGroupingAttr() { return groupingAttribute; } @@ -278,7 +278,7 @@ public final class DiscoveryEventUtils { private final GroupKey groupKey; private final int groupSize; private final List searchfilters; - private final FileSearch.AttributeType groupingAttribute; + private final DiscoveryAttributes.AttributeType groupingAttribute; private final Group.GroupSortingAlgorithm groupSort; private final FileSorter.SortingMethod fileSortMethod; @@ -297,7 +297,7 @@ public final class DiscoveryEventUtils { * @param resultType The type of files which exist in the group. */ public GroupSelectedEvent(List searchfilters, - FileSearch.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, + DiscoveryAttributes.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod, GroupKey groupKey, int groupSize, Type resultType) { this.searchfilters = searchfilters; this.groupingAttribute = groupingAttribute; @@ -369,7 +369,7 @@ public final class DiscoveryEventUtils { * * @return The grouping attribute used by the search. */ - public FileSearch.AttributeType getGroupingAttr() { + public DiscoveryAttributes.AttributeType getGroupingAttr() { return groupingAttribute; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java index 481d354b8f..9eb172094f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java @@ -52,7 +52,7 @@ public class DiscoveryKeyUtils { * @param fileSortingMethod The method to sort the files by. */ SearchKey(String userName, List filters, - FileSearch.AttributeType groupAttributeType, + DiscoveryAttributes.AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, FileSorter.SortingMethod fileSortingMethod) { StringBuilder searchStringBuilder = new StringBuilder(); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java index 625f2140bd..b5d51d6810 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java @@ -21,35 +21,18 @@ package org.sleuthkit.autopsy.discovery.search; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import java.io.IOException; -import java.sql.ResultSet; -import java.sql.SQLException; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.logging.Level; import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; -import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; -import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbUtil; -import org.sleuthkit.autopsy.centralrepository.datamodel.InstanceTableCallback; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.discovery.search.SearchData.Frequency; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.CaseDbAccessManager; -import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.SleuthkitCase; -import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.datamodel.TskData; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes.AttributeType; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.SearchKey; import org.sleuthkit.autopsy.textsummarizer.TextSummarizer; @@ -322,615 +305,9 @@ public class FileSearch { } } - /** - * Computes the CR frequency of all the given hashes and updates the list of - * files. - * - * @param hashesToLookUp Hashes to find the frequency of - * @param currentFiles List of files to update with frequencies - */ - private static void computeFrequency(Set hashesToLookUp, List currentFiles, CentralRepository centralRepoDb) { - - if (hashesToLookUp.isEmpty()) { - return; - } - - String hashes = String.join("','", hashesToLookUp); - hashes = "'" + hashes + "'"; - try { - CorrelationAttributeInstance.Type attributeType = centralRepoDb.getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID); - String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(attributeType); - - String selectClause = " value, COUNT(value) FROM " - + "(SELECT DISTINCT case_id, value FROM " + tableName - + " WHERE value IN (" - + hashes - + ")) AS foo GROUP BY value"; - - FrequencyCallback callback = new FrequencyCallback(currentFiles); - centralRepoDb.processSelectClause(selectClause, callback); - - } catch (CentralRepoException ex) { - logger.log(Level.WARNING, "Error getting frequency counts from Central Repository", ex); // NON-NLS - } - - } - - private static String createSetNameClause(List files, - int artifactTypeID, int setNameAttrID) throws DiscoveryException { - - // Concatenate the object IDs in the list of files - String objIdList = ""; // NON-NLS - for (ResultFile file : files) { - if (!objIdList.isEmpty()) { - objIdList += ","; // NON-NLS - } - objIdList += "\'" + file.getFirstInstance().getId() + "\'"; // NON-NLS - } - - // Get pairs of (object ID, set name) for all files in the list of files that have - // the given artifact type. - return "blackboard_artifacts.obj_id AS object_id, blackboard_attributes.value_text AS set_name " - + "FROM blackboard_artifacts " - + "INNER JOIN blackboard_attributes ON blackboard_artifacts.artifact_id=blackboard_attributes.artifact_id " - + "WHERE blackboard_attributes.artifact_type_id=\'" + artifactTypeID + "\' " - + "AND blackboard_attributes.attribute_type_id=\'" + setNameAttrID + "\' " - + "AND blackboard_artifacts.obj_id IN (" + objIdList + ") "; // NON-NLS - } private FileSearch() { // Class should not be instantiated } - /** - * Base class for the grouping attributes. - */ - public abstract static class AttributeType { - - /** - * For a given file, return the key for the group it belongs to for this - * attribute type. - * - * @param file the result file to be grouped - * - * @return the key for the group this file goes in - */ - public abstract GroupKey getGroupKey(ResultFile file); - - /** - * Add any extra data to the ResultFile object from this attribute. - * - * @param files The list of files to enhance - * @param caseDb The case database - * @param centralRepoDb The central repository database. Can be null if - * not needed. - * - * @throws DiscoveryException - */ - public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { - // Default is to do nothing - } - } - - /** - * Attribute for grouping/sorting by file size - */ - public static class FileSizeAttribute extends AttributeType { - - @Override - public GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.FileSizeGroupKey(file); - } - } - - /** - * Attribute for grouping/sorting by parent path - */ - public static class ParentPathAttribute extends AttributeType { - - @Override - public GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.ParentPathGroupKey(file); - } - } - - /** - * Default attribute used to make one group - */ - static class NoGroupingAttribute extends FileSearch.AttributeType { - - @Override - public GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.NoGroupingGroupKey(); - } - } - - /** - * Attribute for grouping/sorting by data source - */ - static class DataSourceAttribute extends AttributeType { - - @Override - public GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.DataSourceGroupKey(file); - } - } - - /** - * Attribute for grouping/sorting by file type - */ - static class FileTypeAttribute extends AttributeType { - - @Override - public GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.FileTypeGroupKey(file); - } - } - - /** - * Attribute for grouping/sorting by keyword lists - */ - static class KeywordListAttribute extends AttributeType { - - @Override - public GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.KeywordListGroupKey(file); - } - - @Override - public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { - - // Get pairs of (object ID, keyword list name) for all files in the list of files that have - // keyword list hits. - String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID(), - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()); - - SetKeywordListNamesCallback callback = new SetKeywordListNamesCallback(files); - try { - caseDb.getCaseDbAccessManager().select(selectQuery, callback); - } catch (TskCoreException ex) { - throw new DiscoveryException("Error looking up keyword list attributes", ex); // NON-NLS - } - } - - /** - * Callback to process the results of the CaseDbAccessManager select - * query. Will add the keyword list names to the list of ResultFile - * objects. - */ - private static class SetKeywordListNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { - - List resultFiles; - - /** - * Create the callback. - * - * @param resultFiles List of files to add keyword list names to - */ - SetKeywordListNamesCallback(List resultFiles) { - this.resultFiles = resultFiles; - } - - @Override - public void process(ResultSet rs) { - try { - // Create a temporary map of object ID to ResultFile - Map tempMap = new HashMap<>(); - for (ResultFile file : resultFiles) { - tempMap.put(file.getFirstInstance().getId(), file); - } - - while (rs.next()) { - try { - Long objId = rs.getLong("object_id"); // NON-NLS - String keywordListName = rs.getString("set_name"); // NON-NLS - - tempMap.get(objId).addKeywordListName(keywordListName); - - } catch (SQLException ex) { - logger.log(Level.SEVERE, "Unable to get object_id or set_name from result set", ex); // NON-NLS - } - } - } catch (SQLException ex) { - logger.log(Level.SEVERE, "Failed to get keyword list names", ex); // NON-NLS - } - } - } - } - - /** - * Attribute for grouping/sorting by frequency in the central repository - */ - static class FrequencyAttribute extends AttributeType { - - static final int BATCH_SIZE = 50; // Number of hashes to look up at one time - - @Override - public GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.FrequencyGroupKey(file); - } - - @Override - public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { - if (centralRepoDb == null) { - for (ResultFile file : files) { - if (file.getFrequency() == Frequency.UNKNOWN && file.getFirstInstance().getKnown() == TskData.FileKnown.KNOWN) { - file.setFrequency(Frequency.KNOWN); - } - } - } else { - processResultFilesForCR(files, centralRepoDb); - } - } - - /** - * Private helper method for adding Frequency attribute when CR is - * enabled. - * - * @param files The list of ResultFiles to caluclate frequency - * for. - * @param centralRepoDb The central repository currently in use. - */ - private void processResultFilesForCR(List files, - CentralRepository centralRepoDb) { - List currentFiles = new ArrayList<>(); - Set hashesToLookUp = new HashSet<>(); - for (ResultFile file : files) { - if (file.getFirstInstance().getKnown() == TskData.FileKnown.KNOWN) { - file.setFrequency(Frequency.KNOWN); - } - if (file.getFrequency() == Frequency.UNKNOWN - && file.getFirstInstance().getMd5Hash() != null - && !file.getFirstInstance().getMd5Hash().isEmpty()) { - hashesToLookUp.add(file.getFirstInstance().getMd5Hash()); - currentFiles.add(file); - } - if (hashesToLookUp.size() >= BATCH_SIZE) { - computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); - - hashesToLookUp.clear(); - currentFiles.clear(); - } - } - computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); - } - } - - /** - * Callback to use with findInterCaseValuesByCount which generates a list of - * values for common property search - */ - private static class FrequencyCallback implements InstanceTableCallback { - - private final List files; - - private FrequencyCallback(List files) { - this.files = new ArrayList<>(files); - } - - @Override - public void process(ResultSet resultSet) { - try { - - while (resultSet.next()) { - String hash = resultSet.getString(1); - int count = resultSet.getInt(2); - for (Iterator iterator = files.iterator(); iterator.hasNext();) { - ResultFile file = iterator.next(); - if (file.getFirstInstance().getMd5Hash().equalsIgnoreCase(hash)) { - file.setFrequency(Frequency.fromCount(count)); - iterator.remove(); - } - } - } - - // The files left had no matching entries in the CR, so mark them as unique - for (ResultFile file : files) { - file.setFrequency(Frequency.UNIQUE); - } - } catch (SQLException ex) { - logger.log(Level.WARNING, "Error getting frequency counts from Central Repository", ex); // NON-NLS - } - } - } - - /** - * Attribute for grouping/sorting by hash set lists - */ - static class HashHitsAttribute extends AttributeType { - - @Override - public GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.HashHitsGroupKey(file); - } - - @Override - public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { - - // Get pairs of (object ID, hash set name) for all files in the list of files that have - // hash set hits. - String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(), - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()); - - HashSetNamesCallback callback = new HashSetNamesCallback(files); - try { - caseDb.getCaseDbAccessManager().select(selectQuery, callback); - } catch (TskCoreException ex) { - throw new DiscoveryException("Error looking up hash set attributes", ex); // NON-NLS - } - } - - /** - * Callback to process the results of the CaseDbAccessManager select - * query. Will add the hash set names to the list of ResultFile objects. - */ - private static class HashSetNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { - - List resultFiles; - - /** - * Create the callback. - * - * @param resultFiles List of files to add hash set names to - */ - HashSetNamesCallback(List resultFiles) { - this.resultFiles = resultFiles; - } - - @Override - public void process(ResultSet rs) { - try { - // Create a temporary map of object ID to ResultFile - Map tempMap = new HashMap<>(); - for (ResultFile file : resultFiles) { - tempMap.put(file.getFirstInstance().getId(), file); - } - - while (rs.next()) { - try { - Long objId = rs.getLong("object_id"); // NON-NLS - String hashSetName = rs.getString("set_name"); // NON-NLS - - tempMap.get(objId).addHashSetName(hashSetName); - - } catch (SQLException ex) { - logger.log(Level.SEVERE, "Unable to get object_id or set_name from result set", ex); // NON-NLS - } - } - } catch (SQLException ex) { - logger.log(Level.SEVERE, "Failed to get hash set names", ex); // NON-NLS - } - } - } - } - - /** - * Attribute for grouping/sorting by interesting item set lists - */ - static class InterestingItemAttribute extends AttributeType { - - @Override - public GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.InterestingItemGroupKey(file); - } - - @Override - public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { - - // Get pairs of (object ID, interesting item set name) for all files in the list of files that have - // interesting file set hits. - String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(), - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()); - - InterestingFileSetNamesCallback callback = new InterestingFileSetNamesCallback(files); - try { - caseDb.getCaseDbAccessManager().select(selectQuery, callback); - } catch (TskCoreException ex) { - throw new DiscoveryException("Error looking up interesting file set attributes", ex); // NON-NLS - } - } - - /** - * Callback to process the results of the CaseDbAccessManager select - * query. Will add the interesting file set names to the list of - * ResultFile objects. - */ - private static class InterestingFileSetNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { - - List resultFiles; - - /** - * Create the callback. - * - * @param resultFiles List of files to add interesting file set - * names to - */ - InterestingFileSetNamesCallback(List resultFiles) { - this.resultFiles = resultFiles; - } - - @Override - public void process(ResultSet rs) { - try { - // Create a temporary map of object ID to ResultFile - Map tempMap = new HashMap<>(); - for (ResultFile file : resultFiles) { - tempMap.put(file.getFirstInstance().getId(), file); - } - - while (rs.next()) { - try { - Long objId = rs.getLong("object_id"); // NON-NLS - String setName = rs.getString("set_name"); // NON-NLS - - tempMap.get(objId).addInterestingSetName(setName); - - } catch (SQLException ex) { - logger.log(Level.SEVERE, "Unable to get object_id or set_name from result set", ex); // NON-NLS - } - } - } catch (SQLException ex) { - logger.log(Level.SEVERE, "Failed to get interesting file set names", ex); // NON-NLS - } - } - } - } - - /** - * Attribute for grouping/sorting by objects detected - */ - static class ObjectDetectedAttribute extends AttributeType { - - @Override - public GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.ObjectDetectedGroupKey(file); - } - - @Override - public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { - - // Get pairs of (object ID, object type name) for all files in the list of files that have - // objects detected - String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID(), - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID()); - - ObjectDetectedNamesCallback callback = new ObjectDetectedNamesCallback(files); - try { - caseDb.getCaseDbAccessManager().select(selectQuery, callback); - } catch (TskCoreException ex) { - throw new DiscoveryException("Error looking up object detected attributes", ex); // NON-NLS - } - } - - /** - * Callback to process the results of the CaseDbAccessManager select - * query. Will add the object type names to the list of ResultFile - * objects. - */ - private static class ObjectDetectedNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { - - List resultFiles; - - /** - * Create the callback. - * - * @param resultFiles List of files to add object detected names to - */ - ObjectDetectedNamesCallback(List resultFiles) { - this.resultFiles = resultFiles; - } - - @Override - public void process(ResultSet rs) { - try { - // Create a temporary map of object ID to ResultFile - Map tempMap = new HashMap<>(); - for (ResultFile file : resultFiles) { - tempMap.put(file.getFirstInstance().getId(), file); - } - - while (rs.next()) { - try { - Long objId = rs.getLong("object_id"); // NON-NLS - String setName = rs.getString("set_name"); // NON-NLS - - tempMap.get(objId).addObjectDetectedName(setName); - - } catch (SQLException ex) { - logger.log(Level.SEVERE, "Unable to get object_id or set_name from result set", ex); // NON-NLS - } - } - } catch (SQLException ex) { - logger.log(Level.SEVERE, "Failed to get object detected names", ex); // NON-NLS - } - } - } - } - - /** - * Attribute for grouping/sorting by tag name - */ - static class FileTagAttribute extends AttributeType { - - @Override - public GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.FileTagGroupKey(file); - } - - @Override - public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { - - try { - for (ResultFile resultFile : files) { - List contentTags = caseDb.getContentTagsByContent(resultFile.getFirstInstance()); - - for (ContentTag tag : contentTags) { - resultFile.addTagName(tag.getName().getDisplayName()); - } - } - } catch (TskCoreException ex) { - throw new DiscoveryException("Error looking up file tag attributes", ex); // NON-NLS - } - } - } - - /** - * Enum for the attribute types that can be used for grouping. - */ - @NbBundle.Messages({ - "FileSearch.GroupingAttributeType.fileType.displayName=File Type", - "FileSearch.GroupingAttributeType.frequency.displayName=Past Occurrences", - "FileSearch.GroupingAttributeType.keywordList.displayName=Keyword", - "FileSearch.GroupingAttributeType.size.displayName=File Size", - "FileSearch.GroupingAttributeType.datasource.displayName=Data Source", - "FileSearch.GroupingAttributeType.parent.displayName=Parent Folder", - "FileSearch.GroupingAttributeType.hash.displayName=Hash Set", - "FileSearch.GroupingAttributeType.interestingItem.displayName=Interesting Item", - "FileSearch.GroupingAttributeType.tag.displayName=Tag", - "FileSearch.GroupingAttributeType.object.displayName=Object Detected", - "FileSearch.GroupingAttributeType.none.displayName=None"}) - public enum GroupingAttributeType { - FILE_SIZE(new FileSizeAttribute(), Bundle.FileSearch_GroupingAttributeType_size_displayName()), - FREQUENCY(new FrequencyAttribute(), Bundle.FileSearch_GroupingAttributeType_frequency_displayName()), - KEYWORD_LIST_NAME(new KeywordListAttribute(), Bundle.FileSearch_GroupingAttributeType_keywordList_displayName()), - DATA_SOURCE(new DataSourceAttribute(), Bundle.FileSearch_GroupingAttributeType_datasource_displayName()), - PARENT_PATH(new ParentPathAttribute(), Bundle.FileSearch_GroupingAttributeType_parent_displayName()), - HASH_LIST_NAME(new HashHitsAttribute(), Bundle.FileSearch_GroupingAttributeType_hash_displayName()), - INTERESTING_ITEM_SET(new InterestingItemAttribute(), Bundle.FileSearch_GroupingAttributeType_interestingItem_displayName()), - FILE_TAG(new FileTagAttribute(), Bundle.FileSearch_GroupingAttributeType_tag_displayName()), - OBJECT_DETECTED(new ObjectDetectedAttribute(), Bundle.FileSearch_GroupingAttributeType_object_displayName()), - NO_GROUPING(new NoGroupingAttribute(), Bundle.FileSearch_GroupingAttributeType_none_displayName()); - - private final AttributeType attributeType; - private final String displayName; - - GroupingAttributeType(AttributeType attributeType, String displayName) { - this.attributeType = attributeType; - this.displayName = displayName; - } - - @Override - public String toString() { - return displayName; - } - - public AttributeType getAttributeType() { - return attributeType; - } - - /** - * Get the list of enums that are valid for grouping images. - * - * @return enums that can be used to group images - */ - public static List getOptionsForGrouping() { - return Arrays.asList(FILE_SIZE, FREQUENCY, PARENT_PATH, OBJECT_DETECTED, HASH_LIST_NAME, INTERESTING_ITEM_SET); - } - } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSorter.java b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSorter.java index 30064b5ce9..a97f99d8cd 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSorter.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSorter.java @@ -254,19 +254,19 @@ public class FileSorter implements Comparator { Bundle.FileSorter_SortingMethod_datasource_displayName()), // Sort in increasing order of data source ID BY_FILE_SIZE(new ArrayList<>(), Bundle.FileSorter_SortingMethod_filesize_displayName()), // Sort in decreasing order of size - BY_FILE_TYPE(Arrays.asList(new FileSearch.FileTypeAttribute()), + BY_FILE_TYPE(Arrays.asList(new DiscoveryAttributes.FileTypeAttribute()), Bundle.FileSorter_SortingMethod_filetype_displayName()), // Sort in order of file type (defined in FileType enum), with secondary sort on MIME type - BY_FREQUENCY(Arrays.asList(new FileSearch.FrequencyAttribute()), + BY_FREQUENCY(Arrays.asList(new DiscoveryAttributes.FrequencyAttribute()), Bundle.FileSorter_SortingMethod_frequency_displayName()), // Sort by decreasing rarity in the central repository - BY_KEYWORD_LIST_NAMES(Arrays.asList(new FileSearch.KeywordListAttribute()), + BY_KEYWORD_LIST_NAMES(Arrays.asList(new DiscoveryAttributes.KeywordListAttribute()), Bundle.FileSorter_SortingMethod_keywordlist_displayName()), // Sort alphabetically by list of keyword list names found BY_FULL_PATH(new ArrayList<>(), Bundle.FileSorter_SortingMethod_fullPath_displayName()); // Sort alphabetically by path private final String displayName; - private final List requiredAttributes; + private final List requiredAttributes; - SortingMethod(List attributes, String displayName) { + SortingMethod(List attributes, String displayName) { this.requiredAttributes = attributes; this.displayName = displayName; } @@ -276,7 +276,7 @@ public class FileSorter implements Comparator { return displayName; } - public List getRequiredAttributes() { + public List getRequiredAttributes() { return Collections.unmodifiableList(requiredAttributes); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java index 9b4374e927..59bf5e15d3 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java @@ -524,7 +524,7 @@ public class SearchFiltering { } // Set the frequency for each file - FileSearch.FrequencyAttribute freqAttr = new FileSearch.FrequencyAttribute(); + DiscoveryAttributes.FrequencyAttribute freqAttr = new DiscoveryAttributes.FrequencyAttribute(); freqAttr.addAttributeToResultFiles(currentResults, caseDb, centralRepoDb); // If the frequency matches the filter, add the file to the results diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java index 77ce01b5c9..176c22d652 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java @@ -33,7 +33,7 @@ import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; class SearchResults { private final Group.GroupSortingAlgorithm groupSortingType; - private final FileSearch.AttributeType attrType; + private final DiscoveryAttributes.AttributeType attrType; private final FileSorter fileSorter; private final Map groupMap = new HashMap<>(); @@ -50,7 +50,7 @@ class SearchResults { * @param fileSortingMethod The method that should be used to * sortGroupsAndFiles the files in each group. */ - SearchResults(Group.GroupSortingAlgorithm groupSortingType, FileSearch.AttributeType attrType, + SearchResults(Group.GroupSortingAlgorithm groupSortingType, DiscoveryAttributes.AttributeType attrType, FileSorter.SortingMethod fileSortingMethod) { this.groupSortingType = groupSortingType; this.attrType = attrType; @@ -63,7 +63,7 @@ class SearchResults { */ SearchResults() { this.groupSortingType = Group.GroupSortingAlgorithm.BY_GROUP_NAME; - this.attrType = new FileSearch.FileSizeAttribute(); + this.attrType = new DiscoveryAttributes.FileSizeAttribute(); this.fileSorter = new FileSorter(FileSorter.SortingMethod.BY_FILE_NAME); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index dc0f8cc6de..7227388742 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -37,13 +37,13 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; import org.sleuthkit.autopsy.discovery.search.Group; import org.sleuthkit.autopsy.discovery.search.Group.GroupSortingAlgorithm; import static org.sleuthkit.autopsy.discovery.search.Group.GroupSortingAlgorithm.BY_GROUP_SIZE; -import org.sleuthkit.autopsy.discovery.search.FileSearch; -import org.sleuthkit.autopsy.discovery.search.FileSearch.GroupingAttributeType; -import static org.sleuthkit.autopsy.discovery.search.FileSearch.GroupingAttributeType.PARENT_PATH; +import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes.GroupingAttributeType; +import static org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes.GroupingAttributeType.PARENT_PATH; import org.sleuthkit.autopsy.discovery.search.FileSorter; import org.sleuthkit.autopsy.discovery.search.FileSorter.SortingMethod; import static org.sleuthkit.autopsy.discovery.search.FileSorter.SortingMethod.BY_FILE_NAME; @@ -169,7 +169,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { private void updateComboBoxes() { groupByCombobox.removeAllItems(); // Set up the grouping attributes - for (FileSearch.GroupingAttributeType groupingType : FileSearch.GroupingAttributeType.getOptionsForGrouping()) { + for (DiscoveryAttributes.GroupingAttributeType groupingType : DiscoveryAttributes.GroupingAttributeType.getOptionsForGrouping()) { addTypeToGroupByComboBox(groupingType); } groupByCombobox.setSelectedItem(PARENT_PATH); @@ -554,7 +554,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.SearchStartedEvent(type)); // Get the grouping attribute and group sorting method - FileSearch.AttributeType groupingAttr = groupByCombobox.getItemAt(groupByCombobox.getSelectedIndex()).getAttributeType(); + DiscoveryAttributes.AttributeType groupingAttr = groupByCombobox.getItemAt(groupByCombobox.getSelectedIndex()).getAttributeType(); Group.GroupSortingAlgorithm groupSortAlgorithm = groupSortingComboBox.getItemAt(groupSortingComboBox.getSelectedIndex()); // Get the file sorting method diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java index ddca7c785e..b9f47dc26e 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java @@ -29,10 +29,10 @@ import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; import org.sleuthkit.autopsy.discovery.search.Group; -import org.sleuthkit.autopsy.discovery.search.FileSearch; import org.sleuthkit.autopsy.discovery.search.SearchData.Type; import org.sleuthkit.autopsy.discovery.search.FileSorter; @@ -45,7 +45,7 @@ final class GroupListPanel extends javax.swing.JPanel { private Type type = null; private Map groupMap = null; private List searchfilters; - private FileSearch.AttributeType groupingAttribute; + private DiscoveryAttributes.AttributeType groupingAttribute; private Group.GroupSortingAlgorithm groupSort; private FileSorter.SortingMethod fileSortMethod; private GroupKey selectedGroupKey; @@ -210,7 +210,7 @@ final class GroupListPanel extends javax.swing.JPanel { String valueString = newValue.toString(); setToolTipText(valueString); //if paths would be longer than 37 characters shorten them to be 37 characters - if (groupingAttribute instanceof FileSearch.ParentPathAttribute && valueString.length() > 37) { + if (groupingAttribute instanceof DiscoveryAttributes.ParentPathAttribute && valueString.length() > 37) { valueString = valueString.substring(0, 16) + " ... " + valueString.substring(valueString.length() - 16); } newValue = valueString + " (" + groupMap.get(newValue) + ")"; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java index 1139366cf0..3a9033b08f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java @@ -26,6 +26,7 @@ import javax.swing.SwingWorker; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; import org.sleuthkit.autopsy.discovery.search.Group; @@ -43,7 +44,7 @@ final class PageWorker extends SwingWorker { private final static Logger logger = Logger.getLogger(PageWorker.class.getName()); private static final String USER_NAME_PROPERTY = "user.name"; //NON-NLS private final List searchfilters; - private final FileSearch.AttributeType groupingAttribute; + private final DiscoveryAttributes.AttributeType groupingAttribute; private final Group.GroupSortingAlgorithm groupSort; private final FileSorter.SortingMethod fileSortMethod; private final GroupKey groupKey; @@ -69,7 +70,7 @@ final class PageWorker extends SwingWorker { * @param resultType The type of files which exist in the group. * @param centralRepo The central repository to be used. */ - PageWorker(List searchfilters, FileSearch.AttributeType groupingAttribute, + PageWorker(List searchfilters, DiscoveryAttributes.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod, GroupKey groupKey, int startingEntry, int pageSize, SearchData.Type resultType, CentralRepository centralRepo) { this.searchfilters = searchfilters; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java index c6551d7706..d11700e336 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java @@ -38,6 +38,7 @@ import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; import org.sleuthkit.autopsy.discovery.search.Group; @@ -59,7 +60,7 @@ final class ResultsPanel extends javax.swing.JPanel { private final ImageThumbnailViewer imageThumbnailViewer; private final DocumentPreviewViewer documentPreviewViewer; private List searchFilters; - private FileSearch.AttributeType groupingAttribute; + private DiscoveryAttributes.AttributeType groupingAttribute; private Group.GroupSortingAlgorithm groupSort; private FileSorter.SortingMethod fileSortMethod; private GroupKey selectedGroupKey; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java index 49b2de3d71..4453743bcf 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java @@ -27,6 +27,7 @@ import java.util.logging.Level; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; import org.sleuthkit.autopsy.discovery.search.Group; @@ -42,7 +43,7 @@ final class SearchWorker extends SwingWorker { private final static Logger logger = Logger.getLogger(SearchWorker.class.getName()); private static final String USER_NAME_PROPERTY = "user.name"; //NON-NLS private final List filters; - private final FileSearch.AttributeType groupingAttr; + private final DiscoveryAttributes.AttributeType groupingAttr; private final FileSorter.SortingMethod fileSort; private final Group.GroupSortingAlgorithm groupSortAlgorithm; private final CentralRepository centralRepoDb; @@ -58,7 +59,7 @@ final class SearchWorker extends SwingWorker { * @param groupSort The Algorithm to sort groups by. * @param fileSortMethod The SortingMethod to use for files. */ - SearchWorker(CentralRepository centralRepo, List searchfilters, FileSearch.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod) { + SearchWorker(CentralRepository centralRepo, List searchfilters, DiscoveryAttributes.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod) { centralRepoDb = centralRepo; filters = searchfilters; groupingAttr = groupingAttribute; From e9b80d09a16f1df7c1eb6ff1a77f31b868c0388a Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 20 Aug 2020 16:07:34 -0400 Subject: [PATCH 024/130] 6711 add ResultDomain object --- .../discovery/search/AbstractFilter.java | 2 +- .../discovery/search/DiscoveryAttributes.java | 171 +++++++++++------- .../discovery/search/DiscoveryEventUtils.java | 6 +- .../discovery/search/DiscoveryKeyUtils.java | 31 ++-- .../autopsy/discovery/search/FileSearch.java | 34 ++-- .../autopsy/discovery/search/FileSorter.java | 94 ++++++---- .../autopsy/discovery/search/Group.java | 30 +-- .../autopsy/discovery/search/Result.java | 60 +++++- .../discovery/search/ResultDomain.java | 31 +++- .../autopsy/discovery/search/ResultFile.java | 70 +++---- .../discovery/search/SearchFiltering.java | 31 ++-- .../discovery/search/SearchResults.java | 40 ++-- .../discovery/ui/DiscoveryUiUtils.java | 3 +- .../discovery/ui/OpenDiscoveryAction.java | 2 - .../autopsy/discovery/ui/PageWorker.java | 4 +- 15 files changed, 369 insertions(+), 240 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java b/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java index d31fe246b0..cb44c29415 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java @@ -61,7 +61,7 @@ public abstract class AbstractFilter { * * @throws DiscoveryException */ - public List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, + public List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { return new ArrayList<>(); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java index 54123077e8..6c4a2095f1 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java @@ -52,19 +52,19 @@ public class DiscoveryAttributes { * * @return the key for the group this file goes in */ - public abstract DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file); + public abstract DiscoveryKeyUtils.GroupKey getGroupKey(Result file); /** * Add any extra data to the ResultFile object from this attribute. * - * @param files The list of files to enhance + * @param files The list of results to enhance * @param caseDb The case database * @param centralRepoDb The central repository database. Can be null if * not needed. * * @throws DiscoveryException */ - public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { + public void addAttributeToResultFiles(List results, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { // Default is to do nothing } } @@ -75,8 +75,8 @@ public class DiscoveryAttributes { public static class FileSizeAttribute extends AttributeType { @Override - public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.FileSizeGroupKey(file); + public DiscoveryKeyUtils.GroupKey getGroupKey(Result file) { + return new DiscoveryKeyUtils.FileSizeGroupKey((ResultFile) file); } } @@ -86,8 +86,8 @@ public class DiscoveryAttributes { public static class ParentPathAttribute extends AttributeType { @Override - public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.ParentPathGroupKey(file); + public DiscoveryKeyUtils.GroupKey getGroupKey(Result file) { + return new DiscoveryKeyUtils.ParentPathGroupKey((ResultFile) file); } } @@ -97,7 +97,7 @@ public class DiscoveryAttributes { static class NoGroupingAttribute extends AttributeType { @Override - public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + public DiscoveryKeyUtils.GroupKey getGroupKey(Result result) { return new DiscoveryKeyUtils.NoGroupingGroupKey(); } } @@ -108,8 +108,8 @@ public class DiscoveryAttributes { static class DataSourceAttribute extends AttributeType { @Override - public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.DataSourceGroupKey(file); + public DiscoveryKeyUtils.GroupKey getGroupKey(Result result) { + return new DiscoveryKeyUtils.DataSourceGroupKey(result); } } @@ -119,7 +119,7 @@ public class DiscoveryAttributes { static class FileTypeAttribute extends AttributeType { @Override - public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + public DiscoveryKeyUtils.GroupKey getGroupKey(Result file) { return new DiscoveryKeyUtils.FileTypeGroupKey(file); } } @@ -130,20 +130,20 @@ public class DiscoveryAttributes { static class KeywordListAttribute extends AttributeType { @Override - public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.KeywordListGroupKey(file); + public DiscoveryKeyUtils.GroupKey getGroupKey(Result file) { + return new DiscoveryKeyUtils.KeywordListGroupKey((ResultFile) file); } @Override - public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + public void addAttributeToResultFiles(List results, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { // Get pairs of (object ID, keyword list name) for all files in the list of files that have // keyword list hits. - String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID(), + String selectQuery = createSetNameClause(results, BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID(), BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()); - SetKeywordListNamesCallback callback = new SetKeywordListNamesCallback(files); + SetKeywordListNamesCallback callback = new SetKeywordListNamesCallback(results); try { caseDb.getCaseDbAccessManager().select(selectQuery, callback); } catch (TskCoreException ex) { @@ -158,14 +158,14 @@ public class DiscoveryAttributes { */ private static class SetKeywordListNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { - List resultFiles; + List resultFiles; /** * Create the callback. * * @param resultFiles List of files to add keyword list names to */ - SetKeywordListNamesCallback(List resultFiles) { + SetKeywordListNamesCallback(List resultFiles) { this.resultFiles = resultFiles; } @@ -174,7 +174,11 @@ public class DiscoveryAttributes { try { // Create a temporary map of object ID to ResultFile Map tempMap = new HashMap<>(); - for (ResultFile file : resultFiles) { + for (Result result : resultFiles) { + if (result.getType() == SearchData.Type.DOMAIN) { + break; + } + ResultFile file = (ResultFile) result; tempMap.put(file.getFirstInstance().getId(), file); } @@ -204,21 +208,21 @@ public class DiscoveryAttributes { static final int BATCH_SIZE = 50; // Number of hashes to look up at one time @Override - public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + public DiscoveryKeyUtils.GroupKey getGroupKey(Result file) { return new DiscoveryKeyUtils.FrequencyGroupKey(file); } @Override - public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + public void addAttributeToResultFiles(List results, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { if (centralRepoDb == null) { - for (ResultFile file : files) { - if (file.getFrequency() == SearchData.Frequency.UNKNOWN && file.getFirstInstance().getKnown() == TskData.FileKnown.KNOWN) { - file.setFrequency(SearchData.Frequency.KNOWN); + for (Result result : results) { + if (result.getFrequency() == SearchData.Frequency.UNKNOWN && result.getKnown() == TskData.FileKnown.KNOWN) { + result.setFrequency(SearchData.Frequency.KNOWN); } } } else { - processResultFilesForCR(files, centralRepoDb); + processResultFilesForCR(results, centralRepoDb); } } @@ -230,19 +234,22 @@ public class DiscoveryAttributes { * for. * @param centralRepoDb The central repository currently in use. */ - private void processResultFilesForCR(List files, + private void processResultFilesForCR(List results, CentralRepository centralRepoDb) { List currentFiles = new ArrayList<>(); Set hashesToLookUp = new HashSet<>(); - for (ResultFile file : files) { - if (file.getFirstInstance().getKnown() == TskData.FileKnown.KNOWN) { - file.setFrequency(SearchData.Frequency.KNOWN); + for (Result result : results) { + if (result.getKnown() == TskData.FileKnown.KNOWN) { + result.setFrequency(SearchData.Frequency.KNOWN); } - if (file.getFrequency() == SearchData.Frequency.UNKNOWN - && file.getFirstInstance().getMd5Hash() != null - && !file.getFirstInstance().getMd5Hash().isEmpty()) { - hashesToLookUp.add(file.getFirstInstance().getMd5Hash()); - currentFiles.add(file); + if (result.getType() != SearchData.Type.DOMAIN) { + ResultFile file = (ResultFile) result; + if (file.getFrequency() == SearchData.Frequency.UNKNOWN + && file.getFirstInstance().getMd5Hash() != null + && !file.getFirstInstance().getMd5Hash().isEmpty()) { + hashesToLookUp.add(file.getFirstInstance().getMd5Hash()); + currentFiles.add(file); + } } if (hashesToLookUp.size() >= BATCH_SIZE) { computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); @@ -299,20 +306,23 @@ public class DiscoveryAttributes { static class HashHitsAttribute extends AttributeType { @Override - public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.HashHitsGroupKey(file); + public DiscoveryKeyUtils.GroupKey getGroupKey(Result result) { + if (result.getType() == SearchData.Type.DOMAIN) { + return null; + } + return new DiscoveryKeyUtils.HashHitsGroupKey((ResultFile) result); } @Override - public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + public void addAttributeToResultFiles(List results, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { // Get pairs of (object ID, hash set name) for all files in the list of files that have // hash set hits. - String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(), + String selectQuery = createSetNameClause(results, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(), BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()); - HashSetNamesCallback callback = new HashSetNamesCallback(files); + HashSetNamesCallback callback = new HashSetNamesCallback(results); try { caseDb.getCaseDbAccessManager().select(selectQuery, callback); } catch (TskCoreException ex) { @@ -326,15 +336,15 @@ public class DiscoveryAttributes { */ private static class HashSetNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { - List resultFiles; + List results; /** * Create the callback. * * @param resultFiles List of files to add hash set names to */ - HashSetNamesCallback(List resultFiles) { - this.resultFiles = resultFiles; + HashSetNamesCallback(List results) { + this.results = results; } @Override @@ -342,7 +352,11 @@ public class DiscoveryAttributes { try { // Create a temporary map of object ID to ResultFile Map tempMap = new HashMap<>(); - for (ResultFile file : resultFiles) { + for (Result result : results) { + if (result.getType() == SearchData.Type.DOMAIN) { + return; + } + ResultFile file = (ResultFile) result; tempMap.put(file.getFirstInstance().getId(), file); } @@ -370,20 +384,20 @@ public class DiscoveryAttributes { static class InterestingItemAttribute extends AttributeType { @Override - public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.InterestingItemGroupKey(file); + public DiscoveryKeyUtils.GroupKey getGroupKey(Result file) { + return new DiscoveryKeyUtils.InterestingItemGroupKey((ResultFile) file); } @Override - public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + public void addAttributeToResultFiles(List results, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { // Get pairs of (object ID, interesting item set name) for all files in the list of files that have // interesting file set hits. - String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(), + String selectQuery = createSetNameClause(results, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(), BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()); - InterestingFileSetNamesCallback callback = new InterestingFileSetNamesCallback(files); + InterestingFileSetNamesCallback callback = new InterestingFileSetNamesCallback(results); try { caseDb.getCaseDbAccessManager().select(selectQuery, callback); } catch (TskCoreException ex) { @@ -398,7 +412,7 @@ public class DiscoveryAttributes { */ private static class InterestingFileSetNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { - List resultFiles; + List results; /** * Create the callback. @@ -406,8 +420,8 @@ public class DiscoveryAttributes { * @param resultFiles List of files to add interesting file set * names to */ - InterestingFileSetNamesCallback(List resultFiles) { - this.resultFiles = resultFiles; + InterestingFileSetNamesCallback(List results) { + this.results = results; } @Override @@ -415,7 +429,11 @@ public class DiscoveryAttributes { try { // Create a temporary map of object ID to ResultFile Map tempMap = new HashMap<>(); - for (ResultFile file : resultFiles) { + for (Result result : results) { + if (result.getType() == SearchData.Type.DOMAIN) { + return; + } + ResultFile file = (ResultFile) result; tempMap.put(file.getFirstInstance().getId(), file); } @@ -443,20 +461,20 @@ public class DiscoveryAttributes { static class ObjectDetectedAttribute extends AttributeType { @Override - public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.ObjectDetectedGroupKey(file); + public DiscoveryKeyUtils.GroupKey getGroupKey(Result file) { + return new DiscoveryKeyUtils.ObjectDetectedGroupKey((ResultFile) file); } @Override - public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + public void addAttributeToResultFiles(List results, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { // Get pairs of (object ID, object type name) for all files in the list of files that have // objects detected - String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID(), + String selectQuery = createSetNameClause(results, BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID(), BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID()); - ObjectDetectedNamesCallback callback = new ObjectDetectedNamesCallback(files); + ObjectDetectedNamesCallback callback = new ObjectDetectedNamesCallback(results); try { caseDb.getCaseDbAccessManager().select(selectQuery, callback); } catch (TskCoreException ex) { @@ -471,15 +489,15 @@ public class DiscoveryAttributes { */ private static class ObjectDetectedNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { - List resultFiles; + List results; /** * Create the callback. * * @param resultFiles List of files to add object detected names to */ - ObjectDetectedNamesCallback(List resultFiles) { - this.resultFiles = resultFiles; + ObjectDetectedNamesCallback(List results) { + this.results = results; } @Override @@ -487,7 +505,11 @@ public class DiscoveryAttributes { try { // Create a temporary map of object ID to ResultFile Map tempMap = new HashMap<>(); - for (ResultFile file : resultFiles) { + for (Result result : results) { + if (result.getType() == SearchData.Type.DOMAIN) { + return; + } + ResultFile file = (ResultFile) result; tempMap.put(file.getFirstInstance().getId(), file); } @@ -515,20 +537,24 @@ public class DiscoveryAttributes { static class FileTagAttribute extends AttributeType { @Override - public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.FileTagGroupKey(file); + public DiscoveryKeyUtils.GroupKey getGroupKey(Result file) { + return new DiscoveryKeyUtils.FileTagGroupKey((ResultFile) file); } @Override - public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + public void addAttributeToResultFiles(List results, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { try { - for (ResultFile resultFile : files) { - List contentTags = caseDb.getContentTagsByContent(resultFile.getFirstInstance()); + for (Result result : results) { + if (result.getType() == SearchData.Type.DOMAIN) { + return; + } + ResultFile file = (ResultFile) result; + List contentTags = caseDb.getContentTagsByContent(file.getFirstInstance()); for (ContentTag tag : contentTags) { - resultFile.addTagName(tag.getName().getDisplayName()); + result.addTagName(tag.getName().getDisplayName()); } } } catch (TskCoreException ex) { @@ -625,12 +651,16 @@ public class DiscoveryAttributes { } - private static String createSetNameClause(List files, + private static String createSetNameClause(List results, int artifactTypeID, int setNameAttrID) throws DiscoveryException { // Concatenate the object IDs in the list of files String objIdList = ""; // NON-NLS - for (ResultFile file : files) { + for (Result result : results) { + if (result.getType() == SearchData.Type.DOMAIN) { + break; + } + ResultFile file = (ResultFile) result; if (!objIdList.isEmpty()) { objIdList += ","; // NON-NLS } @@ -644,7 +674,8 @@ public class DiscoveryAttributes { + "INNER JOIN blackboard_attributes ON blackboard_artifacts.artifact_id=blackboard_attributes.artifact_id " + "WHERE blackboard_attributes.artifact_type_id=\'" + artifactTypeID + "\' " + "AND blackboard_attributes.attribute_type_id=\'" + setNameAttrID + "\' " - + "AND blackboard_artifacts.obj_id IN (" + objIdList + ") "; // NON-NLS + + "AND blackboard_artifacts.obj_id IN (" + objIdList + + ") "; // NON-NLS } private DiscoveryAttributes() { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java index f58a6eb08b..62aba44045 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java @@ -197,7 +197,7 @@ public final class DiscoveryEventUtils { */ public static final class PageRetrievedEvent { - private final List results; + private final List results; private final int page; private final Type resultType; @@ -208,7 +208,7 @@ public final class DiscoveryEventUtils { * @param page The number of the page which was retrieved. * @param results The list of files in the page retrieved. */ - public PageRetrievedEvent(Type resultType, int page, List results) { + public PageRetrievedEvent(Type resultType, int page, List results) { this.results = results; this.page = page; this.resultType = resultType; @@ -219,7 +219,7 @@ public final class DiscoveryEventUtils { * * @return The list of files in the page retrieved. */ - public List getSearchResults() { + public List getSearchResults() { return Collections.unmodifiableList(results); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java index 9eb172094f..f970a6541e 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java @@ -155,11 +155,12 @@ public class DiscoveryKeyUtils { private final SearchData.FileSize fileSize; - FileSizeGroupKey(ResultFile file) { - if (file.getFileType() == SearchData.Type.VIDEO) { - fileSize = SearchData.FileSize.fromVideoSize(file.getFirstInstance().getSize()); + FileSizeGroupKey(Result file) { + ResultFile resultFile = (ResultFile) file; + if (resultFile.getFileType() == SearchData.Type.VIDEO) { + fileSize = SearchData.FileSize.fromVideoSize(resultFile.getFirstInstance().getSize()); } else { - fileSize = SearchData.FileSize.fromImageSize(file.getFirstInstance().getSize()); + fileSize = SearchData.FileSize.fromImageSize(resultFile.getFirstInstance().getSize()); } } @@ -212,8 +213,8 @@ public class DiscoveryKeyUtils { private final SearchData.Type fileType; - FileTypeGroupKey(ResultFile file) { - fileType = file.getFileType(); + FileTypeGroupKey(Result file) { + fileType = ((ResultFile) file).getFileType(); } @Override @@ -539,19 +540,19 @@ public class DiscoveryKeyUtils { @NbBundle.Messages({ "# {0} - Data source name", "# {1} - Data source ID", - "FileSearch.DataSourceGroupKey.datasourceAndID={0}(ID: {1})", + "DiscoveryKeyUtils.DataSourceGroupKey.datasourceAndID={0}(ID: {1})", "# {0} - Data source ID", - "FileSearch.DataSourceGroupKey.idOnly=Data source (ID: {0})"}) - DataSourceGroupKey(ResultFile file) { - dataSourceID = file.getFirstInstance().getDataSourceObjectId(); - + "DiscoveryKeyUtils.DataSourceGroupKey.idOnly=Data source (ID: {0})"}) + DataSourceGroupKey(Result result) { + //get the id first so that it can be used when logging if necessary + dataSourceID = result.getDataSourceObjectId(); try { // The data source should be cached so this won't actually be a database query. - Content ds = file.getFirstInstance().getDataSource(); - displayName = Bundle.FileSearch_DataSourceGroupKey_datasourceAndID(ds.getName(), ds.getId()); + Content ds = result.getDataSource(); + displayName = Bundle.DiscoveryKeyUtils_DataSourceGroupKey_datasourceAndID(ds.getName(), ds.getId()); } catch (TskCoreException ex) { logger.log(Level.WARNING, "Error looking up data source with ID " + dataSourceID, ex); // NON-NLS - displayName = Bundle.FileSearch_DataSourceGroupKey_idOnly(dataSourceID); + displayName = Bundle.DiscoveryKeyUtils_DataSourceGroupKey_idOnly(dataSourceID); } } @@ -646,7 +647,7 @@ public class DiscoveryKeyUtils { private final SearchData.Frequency frequency; - FrequencyGroupKey(ResultFile file) { + FrequencyGroupKey(Result file) { frequency = file.getFrequency(); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java index b5d51d6810..3f667c302c 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java @@ -45,7 +45,7 @@ public class FileSearch { private final static Logger logger = Logger.getLogger(FileSearch.class.getName()); private static final int MAXIMUM_CACHE_SIZE = 10; - private static final Cache>> searchCache = CacheBuilder.newBuilder() + private static final Cache>> searchCache = CacheBuilder.newBuilder() .maximumSize(MAXIMUM_CACHE_SIZE) .build(); @@ -82,18 +82,18 @@ public class FileSearch { attributesNeededForGroupingOrSorting.addAll(fileSortingMethod.getRequiredAttributes()); // Run the queries for each filter - List resultFiles = SearchFiltering.runQueries(filters, caseDb, centralRepoDb); + List results = SearchFiltering.runQueries(filters, caseDb, centralRepoDb); // Add the data to resultFiles for any attributes needed for sorting and grouping - addAttributes(attributesNeededForGroupingOrSorting, resultFiles, caseDb, centralRepoDb); + addAttributes(attributesNeededForGroupingOrSorting, results, caseDb, centralRepoDb); // Collect everything in the search results SearchResults searchResults = new SearchResults(groupSortingType, groupAttributeType, fileSortingMethod); - searchResults.add(resultFiles); + searchResults.add(results); // Sort and group the results searchResults.sortGroupsAndFiles(); - Map> resultHashMap = searchResults.toLinkedHashMap(); + Map> resultHashMap = searchResults.toLinkedHashMap(); SearchKey searchKey = new SearchKey(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod); synchronized (searchCache) { searchCache.put(searchKey, resultHashMap); @@ -125,7 +125,7 @@ public class FileSearch { Group.GroupSortingAlgorithm groupSortingType, FileSorter.SortingMethod fileSortingMethod, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { - Map> searchResults = runFileSearch(userName, filters, + Map> searchResults = runFileSearch(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod, caseDb, centralRepoDb); LinkedHashMap groupSizes = new LinkedHashMap<>(); for (GroupKey groupKey : searchResults.keySet()) { @@ -156,7 +156,7 @@ public class FileSearch { * * @throws DiscoveryException */ - public static List getFilesInGroup(String userName, + public static List getFilesInGroup(String userName, List filters, AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, @@ -166,16 +166,16 @@ public class FileSearch { int numberOfEntries, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { //the group should be in the cache at this point - List filesInGroup = null; + List filesInGroup = null; SearchKey searchKey = new SearchKey(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod); - Map> resultsMap; + Map> resultsMap; synchronized (searchCache) { resultsMap = searchCache.getIfPresent(searchKey); } if (resultsMap != null) { filesInGroup = resultsMap.get(groupKey); } - List page = new ArrayList<>(); + List page = new ArrayList<>(); if (filesInGroup == null) { logger.log(Level.INFO, "Group {0} was not cached, performing search to cache all groups again", groupKey); runFileSearch(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod, caseDb, centralRepoDb); @@ -252,7 +252,7 @@ public class FileSearch { * * @throws DiscoveryException */ - private static Map> runFileSearch(String userName, + private static Map> runFileSearch(String userName, List filters, AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, @@ -268,15 +268,15 @@ public class FileSearch { attributesNeededForGroupingOrSorting.addAll(fileSortingMethod.getRequiredAttributes()); // Run the queries for each filter - List resultFiles = SearchFiltering.runQueries(filters, caseDb, centralRepoDb); + List results = SearchFiltering.runQueries(filters, caseDb, centralRepoDb); // Add the data to resultFiles for any attributes needed for sorting and grouping - addAttributes(attributesNeededForGroupingOrSorting, resultFiles, caseDb, centralRepoDb); + addAttributes(attributesNeededForGroupingOrSorting, results, caseDb, centralRepoDb); // Collect everything in the search results SearchResults searchResults = new SearchResults(groupSortingType, groupAttributeType, fileSortingMethod); - searchResults.add(resultFiles); - Map> resultHashMap = searchResults.toLinkedHashMap(); + searchResults.add(results); + Map> resultHashMap = searchResults.toLinkedHashMap(); SearchKey searchKey = new SearchKey(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod); synchronized (searchCache) { searchCache.put(searchKey, resultHashMap); @@ -298,10 +298,10 @@ public class FileSearch { * * @throws DiscoveryException */ - private static void addAttributes(List attrs, List resultFiles, SleuthkitCase caseDb, CentralRepository centralRepoDb) + private static void addAttributes(List attrs, List results, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { for (AttributeType attr : attrs) { - attr.addAttributeToResultFiles(resultFiles, caseDb, centralRepoDb); + attr.addAttributeToResultFiles(results, caseDb, centralRepoDb); } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSorter.java b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSorter.java index a97f99d8cd..f6d3e31ad0 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSorter.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSorter.java @@ -29,9 +29,9 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Class used to sort ResultFiles using the supplied method. */ -public class FileSorter implements Comparator { +public class FileSorter implements Comparator { - private final List> comparators = new ArrayList<>(); + private final List> comparators = new ArrayList<>(); /** * Set up the sorter using the supplied sorting method. The sorting is @@ -51,7 +51,7 @@ public class FileSorter implements Comparator { comparators.add(getFileSizeComparator()); break; case BY_FILE_TYPE: - comparators.add(getFileTypeComparator()); + comparators.add(getTypeComparator()); comparators.add(getMIMETypeComparator()); break; case BY_FREQUENCY: @@ -77,11 +77,11 @@ public class FileSorter implements Comparator { } @Override - public int compare(ResultFile file1, ResultFile file2) { + public int compare(Result result1, Result result2) { int result = 0; - for (Comparator comp : comparators) { - result = comp.compare(file1, file2); + for (Comparator comp : comparators) { + result = comp.compare(result1, result2); if (result != 0) { return result; } @@ -96,8 +96,8 @@ public class FileSorter implements Comparator { * * @return -1 if file1 has the lower data source ID, 0 if equal, 1 otherwise */ - private static Comparator getDataSourceComparator() { - return (ResultFile file1, ResultFile file2) -> Long.compare(file1.getFirstInstance().getDataSourceObjectId(), file2.getFirstInstance().getDataSourceObjectId()); + private static Comparator getDataSourceComparator() { + return (Result result1, Result result2) -> Long.compare(result1.getDataSourceObjectId(), result2.getDataSourceObjectId()); } /** @@ -106,8 +106,8 @@ public class FileSorter implements Comparator { * * @return -1 if file1 has the lower FileType value, 0 if equal, 1 otherwise */ - private static Comparator getFileTypeComparator() { - return (ResultFile file1, ResultFile file2) -> Integer.compare(file1.getFileType().getRanking(), file2.getFileType().getRanking()); + private static Comparator getTypeComparator() { + return (Result result1, Result result2) -> Integer.compare(result1.getType().getRanking(), result2.getType().getRanking()); } /** @@ -118,9 +118,14 @@ public class FileSorter implements Comparator { * @return -1 if file1 has the earliest combined keyword list name, 0 if * equal, 1 otherwise */ - private static Comparator getKeywordListNameComparator() { - return (ResultFile file1, ResultFile file2) -> { + private static Comparator getKeywordListNameComparator() { + return (Result result1, Result result2) -> { // Put empty lists at the bottom + if (result1.getType() == SearchData.Type.DOMAIN) { + return 0; + } + ResultFile file1 = (ResultFile) result1; + ResultFile file2 = (ResultFile) result2; if (file1.getKeywordListNames().isEmpty()) { if (file2.getKeywordListNames().isEmpty()) { return 0; @@ -142,11 +147,16 @@ public class FileSorter implements Comparator { * @return -1 if file1's path comes first alphabetically, 0 if equal, 1 * otherwise */ - private static Comparator getParentPathComparator() { + private static Comparator getParentPathComparator() { - return new Comparator() { + return new Comparator() { @Override - public int compare(ResultFile file1, ResultFile file2) { + public int compare(Result result1, Result result2) { + if (result1.getType() == SearchData.Type.DOMAIN) { + return 0; + } + ResultFile file1 = (ResultFile) result1; + ResultFile file2 = (ResultFile) result2; String file1ParentPath; try { file1ParentPath = file1.getFirstInstance().getParent().getUniquePath(); @@ -170,8 +180,8 @@ public class FileSorter implements Comparator { * * @return -1 if file1's rarity is lower than file2, 0 if equal, 1 otherwise */ - private static Comparator getFrequencyComparator() { - return (ResultFile file1, ResultFile file2) -> Integer.compare(file1.getFrequency().getRanking(), file2.getFrequency().getRanking()); + private static Comparator getFrequencyComparator() { + return (Result result1, Result result2) -> Integer.compare(result1.getFrequency().getRanking(), result2.getFrequency().getRanking()); } /** @@ -180,8 +190,13 @@ public class FileSorter implements Comparator { * @return -1 if file1's MIME type comes before file2's, 0 if equal, 1 * otherwise */ - private static Comparator getMIMETypeComparator() { - return (ResultFile file1, ResultFile file2) -> compareStrings(file1.getFirstInstance().getMIMEType(), file2.getFirstInstance().getMIMEType()); + private static Comparator getMIMETypeComparator() { + return (Result result1, Result result2) -> { + if (result1.getType() == SearchData.Type.DOMAIN) { + return 0; + } + return compareStrings(((ResultFile) result1).getFirstInstance().getMIMEType(), ((ResultFile) result2).getFirstInstance().getMIMEType()); + }; } /** @@ -189,9 +204,13 @@ public class FileSorter implements Comparator { * * @return -1 if file1 is larger than file2, 0 if equal, 1 otherwise */ - private static Comparator getFileSizeComparator() { - return (ResultFile file1, ResultFile file2) -> -1 * Long.compare(file1.getFirstInstance().getSize(), file2.getFirstInstance().getSize()) // Sort large to small - ; + private static Comparator getFileSizeComparator() { + return (Result result1, Result result2) -> { + if (result1.getType() == SearchData.Type.DOMAIN) { + return 0; + } + return -1 * Long.compare(((ResultFile) result1).getFirstInstance().getSize(), ((ResultFile) result2).getFirstInstance().getSize()); // Sort large to small + }; } /** @@ -199,8 +218,13 @@ public class FileSorter implements Comparator { * * @return -1 if file1 comes before file2, 0 if equal, 1 otherwise */ - private static Comparator getFileNameComparator() { - return (ResultFile file1, ResultFile file2) -> compareStrings(file1.getFirstInstance().getName().toLowerCase(), file2.getFirstInstance().getName().toLowerCase()); + private static Comparator getFileNameComparator() { + return (Result result1, Result result2) -> { + if (result1.getType() == SearchData.Type.DOMAIN) { + return 0; + } + return compareStrings(((ResultFile) result1).getFirstInstance().getName().toLowerCase(), (((ResultFile) result2).getFirstInstance().getName().toLowerCase())); + }; } /** @@ -211,14 +235,21 @@ public class FileSorter implements Comparator { * * @return -1 if file1 comes before file2, 0 if equal, 1 otherwise */ - private static Comparator getDefaultComparator() { - return (ResultFile file1, ResultFile file2) -> { + private static Comparator getDefaultComparator() { + return (Result result1, Result result2) -> { // Compare file names and then object ID (to ensure a consistent sort) - int result = getFileNameComparator().compare(file1, file2); - if (result == 0) { - return Long.compare(file1.getFirstInstance().getId(), file2.getFirstInstance().getId()); + if (result1.getType() == SearchData.Type.DOMAIN) { + return getFrequencyComparator().compare(result1, result2); + } else { + ResultFile file1 = (ResultFile) result1; + ResultFile file2 = (ResultFile) result2; + int result = getFileNameComparator().compare(file1, file2); + if (result == 0) { + return Long.compare(file1.getFirstInstance().getId(), file2.getFirstInstance().getId()); + } + return result; } - return result; + }; } @@ -234,6 +265,7 @@ public class FileSorter implements Comparator { String string1 = s1 == null ? "" : s1; String string2 = s2 == null ? "" : s2; return string1.compareTo(string2); + } /** @@ -247,7 +279,7 @@ public class FileSorter implements Comparator { "FileSorter.SortingMethod.frequency.displayName=Central Repo Frequency", "FileSorter.SortingMethod.keywordlist.displayName=Keyword List Names", "FileSorter.SortingMethod.fullPath.displayName=Full Path"}) - public enum SortingMethod { + public enum SortingMethod { BY_FILE_NAME(new ArrayList<>(), Bundle.FileSorter_SortingMethod_filename_displayName()), // Sort alphabetically by file name BY_DATA_SOURCE(new ArrayList<>(), diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/Group.java b/Core/src/org/sleuthkit/autopsy/discovery/search/Group.java index 30738df756..8c371adb5a 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/Group.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/Group.java @@ -30,7 +30,7 @@ public class Group implements Comparable { private final Group.GroupSortingAlgorithm groupSortingType; private final DiscoveryKeyUtils.GroupKey groupKey; - private final List files; + private final List results; private final String displayName; /** @@ -42,21 +42,23 @@ public class Group implements Comparable { public Group(Group.GroupSortingAlgorithm groupSortingType, DiscoveryKeyUtils.GroupKey groupKey) { this.groupSortingType = groupSortingType; this.groupKey = groupKey; - files = new ArrayList<>(); + results = new ArrayList<>(); this.displayName = groupKey.getDisplayName(); } /** - * Add a ResultFile to the group. Will not be sorted at this time. + * Add a Result to the group. Will not be sorted at this time. * - * @param file The ResultFile to add to the FileGroup + * @param result The Result to add to the FileGroup */ - void addFile(ResultFile file) { - if (files.contains(file)) { - ResultFile existingCopy = files.get(files.indexOf(file)); //get the copy of this which exists in the list - existingCopy.addDuplicate(file.getFirstInstance()); + void addResult(Result result) { + if (result.getType() != SearchData.Type.DOMAIN && results.contains(result)) { + //dedupe files and show instances + ResultFile existingCopy = (ResultFile)results.get(results.indexOf(result)); //get the copy of this which exists in the list + existingCopy.addDuplicate(((ResultFile)result).getFirstInstance()); } else { - files.add(file); + //Domains and non files are not being deduped currently + results.add(result); } } @@ -82,7 +84,7 @@ public class Group implements Comparable { * Sort all the files in the group */ public void sortFiles(FileSorter sorter) { - Collections.sort(files, sorter); + Collections.sort(results, sorter); } /** @@ -128,8 +130,8 @@ public class Group implements Comparable { * @return -1 if group1 should be displayed before group2, 1 otherwise */ private static int compareGroupsBySize(Group group1, Group group2) { - if (group1.getFiles().size() != group2.getFiles().size()) { - return -1 * Long.compare(group1.getFiles().size(), group2.getFiles().size()); // High to low + if (group1.getResults().size() != group2.getResults().size()) { + return -1 * Long.compare(group1.getResults().size(), group2.getResults().size()); // High to low } else { // If the groups have the same size, fall through to the BY_GROUP_NAME sorting return compareGroupsByGroupKey(group1, group2); @@ -168,8 +170,8 @@ public class Group implements Comparable { * * @return List of ResultFile objects */ - public List getFiles() { - return Collections.unmodifiableList(files); + public List getResults() { + return Collections.unmodifiableList(results); } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/Result.java b/Core/src/org/sleuthkit/autopsy/discovery/search/Result.java index 5c3ede6971..5286a41b3f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/Result.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/Result.java @@ -18,9 +18,67 @@ */ package org.sleuthkit.autopsy.discovery.search; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; + /** * Interface implemented by all types of results. */ -public interface Result { +public abstract class Result { + private SearchData.Frequency frequency; + private final List tagNames = new ArrayList<>(); + + public abstract long getDataSourceObjectId(); + + /** + * Get the frequency of this result in the central repository. + * + * @return The Frequency enum. + */ + public SearchData.Frequency getFrequency() { + return frequency; + } + + public abstract TskData.FileKnown getKnown(); + + /** + * Set the frequency of this result in the central repository. + * + * @param frequency The frequency of the result as an enum. + */ + final public void setFrequency(SearchData.Frequency frequency) { + this.frequency = frequency; + } + + public abstract Content getDataSource() throws TskCoreException; + + public abstract SearchData.Type getType(); + + /** + * Add a tag name that matched this file. + * + * @param tagName + */ + public void addTagName(String tagName) { + if (!tagNames.contains(tagName)) { + tagNames.add(tagName); + } + + // Sort the list so the getTagNames() will be consistent regardless of the order added + Collections.sort(tagNames); + } + + /** + * Get the tag names for this file + * + * @return the tag names that matched this file. + */ + public List getTagNames() { + return Collections.unmodifiableList(tagNames); + } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultDomain.java b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultDomain.java index b3b03ff3e0..950c5a88e3 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultDomain.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultDomain.java @@ -18,7 +18,34 @@ */ package org.sleuthkit.autopsy.discovery.search; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; + +public class ResultDomain extends Result { + + ResultDomain() { + this.setFrequency(SearchData.Frequency.UNKNOWN); + } + + @Override + public long getDataSourceObjectId() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Content getDataSource() throws TskCoreException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public TskData.FileKnown getKnown() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public SearchData.Type getType() { + return SearchData.Type.DOMAIN; + } -public class ResultDomain implements Result { - } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultFile.java b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultFile.java index 60274310ea..59bfbf48f2 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultFile.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultFile.java @@ -31,6 +31,7 @@ import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; import org.sleuthkit.autopsy.coreutils.Logger; import static org.sleuthkit.autopsy.discovery.search.SearchData.Type.OTHER; import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.HashUtility; import org.sleuthkit.datamodel.Tag; @@ -40,13 +41,11 @@ import org.sleuthkit.datamodel.TskData; /** * Container for files that holds all necessary data for grouping and sorting. */ -public class ResultFile implements Result{ +public class ResultFile extends Result { private final static Logger logger = Logger.getLogger(ResultFile.class.getName()); - private SearchData.Frequency frequency; private final List keywordListNames; private final List hashSetNames; - private final List tagNames; private final List interestingSetNames; private final List objectDetectedNames; private final List instances = new ArrayList<>(); @@ -73,33 +72,13 @@ public class ResultFile implements Result{ deleted = true; } updateScoreAndDescription(abstractFile); - this.frequency = SearchData.Frequency.UNKNOWN; keywordListNames = new ArrayList<>(); hashSetNames = new ArrayList<>(); - tagNames = new ArrayList<>(); interestingSetNames = new ArrayList<>(); objectDetectedNames = new ArrayList<>(); fileType = fromMIMEtype(abstractFile.getMIMEType()); } - /** - * Get the frequency of this file in the central repository - * - * @return The Frequency enum - */ - public SearchData.Frequency getFrequency() { - return frequency; - } - - /** - * Set the frequency of this file from the central repository - * - * @param frequency The frequency of the file as an enum - */ - public void setFrequency(SearchData.Frequency frequency) { - this.frequency = frequency; - } - /** * Add an AbstractFile to the list of files which are instances of this * file. @@ -218,29 +197,6 @@ public class ResultFile implements Result{ return Collections.unmodifiableList(hashSetNames); } - /** - * Add a tag name that matched this file. - * - * @param tagName - */ - public void addTagName(String tagName) { - if (!tagNames.contains(tagName)) { - tagNames.add(tagName); - } - - // Sort the list so the getTagNames() will be consistent regardless of the order added - Collections.sort(tagNames); - } - - /** - * Get the tag names for this file - * - * @return the tag names that matched this file. - */ - public List getTagNames() { - return Collections.unmodifiableList(tagNames); - } - /** * Add an interesting file set name that matched this file. * @@ -300,7 +256,7 @@ public class ResultFile implements Result{ public String toString() { return getFirstInstance().getName() + "(" + getFirstInstance().getId() + ") - " + getFirstInstance().getSize() + ", " + getFirstInstance().getParentPath() + ", " - + getFirstInstance().getDataSourceObjectId() + ", " + frequency.toString() + ", " + + getFirstInstance().getDataSourceObjectId() + ", " + getFrequency().toString() + ", " + String.join(",", keywordListNames) + ", " + getFirstInstance().getMIMEType(); } @@ -397,4 +353,24 @@ public class ResultFile implements Result{ } return OTHER; } + + @Override + public long getDataSourceObjectId() { + return getFirstInstance().getDataSourceObjectId(); + } + + @Override + public Content getDataSource() throws TskCoreException { + return getFirstInstance().getDataSource(); + } + + @Override + public TskData.FileKnown getKnown() { + return getFirstInstance().getKnown(); + } + + @Override + public Type getType() { + return fileType; + } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java index 59bf5e15d3..80def7276d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java @@ -54,7 +54,7 @@ public class SearchFiltering { * * @return */ - static List runQueries(List filters, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { + static List runQueries(List filters, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { if (caseDb == null) { throw new DiscoveryException("Case DB parameter is null"); // NON-NLS } @@ -94,9 +94,9 @@ public class SearchFiltering { * @throws TskCoreException * @throws DiscoveryException */ - private static List getResultList(List filters, String combinedQuery, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws TskCoreException, DiscoveryException { + private static List getResultList(List filters, String combinedQuery, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws TskCoreException, DiscoveryException { // Get all matching abstract files - List resultList = new ArrayList<>(); + List resultList = new ArrayList<>(); List sqlResults = caseDb.findAllFilesWhere(combinedQuery); // If there are no results, return now @@ -329,7 +329,7 @@ public class SearchFiltering { desc += searchTerm.getSearchStr() + Bundle.SearchFiltering_ParentFilter_substring(); } if (searchTerm.isIncluded()) { - desc += Bundle.SearchFiltering_ParentFilter_included(); + desc += Bundle.SearchFiltering_ParentFilter_included(); } else { desc += Bundle.SearchFiltering_ParentFilter_excluded(); } @@ -393,7 +393,7 @@ public class SearchFiltering { * A filter for specifying keyword list names. A file must contain a keyword * from one of the given lists to pass. */ - public static class KeywordListFilter extends AbstractFilter { + public static class KeywordListFilter extends AbstractFilter { private final List listNames; @@ -514,7 +514,7 @@ public class SearchFiltering { } @Override - public List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, + public List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { // We have to have run some kind of SQL filter before getting to this point, @@ -528,8 +528,8 @@ public class SearchFiltering { freqAttr.addAttributeToResultFiles(currentResults, caseDb, centralRepoDb); // If the frequency matches the filter, add the file to the results - List frequencyResults = new ArrayList<>(); - for (ResultFile file : currentResults) { + List frequencyResults = new ArrayList<>(); + for (Result file : currentResults) { if (frequencies.contains(file.getFrequency())) { frequencyResults.add(file); } @@ -834,7 +834,7 @@ public class SearchFiltering { } @Override - public List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, + public List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { if (centralRepoDb == null) { @@ -848,18 +848,21 @@ public class SearchFiltering { } // The matching files - List notableResults = new ArrayList<>(); + List notableResults = new ArrayList<>(); try { CorrelationAttributeInstance.Type type = CorrelationAttributeInstance.getDefaultCorrelationTypes().get(CorrelationAttributeInstance.FILES_TYPE_ID); - for (ResultFile file : currentResults) { + for (Result result : currentResults) { + ResultFile file = (ResultFile) result; + if (result.getType() == SearchData.Type.DOMAIN) { + break; + } if (file.getFirstInstance().getMd5Hash() != null && !file.getFirstInstance().getMd5Hash().isEmpty()) { - // Check if this file hash is marked as notable in the CR String value = file.getFirstInstance().getMd5Hash(); if (centralRepoDb.getCountArtifactInstancesKnownBad(type, value) > 0) { - notableResults.add(file); + notableResults.add(result); } } } @@ -927,7 +930,7 @@ public class SearchFiltering { return result; } - private SearchFiltering(){ + private SearchFiltering() { // Class should not be instantiated } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java index 176c22d652..485c5134c9 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java @@ -72,15 +72,15 @@ class SearchResults { * * @param files The list of ResultFiles to add. */ - void add(List files) { - for (ResultFile file : files) { + void add(List results) { + for (Result result : results) { // Add the file to the appropriate group, creating it if necessary - GroupKey groupKey = attrType.getGroupKey(file); + GroupKey groupKey = attrType.getGroupKey(result); if (!groupMap.containsKey(groupKey)) { groupMap.put(groupKey, new Group(groupSortingType, groupKey)); } - groupMap.get(groupKey).addFile(file); + groupMap.get(groupKey).addResult(result); } } @@ -102,25 +102,25 @@ class SearchResults { @Override public String toString() { - String result = ""; + String resultString = ""; if (groupList == null) { - return result; + return resultString; } long count = 0; for (Group group : groupList) { - result += group.getDisplayName() + "\n"; + resultString += group.getDisplayName() + "\n"; - for (ResultFile file : group.getFiles()) { - result += " " + file.toString() + "\n"; + for (Result result : group.getResults()) { + resultString += " " + result.toString() + "\n"; count++; if (count > MAX_OUTPUT_FILES) { - result += "(truncated)"; - return result; + resultString += "(truncated)"; + return resultString; } } } - return result; + return resultString; } /** @@ -129,7 +129,7 @@ class SearchResults { * @return The list of group names. */ List getGroupNamesWithCounts() { - return groupList.stream().map(p -> p.getDisplayName() + " (" + p.getFiles().size() + ")").collect(Collectors.toList()); + return groupList.stream().map(p -> p.getDisplayName() + " (" + p.getResults().size() + ")").collect(Collectors.toList()); } /** @@ -139,13 +139,13 @@ class SearchResults { * * @return The list of result files. */ - List getResultFilesInGroup(String groupName) { + List getResultFilesInGroup(String groupName) { if (groupName != null) { final String modifiedGroupName = groupName.replaceAll(" \\([0-9]+\\)$", ""); - java.util.Optional fileGroup = groupList.stream().filter(p -> p.getDisplayName().equals(modifiedGroupName)).findFirst(); - if (fileGroup.isPresent()) { - return fileGroup.get().getFiles(); + java.util.Optional group = groupList.stream().filter(p -> p.getDisplayName().equals(modifiedGroupName)).findFirst(); + if (group.isPresent()) { + return group.get().getResults(); } } return new ArrayList<>(); @@ -156,15 +156,15 @@ class SearchResults { * * @return The grouped and sorted results. */ - Map> toLinkedHashMap() throws DiscoveryException { - Map> map = new LinkedHashMap<>(); + Map> toLinkedHashMap() throws DiscoveryException { + Map> map = new LinkedHashMap<>(); // Sort the groups and files sortGroupsAndFiles(); // groupList is sorted and a LinkedHashMap will preserve that order. for (Group group : groupList) { - map.put(group.getGroupKey(), group.getFiles()); + map.put(group.getGroupKey(), group.getResults()); } return map; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryUiUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryUiUtils.java index 1e27e4e939..a1a15616e7 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryUiUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryUiUtils.java @@ -232,6 +232,7 @@ final class DiscoveryUiUtils { * Helper method to display an error message when the results of the * Discovery Top component may be incomplete. */ + @NbBundle.Messages({"DiscoveryUiUtils.resultsIncomplete.text=Discovery results may be incomplete"}) static void displayErrorMessage(DiscoveryDialog dialog) { //check if modules run and assemble message try { @@ -258,7 +259,7 @@ final class DiscoveryUiUtils { messageScrollPane.setMaximumSize(new Dimension(600, 100)); messageScrollPane.setPreferredSize(new Dimension(600, 100)); messageScrollPane.setViewportView(messageTextPane); - JOptionPane.showMessageDialog(dialog, messageScrollPane, Bundle.OpenDiscoveryAction_resultsIncomplete_text(), JOptionPane.PLAIN_MESSAGE); + JOptionPane.showMessageDialog(dialog, messageScrollPane, Bundle.DiscoveryUiUtils_resultsIncomplete_text(), JOptionPane.PLAIN_MESSAGE); } } catch (NoCurrentCaseException | TskCoreException ex) { logger.log(Level.WARNING, "Exception while determining which modules have been run for Discovery", ex); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/OpenDiscoveryAction.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/OpenDiscoveryAction.java index 74fb716425..adff2a38d4 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/OpenDiscoveryAction.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/OpenDiscoveryAction.java @@ -62,8 +62,6 @@ public final class OpenDiscoveryAction extends CallableSystemAction implements P return Case.isCaseOpen(); } - @NbBundle.Messages({"OpenDiscoveryAction.resultsIncomplete.text=Discovery results may be incomplete"}) - @Override public void performAction() { SwingUtilities.invokeLater(() -> { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java index 3a9033b08f..602c38666f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java @@ -34,7 +34,7 @@ import org.sleuthkit.autopsy.discovery.search.FileSearch; import org.sleuthkit.autopsy.discovery.search.SearchData; import org.sleuthkit.autopsy.discovery.search.DiscoveryException; import org.sleuthkit.autopsy.discovery.search.FileSorter; -import org.sleuthkit.autopsy.discovery.search.ResultFile; +import org.sleuthkit.autopsy.discovery.search.Result; /** * SwingWorker to retrieve the contents of a page. @@ -52,7 +52,7 @@ final class PageWorker extends SwingWorker { private final int pageSize; private final SearchData.Type resultType; private final CentralRepository centralRepo; - private final List results = new ArrayList<>(); + private final List results = new ArrayList<>(); /** * Construct a new PageWorker. From 3b5863e0326edac654f826ee006c1d50a6ffa039 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 20 Aug 2020 16:12:35 -0400 Subject: [PATCH 025/130] 6711 fixes for ResultsPanel for casting --- .../discovery/search/Bundle.properties-MERGED | 32 +++++++++---------- .../autopsy/discovery/search/SearchData.java | 8 ++--- .../discovery/ui/Bundle.properties-MERGED | 2 +- .../discovery/ui/DocumentFilterPanel.java | 2 +- .../autopsy/discovery/ui/ResultsPanel.java | 27 +++++++++------- .../autopsy/discovery/ui/SizeFilterPanel.java | 2 +- 6 files changed, 38 insertions(+), 35 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED index 41cab2b5c2..b9682d5095 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED @@ -1,25 +1,25 @@ +DiscoveryAttributes.GroupingAttributeType.datasource.displayName=Data Source +DiscoveryAttributes.GroupingAttributeType.fileType.displayName=File Type +DiscoveryAttributes.GroupingAttributeType.frequency.displayName=Past Occurrences +DiscoveryAttributes.GroupingAttributeType.hash.displayName=Hash Set +DiscoveryAttributes.GroupingAttributeType.interestingItem.displayName=Interesting Item +DiscoveryAttributes.GroupingAttributeType.keywordList.displayName=Keyword +DiscoveryAttributes.GroupingAttributeType.none.displayName=None +DiscoveryAttributes.GroupingAttributeType.object.displayName=Object Detected +DiscoveryAttributes.GroupingAttributeType.parent.displayName=Parent Folder +DiscoveryAttributes.GroupingAttributeType.size.displayName=File Size +DiscoveryAttributes.GroupingAttributeType.tag.displayName=Tag +# {0} - Data source name +# {1} - Data source ID +DiscoveryKeyUtils.DataSourceGroupKey.datasourceAndID={0}(ID: {1}) +# {0} - Data source ID +DiscoveryKeyUtils.DataSourceGroupKey.idOnly=Data source (ID: {0}) DiscoveryKeyUtils.FileTagGroupKey.noSets=None DiscoveryKeyUtils.NoGroupingGroupKey.allFiles=All Files FileGroup.groupSortingAlgorithm.groupName.text=Group Name FileGroup.groupSortingAlgorithm.groupSize.text=Group Size -# {0} - Data source name -# {1} - Data source ID -FileSearch.DataSourceGroupKey.datasourceAndID={0}(ID: {1}) -# {0} - Data source ID -FileSearch.DataSourceGroupKey.idOnly=Data source (ID: {0}) FileSearch.documentSummary.noBytes=No bytes read for document, unable to display preview. FileSearch.documentSummary.noPreview=No preview available. -FileSearch.GroupingAttributeType.datasource.displayName=Data Source -FileSearch.GroupingAttributeType.fileType.displayName=File Type -FileSearch.GroupingAttributeType.frequency.displayName=Past Occurrences -FileSearch.GroupingAttributeType.hash.displayName=Hash Set -FileSearch.GroupingAttributeType.interestingItem.displayName=Interesting Item -FileSearch.GroupingAttributeType.keywordList.displayName=Keyword -FileSearch.GroupingAttributeType.none.displayName=None -FileSearch.GroupingAttributeType.object.displayName=Object Detected -FileSearch.GroupingAttributeType.parent.displayName=Parent Folder -FileSearch.GroupingAttributeType.size.displayName=File Size -FileSearch.GroupingAttributeType.tag.displayName=Tag FileSearch.HashHitsGroupKey.noHashHits=None FileSearch.InterestingItemGroupKey.noSets=None FileSearch.KeywordListGroupKey.noKeywords=None diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchData.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchData.java index eb0ca6e210..88f0b91e10 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchData.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchData.java @@ -324,9 +324,9 @@ public final class SearchData { "SearchData.FileType.Audio.displayName=Audio", "SearchData.FileType.Video.displayName=Video", "SearchData.FileType.Image.displayName=Image", - "SearchData.FileType.Documents.displayName=Documents", - "SearchData.FileType.Executables.displayName=Executables", - "SearchData.AttributeType.Domain.displayName=Domains", + "SearchData.FileType.Documents.displayName=Document", + "SearchData.FileType.Executables.displayName=Executable", + "SearchData.AttributeType.Domain.displayName=Domain", "SearchData.FileType.Other.displayName=Other/Unknown"}) public enum Type { @@ -334,7 +334,7 @@ public final class SearchData { AUDIO(1, Bundle.SearchData_FileType_Audio_displayName(), FileTypeUtils.FileTypeCategory.AUDIO.getMediaTypes(), new ArrayList<>()), VIDEO(2, Bundle.SearchData_FileType_Video_displayName(), FileTypeUtils.FileTypeCategory.VIDEO.getMediaTypes(), new ArrayList<>()), EXECUTABLE(3, Bundle.SearchData_FileType_Executables_displayName(), FileTypeUtils.FileTypeCategory.EXECUTABLE.getMediaTypes(),new ArrayList<>()), - DOCUMENTS(4, Bundle.SearchData_FileType_Documents_displayName(), DOCUMENT_MIME_TYPES, new ArrayList<>()), + DOCUMENT(4, Bundle.SearchData_FileType_Documents_displayName(), DOCUMENT_MIME_TYPES, new ArrayList<>()), DOMAIN(6, Bundle.SearchData_AttributeType_Domain_displayName(), new ArrayList<>(), DOMAIN_ARTIFACT_TYPES), OTHER(5, Bundle.SearchData_FileType_Other_displayName(), new ArrayList<>(), new ArrayList<>()); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED index 57cbd4cf00..1e9224cf9b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED @@ -28,6 +28,7 @@ DiscoveryUiUtility.terraBytes.text=TB # {0} - file name DiscoveryUiUtils.genVideoThumb.progress.text=extracting temporary file {0} DiscoveryUiUtils.isDeleted.text=All instances of file are deleted. +DiscoveryUiUtils.resultsIncomplete.text=Discovery results may be incomplete # {0} - otherInstanceCount DocumentPanel.nameLabel.more.text=\ and {0} more DocumentPanel.noImageExtraction.text=0 of ? images @@ -40,7 +41,6 @@ GroupsListPanel.noResults.title.text=No results found ImageThumbnailPanel.isDeleted.text=All instances of file are deleted. # {0} - otherInstanceCount ImageThumbnailPanel.nameLabel.more.text=\ and {0} more -OpenDiscoveryAction.resultsIncomplete.text=Discovery results may be incomplete # {0} - currentPage # {1} - totalPages ResultsPanel.currentPage.displayValue=Page: {0} of {1} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentFilterPanel.java index 888f7285d5..44e303ccc1 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DocumentFilterPanel.java @@ -27,7 +27,7 @@ import org.sleuthkit.autopsy.discovery.search.SearchData; final class DocumentFilterPanel extends AbstractFiltersPanel { private static final long serialVersionUID = 1L; - private static final SearchData.Type TYPE = SearchData.Type.DOCUMENTS; + private static final SearchData.Type TYPE = SearchData.Type.DOCUMENT; /** * Constructs a new DocumentFilterPanel. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java index d11700e336..76aa41ec9d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java @@ -45,6 +45,7 @@ import org.sleuthkit.autopsy.discovery.search.Group; import org.sleuthkit.autopsy.discovery.search.FileSearch; import org.sleuthkit.autopsy.discovery.search.SearchData; import org.sleuthkit.autopsy.discovery.search.FileSorter; +import org.sleuthkit.autopsy.discovery.search.Result; import org.sleuthkit.autopsy.discovery.search.ResultFile; import org.sleuthkit.autopsy.textsummarizer.TextSummary; @@ -105,7 +106,7 @@ final class ResultsPanel extends javax.swing.JPanel { } }); documentPreviewViewer.addListSelectionListener((e) -> { - if (resultType == SearchData.Type.DOCUMENTS) { + if (resultType == SearchData.Type.DOCUMENT) { if (!e.getValueIsAdjusting()) { //send populateMesage DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.PopulateInstancesListEvent(getInstancesForSelected())); @@ -131,7 +132,7 @@ final class ResultsPanel extends javax.swing.JPanel { return videoThumbnailViewer.getInstancesForSelected(); case IMAGE: return imageThumbnailViewer.getInstancesForSelected(); - case DOCUMENTS: + case DOCUMENT: return documentPreviewViewer.getInstancesForSelected(); default: break; @@ -176,10 +177,12 @@ final class ResultsPanel extends javax.swing.JPanel { populateVideoViewer(pageRetrievedEvent.getSearchResults()); resultsViewerPanel.add(videoThumbnailViewer); break; - case DOCUMENTS: + case DOCUMENT: populateDocumentViewer(pageRetrievedEvent.getSearchResults()); resultsViewerPanel.add(documentPreviewViewer); break; + case DOMAIN: + break; default: break; } @@ -217,9 +220,9 @@ final class ResultsPanel extends javax.swing.JPanel { * * @param files The list of ResultFiles to populate the video viewer with. */ - synchronized void populateVideoViewer(List files) { - for (ResultFile file : files) { - VideoThumbnailWorker thumbWorker = new VideoThumbnailWorker(file); + synchronized void populateVideoViewer(List results) { + for (Result result : results) { + VideoThumbnailWorker thumbWorker = new VideoThumbnailWorker((ResultFile) result); thumbWorker.execute(); //keep track of thumb worker for possible cancelation resultContentWorkers.add(thumbWorker); @@ -232,9 +235,9 @@ final class ResultsPanel extends javax.swing.JPanel { * * @param files The list of ResultFiles to populate the image viewer with. */ - synchronized void populateImageViewer(List files) { - for (ResultFile file : files) { - ImageThumbnailWorker thumbWorker = new ImageThumbnailWorker(file); + synchronized void populateImageViewer(List results) { + for (Result result : results) { + ImageThumbnailWorker thumbWorker = new ImageThumbnailWorker((ResultFile) result); thumbWorker.execute(); //keep track of thumb worker for possible cancelation resultContentWorkers.add(thumbWorker); @@ -247,9 +250,9 @@ final class ResultsPanel extends javax.swing.JPanel { * * @param files The list of ResultFiles to populate the image viewer with. */ - synchronized void populateDocumentViewer(List files) { - for (ResultFile file : files) { - DocumentPreviewWorker documentWorker = new DocumentPreviewWorker(file); + synchronized void populateDocumentViewer(List results) { + for (Result result : results) { + DocumentPreviewWorker documentWorker = new DocumentPreviewWorker((ResultFile) result); documentWorker.execute(); //keep track of thumb worker for possible cancelation resultContentWorkers.add(documentWorker); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/SizeFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/SizeFilterPanel.java index b0a71fbd25..9f9245937b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/SizeFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/SizeFilterPanel.java @@ -153,7 +153,7 @@ final class SizeFilterPanel extends AbstractDiscoveryFilterPanel { case IMAGE: sizes = FileSize.getDefaultSizeOptions(); break; - case DOCUMENTS: + case DOCUMENT: sizes = FileSize.getDefaultSizeOptions(); break; default: From d39fed8879246b568f185b527eb54b446251ebf9 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 20 Aug 2020 16:47:56 -0400 Subject: [PATCH 026/130] 6711 stub out DomainSearch --- .../discovery/search/Bundle.properties-MERGED | 6 +- .../discovery/search/DiscoveryAttributes.java | 30 +++-- .../discovery/search/DiscoveryEventUtils.java | 12 +- .../discovery/search/DiscoveryKeyUtils.java | 2 +- .../discovery/search/DomainSearch.java | 104 ++++++++++++++++++ .../autopsy/discovery/search/FileSearch.java | 9 +- .../autopsy/discovery/search/Group.java | 2 +- .../autopsy/discovery/search/Result.java | 12 ++ .../discovery/search/ResultDomain.java | 13 ++- .../autopsy/discovery/search/ResultFile.java | 2 +- .../{FileSorter.java => ResultsSorter.java} | 4 +- .../discovery/search/SearchResults.java | 8 +- .../autopsy/discovery/ui/DiscoveryDialog.java | 14 +-- .../autopsy/discovery/ui/PageWorker.java | 25 +++-- .../autopsy/discovery/ui/ResultsPanel.java | 4 +- .../autopsy/discovery/ui/SearchWorker.java | 28 +++-- 16 files changed, 218 insertions(+), 57 deletions(-) rename Core/src/org/sleuthkit/autopsy/discovery/search/{FileSorter.java => ResultsSorter.java} (99%) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED index b9682d5095..fbb3240018 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED @@ -44,7 +44,7 @@ ResultFile.score.interestingResult.description=At least one instance of the file ResultFile.score.notableFile.description=At least one instance of the file was recognized as notable. ResultFile.score.notableTaggedFile.description=At least one instance of the file is tagged with a notable tag. ResultFile.score.taggedFile.description=At least one instance of the file has been tagged. -SearchData.AttributeType.Domain.displayName=Domains +SearchData.AttributeType.Domain.displayName=Domain SearchData.FileSize.100kbto1mb=: 100KB-1MB SearchData.FileSize.100mbto1gb=: 100MB-1GB SearchData.FileSize.10PlusGb=: 10GB+ @@ -64,8 +64,8 @@ SearchData.FileSize.XLARGE.displayName=XLarge SearchData.FileSize.XSMALL.displayName=XSmall SearchData.FileSize.XXLARGE.displayName=XXLarge SearchData.FileType.Audio.displayName=Audio -SearchData.FileType.Documents.displayName=Documents -SearchData.FileType.Executables.displayName=Executables +SearchData.FileType.Documents.displayName=Document +SearchData.FileType.Executables.displayName=Executable SearchData.FileType.Image.displayName=Image SearchData.FileType.Other.displayName=Other/Unknown SearchData.FileType.Video.displayName=Video diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java index 6c4a2095f1..d214236e83 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy + * + * 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.discovery.search; @@ -32,8 +45,8 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; /** - * - * @author wschaefer + * Class which contains the search attributes which can be specified for + * Discovery. */ public class DiscoveryAttributes { @@ -75,8 +88,8 @@ public class DiscoveryAttributes { public static class FileSizeAttribute extends AttributeType { @Override - public DiscoveryKeyUtils.GroupKey getGroupKey(Result file) { - return new DiscoveryKeyUtils.FileSizeGroupKey((ResultFile) file); + public DiscoveryKeyUtils.GroupKey getGroupKey(Result result) { + return new DiscoveryKeyUtils.FileSizeGroupKey(result); } } @@ -678,6 +691,9 @@ public class DiscoveryAttributes { + ") "; // NON-NLS } + /** + * Private constructor for DiscoveryAttributes class. + */ private DiscoveryAttributes() { // Class should not be instantiated } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java index 62aba44045..88ff2efc38 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java @@ -121,7 +121,7 @@ public final class DiscoveryEventUtils { private final List searchFilters; private final DiscoveryAttributes.AttributeType groupingAttribute; private final Group.GroupSortingAlgorithm groupSort; - private final FileSorter.SortingMethod fileSortMethod; + private final ResultsSorter.SortingMethod fileSortMethod; /** * Construct a new SearchCompleteEvent, @@ -136,7 +136,7 @@ public final class DiscoveryEventUtils { */ public SearchCompleteEvent(Map groupMap, List searchfilters, DiscoveryAttributes.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, - FileSorter.SortingMethod fileSortMethod) { + ResultsSorter.SortingMethod fileSortMethod) { this.groupMap = groupMap; this.searchFilters = searchfilters; this.groupingAttribute = groupingAttribute; @@ -185,7 +185,7 @@ public final class DiscoveryEventUtils { * * @return The sorting method used for files. */ - public FileSorter.SortingMethod getFileSort() { + public ResultsSorter.SortingMethod getFileSort() { return fileSortMethod; } @@ -280,7 +280,7 @@ public final class DiscoveryEventUtils { private final List searchfilters; private final DiscoveryAttributes.AttributeType groupingAttribute; private final Group.GroupSortingAlgorithm groupSort; - private final FileSorter.SortingMethod fileSortMethod; + private final ResultsSorter.SortingMethod fileSortMethod; /** * Construct a new GroupSelectedEvent. @@ -298,7 +298,7 @@ public final class DiscoveryEventUtils { */ public GroupSelectedEvent(List searchfilters, DiscoveryAttributes.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, - FileSorter.SortingMethod fileSortMethod, GroupKey groupKey, int groupSize, Type resultType) { + ResultsSorter.SortingMethod fileSortMethod, GroupKey groupKey, int groupSize, Type resultType) { this.searchfilters = searchfilters; this.groupingAttribute = groupingAttribute; this.groupSort = groupSort; @@ -351,7 +351,7 @@ public final class DiscoveryEventUtils { * * @return The sorting method used for files. */ - public FileSorter.SortingMethod getFileSort() { + public ResultsSorter.SortingMethod getFileSort() { return fileSortMethod; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java index f970a6541e..8f21a89f30 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java @@ -54,7 +54,7 @@ public class DiscoveryKeyUtils { SearchKey(String userName, List filters, DiscoveryAttributes.AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, - FileSorter.SortingMethod fileSortingMethod) { + ResultsSorter.SortingMethod fileSortingMethod) { StringBuilder searchStringBuilder = new StringBuilder(); searchStringBuilder.append(userName); for (AbstractFilter filter : filters) { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java index 69843e0708..dfb0248d86 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java @@ -18,11 +18,115 @@ */ package org.sleuthkit.autopsy.discovery.search; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import java.util.List; +import java.util.Map; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.SleuthkitCase; + /** * Main class to perform the domain search. */ public class DomainSearch { + private final static Logger logger = Logger.getLogger(DomainSearch.class.getName()); + private static final int MAXIMUM_CACHE_SIZE = 10; + private static final Cache>> searchCache = CacheBuilder.newBuilder() + .maximumSize(MAXIMUM_CACHE_SIZE) + .build(); + + /** + * Run the domain search to get the group keys and sizes. Clears cache of + * search results, caching new results for access at later time. + * + * @param userName The name of the user performing the search. + * @param filters The filters to apply + * @param groupAttributeType The attribute to use for grouping + * @param groupSortingType The method to use to sort the groups + * @param domainSortingMethod The method to use to sort the domains within + * the groups + * @param caseDb The case database + * @param centralRepoDb The central repository database. Can be null + * if not needed. + * + * @return A LinkedHashMap grouped and sorted according to the parameters + * + * @throws DiscoveryException + */ + public static Map getGroupSizes(String userName, + List filters, + DiscoveryAttributes.AttributeType groupAttributeType, + Group.GroupSortingAlgorithm groupSortingType, + ResultsSorter.SortingMethod domainSortingMethod, + SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + /** + * Get the domains from the specified group from the cache, if the the group + * was not cached perform a search caching the groups. + * + * @param userName The name of the user performing the search. + * @param filters The filters to apply + * @param groupAttributeType The attribute to use for grouping + * @param groupSortingType The method to use to sort the groups + * @param domainSortingMethod The method to use to sort the Domains within + * the groups + * @param groupKey The key which uniquely identifies the group to + * get entries from + * @param startingEntry The first entry to return + * @param numberOfEntries The number of entries to return + * @param caseDb The case database + * @param centralRepoDb The central repository database. Can be null + * if not needed. + * + * @return A LinkedHashMap grouped and sorted according to the parameters + * + * @throws DiscoveryException + */ + public static List getDomainsInGroup(String userName, + List filters, + DiscoveryAttributes.AttributeType groupAttributeType, + Group.GroupSortingAlgorithm groupSortingType, + ResultsSorter.SortingMethod domainSortingMethod, + DiscoveryKeyUtils.GroupKey groupKey, + int startingEntry, + int numberOfEntries, + SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + /** + * Run the Domain search. Caching new results for access at later time. + * + * @param userName The name of the user performing the search. + * @param filters The filters to apply + * @param groupAttributeType The attribute to use for grouping + * @param groupSortingType The method to use to sort the groups + * @param domainSortingMethod The method to use to sort the domains within + * the groups + * @param caseDb The case database + * @param centralRepoDb The central repository database. Can be null if + * not needed. + * + * @return A LinkedHashMap grouped and sorted according to the parameters + * + * @throws DiscoveryException + */ + private static Map> runDomainSearch(String userName, + List filters, + DiscoveryAttributes.AttributeType groupAttributeType, + Group.GroupSortingAlgorithm groupSortingType, + ResultsSorter.SortingMethod domainSortingMethod, + SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + /** + * Private constructor for DomainSearch class. + */ private DomainSearch() { // Class should not be instantiated } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java index 3f667c302c..aea0d18249 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java @@ -71,7 +71,7 @@ public class FileSearch { List filters, AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, - FileSorter.SortingMethod fileSortingMethod, + ResultsSorter.SortingMethod fileSortingMethod, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { // Make a list of attributes that we want to add values for. This ensures the // ResultFile objects will have all needed fields set when it's time to group @@ -123,7 +123,7 @@ public class FileSearch { List filters, AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, - FileSorter.SortingMethod fileSortingMethod, + ResultsSorter.SortingMethod fileSortingMethod, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { Map> searchResults = runFileSearch(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod, caseDb, centralRepoDb); @@ -160,7 +160,7 @@ public class FileSearch { List filters, AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, - FileSorter.SortingMethod fileSortingMethod, + ResultsSorter.SortingMethod fileSortingMethod, GroupKey groupKey, int startingEntry, int numberOfEntries, @@ -256,7 +256,7 @@ public class FileSearch { List filters, AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, - FileSorter.SortingMethod fileSortingMethod, + ResultsSorter.SortingMethod fileSortingMethod, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { // Make a list of attributes that we want to add values for. This ensures the @@ -305,7 +305,6 @@ public class FileSearch { } } - private FileSearch() { // Class should not be instantiated } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/Group.java b/Core/src/org/sleuthkit/autopsy/discovery/search/Group.java index 8c371adb5a..de96b5750f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/Group.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/Group.java @@ -83,7 +83,7 @@ public class Group implements Comparable { /** * Sort all the files in the group */ - public void sortFiles(FileSorter sorter) { + public void sortFiles(ResultsSorter sorter) { Collections.sort(results, sorter); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/Result.java b/Core/src/org/sleuthkit/autopsy/discovery/search/Result.java index 5286a41b3f..4f4151eec5 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/Result.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/Result.java @@ -55,8 +55,20 @@ public abstract class Result { this.frequency = frequency; } + /** + * Get the data source associated with this result. + * + * @return The data source this result came from. + * + * @throws TskCoreException + */ public abstract Content getDataSource() throws TskCoreException; + /** + * Get the type of this result. + * + * @return The type of items being searched for. + */ public abstract SearchData.Type getType(); /** diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultDomain.java b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultDomain.java index 950c5a88e3..f132a3f9cc 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultDomain.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultDomain.java @@ -22,9 +22,18 @@ import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; +/** + * Container for domains that holds all necessary data for grouping and sorting. + */ public class ResultDomain extends Result { - - ResultDomain() { + private String domain; + /** + * Create a ResultDomain from a String. + * + * @param domain The domain the result is being created from. + */ + ResultDomain(String domain) { + this.domain = domain; this.setFrequency(SearchData.Frequency.UNKNOWN); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultFile.java b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultFile.java index 59bfbf48f2..de879910a5 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultFile.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultFile.java @@ -59,7 +59,7 @@ public class ResultFile extends Result { * * @param abstractFile */ - public ResultFile(AbstractFile abstractFile) { + public ResultFile(BlackboardA abstractFile) { try { //call get uniquePath to cache the path abstractFile.getUniquePath(); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSorter.java b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultsSorter.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/discovery/search/FileSorter.java rename to Core/src/org/sleuthkit/autopsy/discovery/search/ResultsSorter.java index f6d3e31ad0..45a411d8af 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSorter.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultsSorter.java @@ -29,7 +29,7 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Class used to sort ResultFiles using the supplied method. */ -public class FileSorter implements Comparator { +public class ResultsSorter implements Comparator { private final List> comparators = new ArrayList<>(); @@ -40,7 +40,7 @@ public class FileSorter implements Comparator { * * @param method The method that should be used to sort the files */ - public FileSorter(SortingMethod method) { + public ResultsSorter(SortingMethod method) { // Set up the primary comparators that should applied to the files switch (method) { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java index 485c5134c9..3cd64a9e13 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java @@ -34,7 +34,7 @@ class SearchResults { private final Group.GroupSortingAlgorithm groupSortingType; private final DiscoveryAttributes.AttributeType attrType; - private final FileSorter fileSorter; + private final ResultsSorter fileSorter; private final Map groupMap = new HashMap<>(); private List groupList = new ArrayList<>(); @@ -51,10 +51,10 @@ class SearchResults { * sortGroupsAndFiles the files in each group. */ SearchResults(Group.GroupSortingAlgorithm groupSortingType, DiscoveryAttributes.AttributeType attrType, - FileSorter.SortingMethod fileSortingMethod) { + ResultsSorter.SortingMethod fileSortingMethod) { this.groupSortingType = groupSortingType; this.attrType = attrType; - this.fileSorter = new FileSorter(fileSortingMethod); + this.fileSorter = new ResultsSorter(fileSortingMethod); } /** @@ -64,7 +64,7 @@ class SearchResults { SearchResults() { this.groupSortingType = Group.GroupSortingAlgorithm.BY_GROUP_NAME; this.attrType = new DiscoveryAttributes.FileSizeAttribute(); - this.fileSorter = new FileSorter(FileSorter.SortingMethod.BY_FILE_NAME); + this.fileSorter = new ResultsSorter(ResultsSorter.SortingMethod.BY_FILE_NAME); } /** diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index 7227388742..2f629f6443 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -44,9 +44,9 @@ import org.sleuthkit.autopsy.discovery.search.Group.GroupSortingAlgorithm; import static org.sleuthkit.autopsy.discovery.search.Group.GroupSortingAlgorithm.BY_GROUP_SIZE; import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes.GroupingAttributeType; import static org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes.GroupingAttributeType.PARENT_PATH; -import org.sleuthkit.autopsy.discovery.search.FileSorter; -import org.sleuthkit.autopsy.discovery.search.FileSorter.SortingMethod; -import static org.sleuthkit.autopsy.discovery.search.FileSorter.SortingMethod.BY_FILE_NAME; +import org.sleuthkit.autopsy.discovery.search.ResultsSorter; +import org.sleuthkit.autopsy.discovery.search.ResultsSorter.SortingMethod; +import static org.sleuthkit.autopsy.discovery.search.ResultsSorter.SortingMethod.BY_FILE_NAME; import org.sleuthkit.autopsy.discovery.search.SearchData; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -175,7 +175,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { groupByCombobox.setSelectedItem(PARENT_PATH); orderByCombobox.removeAllItems(); // Set up the file order list - for (FileSorter.SortingMethod method : FileSorter.SortingMethod.getOptionsForOrdering()) { + for (ResultsSorter.SortingMethod method : ResultsSorter.SortingMethod.getOptionsForOrdering()) { if (method != SortingMethod.BY_FREQUENCY || CentralRepository.isEnabled()) { orderByCombobox.addItem(method); } @@ -232,7 +232,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { videoFilterPanel.validateFields(); } break; - case DOCUMENTS: + case DOCUMENT: if (documentFilterPanel != null) { documentFilterPanel.validateFields(); } @@ -497,7 +497,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { documentsButton.setEnabled(false); documentsButton.setBackground(SELECTED_COLOR); documentsButton.setForeground(Color.BLACK); - type = SearchData.Type.DOCUMENTS; + type = SearchData.Type.DOCUMENT; documentFilterPanel.addPropertyChangeListener(listener); validateDialog(); pack(); @@ -558,7 +558,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { Group.GroupSortingAlgorithm groupSortAlgorithm = groupSortingComboBox.getItemAt(groupSortingComboBox.getSelectedIndex()); // Get the file sorting method - FileSorter.SortingMethod fileSort = (FileSorter.SortingMethod) orderByCombobox.getSelectedItem(); + ResultsSorter.SortingMethod fileSort = (ResultsSorter.SortingMethod) orderByCombobox.getSelectedItem(); CentralRepository centralRepoDb = null; if (CentralRepository.isEnabled()) { try { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java index 602c38666f..54ed286f9e 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java @@ -33,7 +33,8 @@ import org.sleuthkit.autopsy.discovery.search.Group; import org.sleuthkit.autopsy.discovery.search.FileSearch; import org.sleuthkit.autopsy.discovery.search.SearchData; import org.sleuthkit.autopsy.discovery.search.DiscoveryException; -import org.sleuthkit.autopsy.discovery.search.FileSorter; +import org.sleuthkit.autopsy.discovery.search.DomainSearch; +import org.sleuthkit.autopsy.discovery.search.ResultsSorter; import org.sleuthkit.autopsy.discovery.search.Result; /** @@ -46,7 +47,7 @@ final class PageWorker extends SwingWorker { private final List searchfilters; private final DiscoveryAttributes.AttributeType groupingAttribute; private final Group.GroupSortingAlgorithm groupSort; - private final FileSorter.SortingMethod fileSortMethod; + private final ResultsSorter.SortingMethod fileSortMethod; private final GroupKey groupKey; private final int startingEntry; private final int pageSize; @@ -71,7 +72,7 @@ final class PageWorker extends SwingWorker { * @param centralRepo The central repository to be used. */ PageWorker(List searchfilters, DiscoveryAttributes.AttributeType groupingAttribute, - Group.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod, GroupKey groupKey, + Group.GroupSortingAlgorithm groupSort, ResultsSorter.SortingMethod fileSortMethod, GroupKey groupKey, int startingEntry, int pageSize, SearchData.Type resultType, CentralRepository centralRepo) { this.searchfilters = searchfilters; this.groupingAttribute = groupingAttribute; @@ -89,11 +90,19 @@ final class PageWorker extends SwingWorker { try { // Run the search - results.addAll(FileSearch.getFilesInGroup(System.getProperty(USER_NAME_PROPERTY), searchfilters, - groupingAttribute, - groupSort, - fileSortMethod, groupKey, startingEntry, pageSize, - Case.getCurrentCase().getSleuthkitCase(), centralRepo)); + if (resultType == SearchData.Type.DOMAIN) { + results.addAll(DomainSearch.getDomainsInGroup(System.getProperty(USER_NAME_PROPERTY), searchfilters, + groupingAttribute, + groupSort, + fileSortMethod, groupKey, startingEntry, pageSize, + Case.getCurrentCase().getSleuthkitCase(), centralRepo)); + } else { + results.addAll(FileSearch.getFilesInGroup(System.getProperty(USER_NAME_PROPERTY), searchfilters, + groupingAttribute, + groupSort, + fileSortMethod, groupKey, startingEntry, pageSize, + Case.getCurrentCase().getSleuthkitCase(), centralRepo)); + } } catch (DiscoveryException ex) { logger.log(Level.SEVERE, "Error running file search test", ex); cancel(true); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java index 76aa41ec9d..64f68d5515 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java @@ -44,7 +44,7 @@ import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; import org.sleuthkit.autopsy.discovery.search.Group; import org.sleuthkit.autopsy.discovery.search.FileSearch; import org.sleuthkit.autopsy.discovery.search.SearchData; -import org.sleuthkit.autopsy.discovery.search.FileSorter; +import org.sleuthkit.autopsy.discovery.search.ResultsSorter; import org.sleuthkit.autopsy.discovery.search.Result; import org.sleuthkit.autopsy.discovery.search.ResultFile; import org.sleuthkit.autopsy.textsummarizer.TextSummary; @@ -63,7 +63,7 @@ final class ResultsPanel extends javax.swing.JPanel { private List searchFilters; private DiscoveryAttributes.AttributeType groupingAttribute; private Group.GroupSortingAlgorithm groupSort; - private FileSorter.SortingMethod fileSortMethod; + private ResultsSorter.SortingMethod fileSortMethod; private GroupKey selectedGroupKey; private int currentPage = 0; private int previousPageSize = 10; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java index 4453743bcf..a2e35c7a29 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java @@ -33,7 +33,9 @@ import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; import org.sleuthkit.autopsy.discovery.search.Group; import org.sleuthkit.autopsy.discovery.search.FileSearch; import org.sleuthkit.autopsy.discovery.search.DiscoveryException; -import org.sleuthkit.autopsy.discovery.search.FileSorter; +import org.sleuthkit.autopsy.discovery.search.DomainSearch; +import org.sleuthkit.autopsy.discovery.search.ResultsSorter; +import org.sleuthkit.autopsy.discovery.search.SearchData; /** * SwingWorker to perform search on a background thread. @@ -44,9 +46,10 @@ final class SearchWorker extends SwingWorker { private static final String USER_NAME_PROPERTY = "user.name"; //NON-NLS private final List filters; private final DiscoveryAttributes.AttributeType groupingAttr; - private final FileSorter.SortingMethod fileSort; + private final ResultsSorter.SortingMethod fileSort; private final Group.GroupSortingAlgorithm groupSortAlgorithm; private final CentralRepository centralRepoDb; + private final SearchData.Type searchType; private final Map results = new LinkedHashMap<>(); /** @@ -59,8 +62,9 @@ final class SearchWorker extends SwingWorker { * @param groupSort The Algorithm to sort groups by. * @param fileSortMethod The SortingMethod to use for files. */ - SearchWorker(CentralRepository centralRepo, List searchfilters, DiscoveryAttributes.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod) { + SearchWorker(CentralRepository centralRepo, SearchData.Type type, List searchfilters, DiscoveryAttributes.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, ResultsSorter.SortingMethod fileSortMethod) { centralRepoDb = centralRepo; + searchType = type; filters = searchfilters; groupingAttr = groupingAttribute; groupSortAlgorithm = groupSort; @@ -71,11 +75,19 @@ final class SearchWorker extends SwingWorker { protected Void doInBackground() throws Exception { try { // Run the search - results.putAll(FileSearch.getGroupSizes(System.getProperty(USER_NAME_PROPERTY), filters, - groupingAttr, - groupSortAlgorithm, - fileSort, - Case.getCurrentCase().getSleuthkitCase(), centralRepoDb)); + if (searchType == SearchData.Type.DOMAIN) { + results.putAll(DomainSearch.getGroupSizes(System.getProperty(USER_NAME_PROPERTY), filters, + groupingAttr, + groupSortAlgorithm, + fileSort, + Case.getCurrentCase().getSleuthkitCase(), centralRepoDb)); + } else { + results.putAll(FileSearch.getGroupSizes(System.getProperty(USER_NAME_PROPERTY), filters, + groupingAttr, + groupSortAlgorithm, + fileSort, + Case.getCurrentCase().getSleuthkitCase(), centralRepoDb)); + } } catch (DiscoveryException ex) { logger.log(Level.SEVERE, "Error running file search test", ex); cancel(true); From 64110a5c33bb7dabf38e647a0f776c9522cb26d2 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 20 Aug 2020 16:54:03 -0400 Subject: [PATCH 027/130] 6711 fix refactoring errors --- .../sleuthkit/autopsy/discovery/search/ResultFile.java | 2 +- .../sleuthkit/autopsy/discovery/ui/GroupListPanel.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultFile.java b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultFile.java index de879910a5..59bfbf48f2 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultFile.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultFile.java @@ -59,7 +59,7 @@ public class ResultFile extends Result { * * @param abstractFile */ - public ResultFile(BlackboardA abstractFile) { + public ResultFile(AbstractFile abstractFile) { try { //call get uniquePath to cache the path abstractFile.getUniquePath(); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java index b9f47dc26e..6a185b70ab 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java @@ -33,8 +33,8 @@ import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; import org.sleuthkit.autopsy.discovery.search.Group; +import org.sleuthkit.autopsy.discovery.search.ResultsSorter; import org.sleuthkit.autopsy.discovery.search.SearchData.Type; -import org.sleuthkit.autopsy.discovery.search.FileSorter; /** * Panel to display the list of groups which are provided by a search. @@ -47,7 +47,7 @@ final class GroupListPanel extends javax.swing.JPanel { private List searchfilters; private DiscoveryAttributes.AttributeType groupingAttribute; private Group.GroupSortingAlgorithm groupSort; - private FileSorter.SortingMethod fileSortMethod; + private ResultsSorter.SortingMethod resultSortMethod; private GroupKey selectedGroupKey; /** @@ -86,7 +86,7 @@ final class GroupListPanel extends javax.swing.JPanel { searchfilters = searchCompleteEvent.getFilters(); groupingAttribute = searchCompleteEvent.getGroupingAttr(); groupSort = searchCompleteEvent.getGroupSort(); - fileSortMethod = searchCompleteEvent.getFileSort(); + resultSortMethod = searchCompleteEvent.getFileSort(); groupKeyList.setListData(groupMap.keySet().toArray(new GroupKey[groupMap.keySet().size()])); SwingUtilities.invokeLater(() -> { if (groupKeyList.getModel().getSize() > 0) { @@ -175,7 +175,7 @@ final class GroupListPanel extends javax.swing.JPanel { if (selectedGroup.equals(groupKey)) { selectedGroupKey = groupKey; DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.GroupSelectedEvent( - searchfilters, groupingAttribute, groupSort, fileSortMethod, selectedGroupKey, groupMap.get(selectedGroupKey), type)); + searchfilters, groupingAttribute, groupSort, resultSortMethod, selectedGroupKey, groupMap.get(selectedGroupKey), type)); break; } } From 186b975204d4ef0bba22efece7a540533171450a Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 20 Aug 2020 16:55:51 -0400 Subject: [PATCH 028/130] 6711 add missing arguement --- .../src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index 2f629f6443..e76e202eb3 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -568,7 +568,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { logger.log(Level.SEVERE, "Error loading central repository database, no central repository options will be available for Discovery", ex); } } - searchWorker = new SearchWorker(centralRepoDb, filters, groupingAttr, groupSortAlgorithm, fileSort); + searchWorker = new SearchWorker(centralRepoDb, type, filters, groupingAttr, groupSortAlgorithm, fileSort); searchWorker.execute(); dispose(); tc.toFront(); From 04cfb47cd7553eb20d1351eb45fb5b666094c2bb Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 20 Aug 2020 17:01:08 -0400 Subject: [PATCH 029/130] 6711 update comment --- .../org/sleuthkit/autopsy/discovery/search/Result.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/Result.java b/Core/src/org/sleuthkit/autopsy/discovery/search/Result.java index 4f4151eec5..2b196aadcc 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/Result.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/Result.java @@ -33,6 +33,11 @@ public abstract class Result { private SearchData.Frequency frequency; private final List tagNames = new ArrayList<>(); + /** + * Get the Object ID for the data source the result is in. + * + * @return The Object ID of the data source the result is in. + */ public abstract long getDataSourceObjectId(); /** @@ -44,6 +49,11 @@ public abstract class Result { return frequency; } + /** + * Get the known status of the result. + * + * @return The Known status of the result. + */ public abstract TskData.FileKnown getKnown(); /** From 0c8d76bc057f0470d2d6babca05f71b2fd739382 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 21 Aug 2020 12:48:52 -0400 Subject: [PATCH 030/130] 6711 update copyright get github to update --- Core/src/org/sleuthkit/autopsy/discovery/search/Group.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/Group.java b/Core/src/org/sleuthkit/autopsy/discovery/search/Group.java index de96b5750f..8bd72e649a 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/Group.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/Group.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); From 47453a5b899bf20be577dcd8517c729a843d1dbb Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 3 Sep 2020 09:55:02 -0400 Subject: [PATCH 031/130] 6714 fix listener, validation, and enabling of filters --- .../discovery/ui/ArtifactTypeFilterPanel.form | 5 +- .../discovery/ui/ArtifactTypeFilterPanel.java | 29 +++++++-- .../autopsy/discovery/ui/Bundle.properties | 2 +- .../discovery/ui/Bundle.properties-MERGED | 2 +- .../autopsy/discovery/ui/DateFilterPanel.form | 16 +++-- .../autopsy/discovery/ui/DateFilterPanel.java | 59 ++++++++++++++----- .../autopsy/discovery/ui/DiscoveryDialog.java | 10 ++-- 7 files changed, 89 insertions(+), 34 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.form index d269dc7d15..e0d00591cc 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.form @@ -8,6 +8,9 @@ + + +
@@ -49,7 +52,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java index eba7fbe1f1..aca79c056c 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java @@ -47,7 +47,7 @@ class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { */ private void setUpArtifactTypeFilter() { int count = 0; - DefaultListModel artifactTypeModel = (DefaultListModel) jList1.getModel(); + DefaultListModel artifactTypeModel = (DefaultListModel) artifactList.getModel(); artifactTypeModel.removeAllElements(); for (BlackboardArtifact.ARTIFACT_TYPE artifactType : SearchData.Type.DOMAIN.getArtifactTypes()) { artifactTypeModel.add(count, new ArtifactTypeItem(artifactType)); @@ -66,17 +66,22 @@ class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { artifactTypeCheckbox = new javax.swing.JCheckBox(); artifactTypeScrollPane = new javax.swing.JScrollPane(); - jList1 = new javax.swing.JList<>(); + artifactList = new javax.swing.JList<>(); org.openide.awt.Mnemonics.setLocalizedText(artifactTypeCheckbox, org.openide.util.NbBundle.getMessage(ArtifactTypeFilterPanel.class, "ArtifactTypeFilterPanel.artifactTypeCheckbox.text")); // NOI18N + artifactTypeCheckbox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + artifactTypeCheckboxActionPerformed(evt); + } + }); setPreferredSize(new java.awt.Dimension(27, 27)); artifactTypeScrollPane.setPreferredSize(new java.awt.Dimension(27, 27)); - jList1.setModel(new DefaultListModel()); - jList1.setEnabled(false); - artifactTypeScrollPane.setViewportView(jList1); + artifactList.setModel(new DefaultListModel()); + artifactList.setEnabled(false); + artifactTypeScrollPane.setViewportView(artifactList); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -90,9 +95,21 @@ class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { ); }// //GEN-END:initComponents + private void artifactTypeCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_artifactTypeCheckboxActionPerformed + artifactTypeScrollPane.setEnabled(artifactTypeCheckbox.isSelected()); + artifactList.setEnabled(artifactTypeCheckbox.isSelected()); + }//GEN-LAST:event_artifactTypeCheckboxActionPerformed + @Override void configurePanel(boolean selected, int[] indicesSelected) { artifactTypeCheckbox.setSelected(selected); + if (artifactTypeCheckbox.isEnabled() && artifactTypeCheckbox.isSelected()) { + artifactTypeScrollPane.setEnabled(true); + artifactList.setEnabled(true); + } else { + artifactTypeScrollPane.setEnabled(false); + artifactList.setEnabled(false); + } } @Override @@ -153,8 +170,8 @@ class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { } // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JList artifactList; private javax.swing.JCheckBox artifactTypeCheckbox; private javax.swing.JScrollPane artifactTypeScrollPane; - private javax.swing.JList jList1; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties index faa0025da5..6e0553c5ea 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties @@ -39,7 +39,6 @@ SizeFilterPanel.sizeCheckbox.text=File Size: DateFilterPanel.dateFilterCheckbox.text=Date Filter: DateFilterPanel.endCheckBox.text=End: DateFilterPanel.startCheckBox.text=Start: -DateFilterPanel.mostRecentButton.text=Only last: DateFilterPanel.daysLabel.text=days of activity ImageThumbnailPanel.isDeletedLabel.toolTipText= ResultsPanel.pageControlsLabel.text=Pages: @@ -54,3 +53,4 @@ PastOccurrencesFilterPanel.pastOccurrencesCheckbox.text=Past Occurrences: DocumentFilterPanel.documentsFiltersSplitPane.border.title=Step 2: Filter which documents to show ObjectDetectedFilterPanel.text=Object Detected: DetailsPanel.instancesList.border.title=Instances +DateFilterPanel.mostRecentRadioButton.text=Only last: diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED index 1e9224cf9b..1c202fbc4a 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED @@ -93,7 +93,6 @@ SizeFilterPanel.sizeCheckbox.text=File Size: DateFilterPanel.dateFilterCheckbox.text=Date Filter: DateFilterPanel.endCheckBox.text=End: DateFilterPanel.startCheckBox.text=Start: -DateFilterPanel.mostRecentButton.text=Only last: DateFilterPanel.daysLabel.text=days of activity ImageThumbnailPanel.isDeletedLabel.toolTipText= ResultsPanel.pageControlsLabel.text=Pages: @@ -108,6 +107,7 @@ PastOccurrencesFilterPanel.pastOccurrencesCheckbox.text=Past Occurrences: DocumentFilterPanel.documentsFiltersSplitPane.border.title=Step 2: Filter which documents to show ObjectDetectedFilterPanel.text=Object Detected: DetailsPanel.instancesList.border.title=Instances +DateFilterPanel.mostRecentRadioButton.text=Only last: VideoThumbnailPanel.bytes.text=bytes VideoThumbnailPanel.deleted.text=All instances of file are deleted. VideoThumbnailPanel.gigaBytes.text=GB diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form index 6801b3f579..2728d1a822 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form @@ -10,6 +10,9 @@ + + + @@ -51,7 +54,7 @@ - + @@ -76,7 +79,7 @@ - + @@ -104,6 +107,9 @@ + + + @@ -117,18 +123,18 @@ - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java index cf78c5fe7d..ca8b9ca96d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java @@ -60,7 +60,7 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { jPanel1 = new javax.swing.JPanel(); daysSpinner = new javax.swing.JSpinner(numberModel); daysLabel = new javax.swing.JLabel(); - mostRecentButton = new javax.swing.JRadioButton(); + mostRecentRadioButton = new javax.swing.JRadioButton(); startCheckBox = new javax.swing.JCheckBox(); startDatePicker = new com.github.lgooddatepicker.components.DatePicker(); endDatePicker = new com.github.lgooddatepicker.components.DatePicker(); @@ -68,19 +68,25 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { rangeRadioButton = new javax.swing.JRadioButton(); org.openide.awt.Mnemonics.setLocalizedText(dateFilterCheckbox, org.openide.util.NbBundle.getMessage(DateFilterPanel.class, "DateFilterPanel.dateFilterCheckbox.text")); // NOI18N + dateFilterCheckbox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + dateFilterCheckboxActionPerformed(evt); + } + }); daysSpinner.setEnabled(false); daysSpinner.setPreferredSize(new java.awt.Dimension(75, 26)); + daysSpinner.setValue(7); org.openide.awt.Mnemonics.setLocalizedText(daysLabel, org.openide.util.NbBundle.getMessage(DateFilterPanel.class, "DateFilterPanel.daysLabel.text")); // NOI18N daysLabel.setEnabled(false); - buttonGroup1.add(mostRecentButton); - org.openide.awt.Mnemonics.setLocalizedText(mostRecentButton, org.openide.util.NbBundle.getMessage(DateFilterPanel.class, "DateFilterPanel.mostRecentButton.text")); // NOI18N - mostRecentButton.setEnabled(false); - mostRecentButton.addActionListener(new java.awt.event.ActionListener() { + buttonGroup1.add(mostRecentRadioButton); + org.openide.awt.Mnemonics.setLocalizedText(mostRecentRadioButton, org.openide.util.NbBundle.getMessage(DateFilterPanel.class, "DateFilterPanel.mostRecentRadioButton.text")); // NOI18N + mostRecentRadioButton.setEnabled(false); + mostRecentRadioButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - mostRecentButtonActionPerformed(evt); + mostRecentRadioButtonActionPerformed(evt); } }); @@ -121,7 +127,7 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() - .addComponent(mostRecentButton, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(mostRecentRadioButton, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(daysSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) @@ -141,7 +147,7 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(mostRecentButton) + .addComponent(mostRecentRadioButton) .addComponent(daysSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(daysLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) @@ -177,25 +183,48 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { private void startCheckBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_startCheckBoxStateChanged startDatePicker.setEnabled(startCheckBox.isSelected()); -// validateFilters(); //TODO JIRA-6714 when search will begin doing something }//GEN-LAST:event_startCheckBoxStateChanged private void endCheckBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_endCheckBoxStateChanged endDatePicker.setEnabled(endCheckBox.isSelected()); -// validateFilters(); //TODO JIRA-6714 when search will begin doing something }//GEN-LAST:event_endCheckBoxStateChanged - private void mostRecentButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mostRecentButtonActionPerformed - - }//GEN-LAST:event_mostRecentButtonActionPerformed + private void mostRecentRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mostRecentRadioButtonActionPerformed + startCheckBox.setEnabled(false); + endCheckBox.setEnabled(false); + daysSpinner.setEnabled(true); + daysLabel.setEnabled(true); + }//GEN-LAST:event_mostRecentRadioButtonActionPerformed private void rangeRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rangeRadioButtonActionPerformed - // TODO add your handling code here: + startCheckBox.setEnabled(true); + endCheckBox.setEnabled(true); + daysSpinner.setEnabled(false); + daysLabel.setEnabled(false); }//GEN-LAST:event_rangeRadioButtonActionPerformed + private void dateFilterCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dateFilterCheckboxActionPerformed + mostRecentRadioButton.setEnabled(dateFilterCheckbox.isSelected()); + rangeRadioButton.setEnabled(dateFilterCheckbox.isSelected()); + }//GEN-LAST:event_dateFilterCheckboxActionPerformed + @Override void configurePanel(boolean selected, int[] indicesSelected) { dateFilterCheckbox.setSelected(selected); + if (dateFilterCheckbox.isEnabled() && dateFilterCheckbox.isSelected()) { + mostRecentRadioButton.setEnabled(true); + rangeRadioButton.setEnabled(true); + mostRecentRadioButton.setSelected(true); + } else { + mostRecentRadioButton.setEnabled(false); + rangeRadioButton.setEnabled(false); + daysLabel.setEnabled(false); + daysSpinner.setEnabled(false); + startCheckBox.setEnabled(false); + endCheckBox.setEnabled(false); + startDatePicker.setEnabled(false); + endDatePicker.setEnabled(false); + } } @Override @@ -232,7 +261,7 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { private javax.swing.JCheckBox endCheckBox; private com.github.lgooddatepicker.components.DatePicker endDatePicker; private javax.swing.JPanel jPanel1; - private javax.swing.JRadioButton mostRecentButton; + private javax.swing.JRadioButton mostRecentRadioButton; private javax.swing.JRadioButton rangeRadioButton; private javax.swing.JCheckBox startCheckBox; private com.github.lgooddatepicker.components.DatePicker startDatePicker; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index e76e202eb3..94e41c8cf2 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -512,6 +512,10 @@ final class DiscoveryDialog extends javax.swing.JDialog { remove(imageFilterPanel); imageFilterPanel.removePropertyChangeListener(listener); } + if (domainFilterPanel != null) { + remove(domainFilterPanel); + domainFilterPanel.removePropertyChangeListener(listener); + } if (documentFilterPanel != null) { remove(documentFilterPanel); documentFilterPanel.removePropertyChangeListener(listener); @@ -520,10 +524,6 @@ final class DiscoveryDialog extends javax.swing.JDialog { remove(videoFilterPanel); videoFilterPanel.removePropertyChangeListener(listener); } - if (domainFilterPanel != null) { - remove(domainFilterPanel); - domainFilterPanel.removePropertyChangeListener(listener); - } } private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed @@ -584,7 +584,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { domainsButton.setBackground(SELECTED_COLOR); domainsButton.setForeground(Color.BLACK); type = SearchData.Type.DOMAIN; - documentFilterPanel.addPropertyChangeListener(listener); + domainFilterPanel.addPropertyChangeListener(listener); validateDialog(); pack(); repaint(); From 62c97436d1cefe0cc2d2501fcbee72284780341c Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Tue, 8 Sep 2020 10:06:18 -0400 Subject: [PATCH 032/130] Implemented Domain Discovery functionality --- .../discovery/search/DiscoveryAttributes.java | 18 +- .../discovery/search/DiscoveryKeyUtils.java | 60 +++- .../discovery/search/DomainSearch.java | 90 +++--- .../discovery/search/DomainSearchCache.java | 71 +++++ .../search/DomainSearchCacheLoader.java | 280 ++++++++++++++++++ .../discovery/search/ResultDomain.java | 53 +++- .../discovery/search/ResultsSorter.java | 25 +- .../discovery/search/SearchFiltering.java | 76 +++++ 8 files changed, 615 insertions(+), 58 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java create mode 100755 Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java index d214236e83..7b8df83c37 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java @@ -29,11 +29,13 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException; import org.sleuthkit.autopsy.centralrepository.datamodel.InstanceTableCallback; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -248,9 +250,10 @@ public class DiscoveryAttributes { * @param centralRepoDb The central repository currently in use. */ private void processResultFilesForCR(List results, - CentralRepository centralRepoDb) { + CentralRepository centralRepoDb) throws DiscoveryException { List currentFiles = new ArrayList<>(); Set hashesToLookUp = new HashSet<>(); + for (Result result : results) { if (result.getKnown() == TskData.FileKnown.KNOWN) { result.setFrequency(SearchData.Frequency.KNOWN); @@ -263,7 +266,20 @@ public class DiscoveryAttributes { hashesToLookUp.add(file.getFirstInstance().getMd5Hash()); currentFiles.add(file); } + } else { + ResultDomain domain = (ResultDomain) result; + try { + CorrelationAttributeInstance.Type domainAttributeType = + centralRepoDb.getCorrelationTypeById(CorrelationAttributeInstance.DOMAIN_TYPE_ID); + Long count = centralRepoDb.getCountArtifactInstancesByTypeValue(domainAttributeType, domain.getDomain()); + domain.setFrequency(SearchData.Frequency.fromCount(count)); + } catch (CentralRepoException ex) { + throw new DiscoveryException("Error encountered querying the central repository.", ex); + } catch (CorrelationAttributeNormalizationException ex) { + logger.log(Level.INFO, "Domain [%s] could not be normalized for central repository querying, skipping...", domain.getDomain()); + } } + if (hashesToLookUp.size() >= BATCH_SIZE) { computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java index 8f21a89f30..0bcbc20b61 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java @@ -23,9 +23,11 @@ import java.util.List; import java.util.Objects; import java.util.logging.Level; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; /** @@ -41,6 +43,12 @@ public class DiscoveryKeyUtils { static class SearchKey implements Comparable { private final String keyString; + private final Group.GroupSortingAlgorithm groupSortingType; + private final DiscoveryAttributes.AttributeType groupAttributeType; + private final ResultsSorter.SortingMethod fileSortingMethod; + private final List filters; + private final SleuthkitCase sleuthkitCase; + private final CentralRepository centralRepository; /** * Construct a new SearchKey with all information that defines a search. @@ -50,11 +58,19 @@ public class DiscoveryKeyUtils { * @param groupAttributeType The AttributeType to group by. * @param groupSortingType The algorithm to sort the groups by. * @param fileSortingMethod The method to sort the files by. + * @param sleuthkitCase The SleuthkitCase being searched. + * @param centralRepository The Central Repository being searched. */ SearchKey(String userName, List filters, DiscoveryAttributes.AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, - ResultsSorter.SortingMethod fileSortingMethod) { + ResultsSorter.SortingMethod fileSortingMethod, + SleuthkitCase sleuthkitCase, CentralRepository centralRepository) { + this.groupAttributeType = groupAttributeType; + this.groupSortingType = groupSortingType; + this.fileSortingMethod = fileSortingMethod; + this.filters = filters; + StringBuilder searchStringBuilder = new StringBuilder(); searchStringBuilder.append(userName); for (AbstractFilter filter : filters) { @@ -62,6 +78,19 @@ public class DiscoveryKeyUtils { } searchStringBuilder.append(groupAttributeType).append(groupSortingType).append(fileSortingMethod); keyString = searchStringBuilder.toString(); + this.sleuthkitCase = sleuthkitCase; + this.centralRepository = centralRepository; + } + + /** + * Construct a SearchKey without a SleuthkitCase or CentralRepositry instance. + */ + SearchKey(String userName, List filters, + DiscoveryAttributes.AttributeType groupAttributeType, + Group.GroupSortingAlgorithm groupSortingType, + ResultsSorter.SortingMethod fileSortingMethod) { + this(userName, filters, groupAttributeType, groupSortingType, + fileSortingMethod, null, null); } @Override @@ -80,6 +109,11 @@ public class DiscoveryKeyUtils { } SearchKey otherSearchKey = (SearchKey) otherKey; + if (this.sleuthkitCase != otherSearchKey.getSleuthkitCase() || + this.centralRepository != otherSearchKey.getCentralRepository()) { + return false; + } + return getKeyString().equals(otherSearchKey.getKeyString()); } @@ -96,6 +130,30 @@ public class DiscoveryKeyUtils { String getKeyString() { return keyString; } + + List getFilters() { + return Collections.unmodifiableList(this.filters); + } + + Group.GroupSortingAlgorithm getGroupSortingType() { + return groupSortingType; + } + + DiscoveryAttributes.AttributeType getGroupAttributeType() { + return groupAttributeType; + } + + ResultsSorter.SortingMethod getFileSortingMethod() { + return fileSortingMethod; + } + + SleuthkitCase getSleuthkitCase() { + return this.sleuthkitCase; + } + + CentralRepository getCentralRepository() { + return this.centralRepository; + } } /** diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java index dfb0248d86..94ad264155 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java @@ -18,25 +18,30 @@ */ package org.sleuthkit.autopsy.discovery.search; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; +import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; + import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; -import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; import org.sleuthkit.datamodel.SleuthkitCase; /** * Main class to perform the domain search. */ public class DomainSearch { - - private final static Logger logger = Logger.getLogger(DomainSearch.class.getName()); - private static final int MAXIMUM_CACHE_SIZE = 10; - private static final Cache>> searchCache = CacheBuilder.newBuilder() - .maximumSize(MAXIMUM_CACHE_SIZE) - .build(); - + + private final DomainSearchCache searchCache; + + public DomainSearch() { + this(new DomainSearchCache()); + } + + DomainSearch(DomainSearchCache cache) { + this.searchCache = cache; + } + /** * Run the domain search to get the group keys and sizes. Clears cache of * search results, caching new results for access at later time. @@ -55,13 +60,24 @@ public class DomainSearch { * * @throws DiscoveryException */ - public static Map getGroupSizes(String userName, + public Map getGroupSizes(String userName, List filters, DiscoveryAttributes.AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, ResultsSorter.SortingMethod domainSortingMethod, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + + final Map> searchResults = searchCache.get( + userName, filters, groupAttributeType, groupSortingType, + domainSortingMethod, caseDb, centralRepoDb); + + // Transform the cached results into a map of group key to group size. + final LinkedHashMap groupSizes = new LinkedHashMap<>(); + for (GroupKey groupKey : searchResults.keySet()) { + groupSizes.put(groupKey, searchResults.get(groupKey).size()); + } + + return groupSizes; } /** @@ -86,49 +102,25 @@ public class DomainSearch { * * @throws DiscoveryException */ - public static List getDomainsInGroup(String userName, + public List getDomainsInGroup(String userName, List filters, DiscoveryAttributes.AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, ResultsSorter.SortingMethod domainSortingMethod, - DiscoveryKeyUtils.GroupKey groupKey, - int startingEntry, - int numberOfEntries, + GroupKey groupKey, int startingEntry, int numberOfEntries, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } + + final Map> searchResults = searchCache.get( + userName, filters, groupAttributeType, groupSortingType, + domainSortingMethod, caseDb, centralRepoDb); + final List domainsInGroup = searchResults.get(groupKey); - /** - * Run the Domain search. Caching new results for access at later time. - * - * @param userName The name of the user performing the search. - * @param filters The filters to apply - * @param groupAttributeType The attribute to use for grouping - * @param groupSortingType The method to use to sort the groups - * @param domainSortingMethod The method to use to sort the domains within - * the groups - * @param caseDb The case database - * @param centralRepoDb The central repository database. Can be null if - * not needed. - * - * @return A LinkedHashMap grouped and sorted according to the parameters - * - * @throws DiscoveryException - */ - private static Map> runDomainSearch(String userName, - List filters, - DiscoveryAttributes.AttributeType groupAttributeType, - Group.GroupSortingAlgorithm groupSortingType, - ResultsSorter.SortingMethod domainSortingMethod, - SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } + final List page = new ArrayList<>(); + for (int i = startingEntry; (i < startingEntry + numberOfEntries) + && (i < domainsInGroup.size()); i++) { + page.add(domainsInGroup.get(i)); + } - /** - * Private constructor for DomainSearch class. - */ - private DomainSearch() { - // Class should not be instantiated + return page; } - } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java new file mode 100755 index 0000000000..fb29e41078 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java @@ -0,0 +1,71 @@ +/* + * 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.discovery.search; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.LoadingCache; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; +import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.SearchKey; +import org.sleuthkit.datamodel.SleuthkitCase; + +/** + * Caches results for domain searches initiated by the user in the Discovery + * panel. Uses a Guava Cache as a backing data structure. See + * DomainSearchCacheLoader for database querying in the event of a cache miss. + */ +class DomainSearchCache { + + private static final int MAXIMUM_CACHE_SIZE = 10; + private final LoadingCache>> cache; + + DomainSearchCache() { + this(new DomainSearchCacheLoader()); + } + + DomainSearchCache(DomainSearchCacheLoader cacheLoader) { + this.cache = CacheBuilder.newBuilder() + .maximumSize(MAXIMUM_CACHE_SIZE) + .build(cacheLoader); + } + + /** + * Get domain search results matching the given parameters. If no results + * are found, the cache will automatically load them. + */ + Map> get(String userName, + List filters, + DiscoveryAttributes.AttributeType groupAttributeType, + Group.GroupSortingAlgorithm groupSortingType, + ResultsSorter.SortingMethod domainSortingMethod, + SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { + + try { + final SearchKey searchKey = new SearchKey(userName, filters, groupAttributeType, + groupSortingType, domainSortingMethod, caseDb, centralRepoDb); + + return cache.get(searchKey); + } catch (ExecutionException ex) { + throw new DiscoveryException("Error fetching results from cache", ex.getCause()); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java new file mode 100755 index 0000000000..cb0db1c2dc --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java @@ -0,0 +1,280 @@ +/* + * 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.discovery.search; + +import com.google.common.cache.CacheLoader; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.StringJoiner; +import org.apache.commons.lang3.tuple.Pair; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException; +import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes.AttributeType; +import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes.DataSourceAttribute; +import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; +import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.SearchKey; +import org.sleuthkit.autopsy.discovery.search.SearchFiltering.ArtifactDateRangeFilter; +import org.sleuthkit.autopsy.discovery.search.SearchFiltering.ArtifactTypeFilter; +import org.sleuthkit.autopsy.discovery.search.SearchFiltering.DataSourceFilter; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN; +import org.sleuthkit.datamodel.CaseDbAccessManager; +import org.sleuthkit.datamodel.CaseDbAccessManager.CaseDbAccessQueryCallback; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Loads domain search results for cache misses. This loader is a Guava cache loader, + * which will be used in tandem with the DomainSearchCache, which is backed by a + * Guava LoadingCache. + */ +class DomainSearchCacheLoader extends CacheLoader>> { + + @Override + public Map> load(SearchKey key) throws DiscoveryException, SQLException, TskCoreException, + CentralRepoException, CorrelationAttributeNormalizationException { + + List domainResults = getResultDomainsFromDatabase(key); + + // Apply secondary in memory filters + for (AbstractFilter filter : key.getFilters()) { + if (filter.useAlternateFilter()) { + domainResults = filter.applyAlternateFilter(domainResults, key.getSleuthkitCase(), key.getCentralRepository()); + } + } + + // Sort the ResultDomains by the requested criteria. + final SearchResults searchResults = new SearchResults( + key.getGroupSortingType(), + key.getGroupAttributeType(), + key.getFileSortingMethod()); + searchResults.add(domainResults); + return searchResults.toLinkedHashMap(); + } + + /** + * Queries for domain names from the case database. + * + * @param key The SearchKey passed to the cache. + * @return A list of results corresponding to the domains found in the + * case database. + */ + List getResultDomainsFromDatabase(SearchKey key) throws TskCoreException, SQLException, DiscoveryException { + + // Filters chosen in the UI are aggregated into SQL statements to be used in + // the queries that follow. + final Pair filterClauses = createWhereAndHavingClause(key.getFilters()); + final String whereClause = filterClauses.getLeft(); + final String havingClause = filterClauses.getRight(); + + // You may think of each row of this result as a TSK_DOMAIN attribute, where the parent + // artifact type is within the (optional) filter and the parent artifact + // had a date time attribute that was within the (optional) filter. With this + // table in hand, we can simply group by domain and apply aggregate functions + // to get, for example, # of downloads, # of visits in last 60, etc. + final String domainsTable = + "SELECT MAX(value_text) AS domain," + + " MAX(value_int64) AS date," + + " artifact_id AS parent_artifact_id," + + " MAX(artifact_type_id) AS parent_artifact_type_id " + + + "FROM blackboard_attributes " + + "WHERE " + whereClause + " " + + + "GROUP BY artifact_id " + + "HAVING " + havingClause; + + // Needed to populate the visitsInLast60 data. + final Instant currentTime = Instant.now(); + final Instant sixtyDaysAgo = currentTime.minus(60, ChronoUnit.DAYS); + + // Check the group attribute, if by data source then the GROUP BY clause + // should group by data source id before grouping by domain. + final AttributeType groupAttribute = key.getGroupAttributeType(); + final String groupByClause = (groupAttribute instanceof DataSourceAttribute) ? + "data_source_obj_id, domain" : "domain"; + + final Optional dataSourceFilter = key.getFilters().stream() + .filter(filter -> filter instanceof DataSourceFilter) + .findFirst(); + + String dataSourceWhereClause = null; + if (dataSourceFilter.isPresent()) { + dataSourceWhereClause = dataSourceFilter.get().getWhereClause(); + } + + // This query just processes the domains table, performing additional + // groupings and applying aggregate functions to calculate discovery data. + final String domainsQuery = + /*SELECT */" domain," + + " MIN(date) AS activity_start," + + " MAX(date) AS activity_end," + + " SUM(CASE WHEN artifact_type_id = " + TSK_WEB_DOWNLOAD.getTypeID() + " THEN 1 ELSE 0 END) AS fileDownloads," + + " SUM(CASE WHEN artifact_type_id = " + TSK_WEB_HISTORY.getTypeID() + " AND" + + " date BETWEEN " + sixtyDaysAgo.getEpochSecond() + " AND " + currentTime.getEpochSecond() + " THEN 1 ELSE 0 END) AS last60," + + " data_source_obj_id AS dataSource " + + + "FROM blackboard_artifacts" + + " JOIN (" + domainsTable + ") AS domains_table" + + " ON artifact_id = parent_artifact_id " + + + // Add the data source where clause here if present. + ((dataSourceWhereClause != null) ? "WHERE " + dataSourceWhereClause + " " : "") + + + "GROUP BY " + groupByClause; + + final SleuthkitCase caseDb = key.getSleuthkitCase(); + final CaseDbAccessManager dbManager = caseDb.getCaseDbAccessManager(); + + final DomainCallback domainCallback = new DomainCallback(caseDb); + dbManager.select(domainsQuery, domainCallback); + + if (domainCallback.getSQLException() != null) { + throw domainCallback.getSQLException(); + } + + if (domainCallback.getTskCoreException() != null) { + throw domainCallback.getTskCoreException(); + } + + return domainCallback.getResultDomains(); + } + + /** + * A utility method to transform filters into the necessary SQL statements + * for the domainsTable query. The complexity of that query requires this + * transformation process to be conditional. The date time filter is a good + * example of the type of conditional handling that follows in the method + * below. If no dateTime filter is supplied, then in order for the query to + * be correct, an special clause needs to be added in. + * + * @return The whereClause and havingClause as a pair. These methods were + * combined into one in order to stress that these clauses are tightly + * coupled. + */ + Pair createWhereAndHavingClause(List filters) { + final StringJoiner whereClause = new StringJoiner(" OR "); + final StringJoiner havingClause = new StringJoiner(" AND "); + + String artifactTypeFilter = null; + boolean hasDateTimeFilter = false; + + for (AbstractFilter filter : filters) { + if (filter instanceof ArtifactTypeFilter) { + artifactTypeFilter = filter.getWhereClause(); + } else if (!(filter instanceof DataSourceFilter) && !filter.useAlternateFilter()) { + if (filter instanceof ArtifactDateRangeFilter) { + hasDateTimeFilter = true; + } + + whereClause.add("(" + filter.getWhereClause() + ")"); + havingClause.add("SUM(CASE WHEN " + filter.getWhereClause() + " THEN 1 ELSE 0 END) > 0"); + } + } + + if (!hasDateTimeFilter) { + whereClause.add(ArtifactDateRangeFilter.createAttributeTypeClause()); + } + + String domainAttributeFilter = "attribute_type_id = " + TSK_DOMAIN.getTypeID() + + " AND value_text <> ''"; + + whereClause.add("(" + domainAttributeFilter + ")"); + havingClause.add("SUM(CASE WHEN " + domainAttributeFilter + " THEN 1 ELSE 0 END) > 0"); + + return Pair.of( + whereClause.toString() + ((artifactTypeFilter != null) ? " AND (" + artifactTypeFilter + ")" : ""), + havingClause.toString() + ); + } + + /** + * Callback to handle the result set of the domain query. This callback + * is responsible for mapping result set rows into ResultDomain objects + * for display. + */ + private class DomainCallback implements CaseDbAccessQueryCallback { + + private final List resultDomains; + private final SleuthkitCase skc; + private SQLException sqlCause; + private TskCoreException coreCause; + + public DomainCallback(SleuthkitCase skc) { + this.resultDomains = new ArrayList<>(); + this.skc = skc; + } + + @Override + public void process(ResultSet resultSet) { + try { + while (resultSet.next()) { + String domain = resultSet.getString("domain"); + Long activityStart = resultSet.getLong("activity_start"); + if (resultSet.wasNull()) { + activityStart = null; + } + Long activityEnd = resultSet.getLong("activity_end"); + if (resultSet.wasNull()) { + activityEnd = null; + } + Long filesDownloaded = resultSet.getLong("fileDownloads"); + if (resultSet.wasNull()) { + filesDownloaded = null; + } + Long visitsInLast60 = resultSet.getLong("last60"); + if (resultSet.wasNull()) { + visitsInLast60 = null; + } + Long dataSourceID = resultSet.getLong("dataSource"); + + Content dataSource = skc.getContentById(dataSourceID); + + resultDomains.add(new ResultDomain(domain, activityStart, + activityEnd, visitsInLast60, filesDownloaded, dataSource)); + } + } catch (SQLException ex) { + this.sqlCause = ex; + } catch (TskCoreException ex) { + this.coreCause = ex; + } + } + + private List getResultDomains() { + return Collections.unmodifiableList(this.resultDomains); + } + + public SQLException getSQLException() { + return this.sqlCause; + } + + public TskCoreException getTskCoreException() { + return this.coreCause; + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultDomain.java b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultDomain.java index f132a3f9cc..a47e026beb 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultDomain.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultDomain.java @@ -26,25 +26,61 @@ import org.sleuthkit.datamodel.TskData; * Container for domains that holds all necessary data for grouping and sorting. */ public class ResultDomain extends Result { - private String domain; + private final String domain; + private final Long activityStart; + private final Long activityEnd; + private final Long visitsInLast60; + private final Long filesDownloaded; + + private final Content dataSource; + private final long dataSourceId; + /** * Create a ResultDomain from a String. * * @param domain The domain the result is being created from. */ - ResultDomain(String domain) { + ResultDomain(String domain, Long activityStart, Long activityEnd, + Long visitsInLast60, Long filesDownloaded, Content dataSource) { this.domain = domain; + this.dataSource = dataSource; + this.dataSourceId = dataSource.getId(); + this.activityStart = activityStart; + this.activityEnd = activityEnd; + this.visitsInLast60 = visitsInLast60; + this.filesDownloaded = filesDownloaded; + this.setFrequency(SearchData.Frequency.UNKNOWN); } + + public String getDomain() { + return this.domain; + } + + public Long getActivityStart() { + return activityStart; + } + + public Long getActivityEnd() { + return activityEnd; + } + + public Long getVisitsInLast60() { + return visitsInLast60; + } + + public Long getFilesDownloaded() { + return filesDownloaded; + } @Override public long getDataSourceObjectId() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return this.dataSourceId; } @Override public Content getDataSource() throws TskCoreException { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return this.dataSource; } @Override @@ -56,5 +92,12 @@ public class ResultDomain extends Result { public SearchData.Type getType() { return SearchData.Type.DOMAIN; } - + + @Override + public String toString() { + return "[" + this.domain + ", " + this.dataSourceId + ", " + + this.activityStart + ", " + this.activityEnd + ", " + + this.visitsInLast60 + ", " + this.filesDownloaded + ", " + + this.getFrequency() + "]"; + } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultsSorter.java b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultsSorter.java index 45a411d8af..27f0fcb202 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultsSorter.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultsSorter.java @@ -66,6 +66,9 @@ public class ResultsSorter implements Comparator { case BY_FILE_NAME: comparators.add(getFileNameComparator()); break; + case BY_DOMAIN_NAME: + comparators.add(getDomainNameComparator()); + break; default: // The default comparator will be added afterward break; @@ -226,6 +229,21 @@ public class ResultsSorter implements Comparator { return compareStrings(((ResultFile) result1).getFirstInstance().getName().toLowerCase(), (((ResultFile) result2).getFirstInstance().getName().toLowerCase())); }; } + + /** + * Sorts domain names in lexographical order, ignoring case. + */ + private static Comparator getDomainNameComparator() { + return (Result domain1, Result domain2) -> { + if(domain1.getType() != SearchData.Type.DOMAIN) { + return 0; + } + + ResultDomain first = (ResultDomain) domain1; + ResultDomain second = (ResultDomain) domain2; + return compareStrings(first.getDomain().toLowerCase(), second.getDomain().toLowerCase()); + }; + } /** * A final default comparison between two ResultFile objects. Currently this @@ -278,7 +296,8 @@ public class ResultsSorter implements Comparator { "FileSorter.SortingMethod.filetype.displayName=File Type", "FileSorter.SortingMethod.frequency.displayName=Central Repo Frequency", "FileSorter.SortingMethod.keywordlist.displayName=Keyword List Names", - "FileSorter.SortingMethod.fullPath.displayName=Full Path"}) + "FileSorter.SortingMethod.fullPath.displayName=Full Path", + "FileSorter.SortingMethod.domain.displayName=Domain"}) public enum SortingMethod { BY_FILE_NAME(new ArrayList<>(), Bundle.FileSorter_SortingMethod_filename_displayName()), // Sort alphabetically by file name @@ -293,7 +312,9 @@ public class ResultsSorter implements Comparator { BY_KEYWORD_LIST_NAMES(Arrays.asList(new DiscoveryAttributes.KeywordListAttribute()), Bundle.FileSorter_SortingMethod_keywordlist_displayName()), // Sort alphabetically by list of keyword list names found BY_FULL_PATH(new ArrayList<>(), - Bundle.FileSorter_SortingMethod_fullPath_displayName()); // Sort alphabetically by path + Bundle.FileSorter_SortingMethod_fullPath_displayName()), // Sort alphabetically by path + BY_DOMAIN_NAME(new ArrayList<>(), + Bundle.FileSorter_SortingMethod_domain_displayName()); private final String displayName; private final List requiredAttributes; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java index 80def7276d..09e9c852cc 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java @@ -31,13 +31,16 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.StringJoiner; import java.util.stream.Collectors; import org.openide.util.NbBundle; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; /** * Run various filters to return a subset of files from the current case. @@ -121,6 +124,79 @@ public class SearchFiltering { } return resultList; } + + /** + * A filter to specify date range for artifacts. + */ + public static class ArtifactDateRangeFilter extends AbstractFilter { + + private final Long startDate; + private final Long endDate; + + // Attributes to search for date + private static List dateAttributes = + Arrays.asList( + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED, + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED + ); + + public ArtifactDateRangeFilter(Long startDate, Long endDate) { + this.startDate = startDate; + this.endDate = endDate; + } + + /** + * Create a SQL clause containing the date time attribute types + * to search. + */ + static String createAttributeTypeClause() { + StringJoiner joiner = new StringJoiner(","); + for(BlackboardAttribute.ATTRIBUTE_TYPE type : dateAttributes) { + joiner.add("\'" + type.getTypeID() + "\'"); + } + return "attribute_type_id IN (" + joiner.toString() + ")"; + } + + @Override + public String getWhereClause() { + return createAttributeTypeClause() + + " AND (value_int64 BETWEEN " + startDate + " AND " + endDate + ")"; + } + + @Override + public String getDesc() { + return "ArtifactDateRangeFilter Stub"; + } + } + + /** + * A filter to specify artifact types + */ + public static class ArtifactTypeFilter extends AbstractFilter { + + private final List types; + + public ArtifactTypeFilter(List types) { + this.types = types; + } + + @Override + public String getWhereClause() { + StringJoiner joiner = new StringJoiner(","); + for(ARTIFACT_TYPE type : types) { + joiner.add("\'" + type.getTypeID() + "\'"); + } + + return "artifact_type_id IN (" + joiner + ")"; + } + + @Override + public String getDesc() { + return "ArtifactTypeFilter Stub"; + } + + } /** * A filter for specifying the file size From bcce8133d94dfaedfd562962dd2578ee08e097bf Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Tue, 8 Sep 2020 10:18:46 -0400 Subject: [PATCH 033/130] Clean up from diff review, added in PageWorker and SearchWorker changes --- .../discovery/search/DiscoveryAttributes.java | 1 - .../search/DomainSearchCacheLoader.java | 26 ++++++++++--------- .../discovery/search/SearchFiltering.java | 3 ++- .../autopsy/discovery/ui/PageWorker.java | 3 ++- .../autopsy/discovery/ui/SearchWorker.java | 3 ++- 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java index 7b8df83c37..178530e072 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java @@ -29,7 +29,6 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java index cb0db1c2dc..59c47429c4 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java @@ -30,8 +30,6 @@ import java.util.Map; import java.util.Optional; import java.util.StringJoiner; import org.apache.commons.lang3.tuple.Pair; -import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; -import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException; import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes.AttributeType; import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes.DataSourceAttribute; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; @@ -56,8 +54,7 @@ import org.sleuthkit.datamodel.TskCoreException; class DomainSearchCacheLoader extends CacheLoader>> { @Override - public Map> load(SearchKey key) throws DiscoveryException, SQLException, TskCoreException, - CentralRepoException, CorrelationAttributeNormalizationException { + public Map> load(SearchKey key) throws DiscoveryException, SQLException, TskCoreException { List domainResults = getResultDomainsFromDatabase(key); @@ -134,9 +131,15 @@ class DomainSearchCacheLoader extends CacheLoader createWhereAndHavingClause(List filters) { final StringJoiner whereClause = new StringJoiner(" OR "); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java index 09e9c852cc..82ed314d6d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java @@ -126,7 +126,8 @@ public class SearchFiltering { } /** - * A filter to specify date range for artifacts. + * A filter to specify date range for artifacts, start and end times should + * be in epoch seconds. */ public static class ArtifactDateRangeFilter extends AbstractFilter { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java index 54ed286f9e..491e618683 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java @@ -91,7 +91,8 @@ final class PageWorker extends SwingWorker { try { // Run the search if (resultType == SearchData.Type.DOMAIN) { - results.addAll(DomainSearch.getDomainsInGroup(System.getProperty(USER_NAME_PROPERTY), searchfilters, + DomainSearch domainSearch = new DomainSearch(); + results.addAll(domainSearch.getDomainsInGroup(System.getProperty(USER_NAME_PROPERTY), searchfilters, groupingAttribute, groupSort, fileSortMethod, groupKey, startingEntry, pageSize, diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java index a2e35c7a29..7c6863ce62 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java @@ -76,7 +76,8 @@ final class SearchWorker extends SwingWorker { try { // Run the search if (searchType == SearchData.Type.DOMAIN) { - results.putAll(DomainSearch.getGroupSizes(System.getProperty(USER_NAME_PROPERTY), filters, + DomainSearch domainSearch = new DomainSearch(); + results.putAll(domainSearch.getGroupSizes(System.getProperty(USER_NAME_PROPERTY), filters, groupingAttr, groupSortAlgorithm, fileSort, From 93691e3979572a252e1cdd6860af2e921ee0ba3a Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 9 Sep 2020 06:54:41 -0400 Subject: [PATCH 034/130] 6714 fix more bugs with UI use --- .../discovery/ui/ArtifactTypeFilterPanel.java | 10 ++- .../autopsy/discovery/ui/Bundle.properties | 2 +- .../autopsy/discovery/ui/DateFilterPanel.form | 8 ++- .../autopsy/discovery/ui/DateFilterPanel.java | 72 ++++++++++--------- 4 files changed, 54 insertions(+), 38 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java index aca79c056c..4d80b68e2b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java @@ -106,6 +106,9 @@ class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { if (artifactTypeCheckbox.isEnabled() && artifactTypeCheckbox.isSelected()) { artifactTypeScrollPane.setEnabled(true); artifactList.setEnabled(true); + if (indicesSelected != null) { + artifactList.setSelectedIndices(indicesSelected); + } } else { artifactTypeScrollPane.setEnabled(false); artifactList.setEnabled(false); @@ -119,7 +122,7 @@ class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { @Override JList getList() { - return null; + return artifactList; } @Override @@ -129,7 +132,10 @@ class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { @Override String checkForError() { - return "Domain search is not implemented."; + if (artifactTypeCheckbox.isSelected() && artifactList.getSelectedValuesList().isEmpty()) { + return "At least one Result type must be selected."; + } + return ""; } @Override diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties index 6e0553c5ea..90bf2dd504 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties @@ -29,7 +29,7 @@ ResultsSplitPaneDivider.showButton.text= ResultsSplitPaneDivider.hideButton.text= ImageFilterPanel.imageFiltersSplitPane.toolTipText= ImageFilterPanel.imageFiltersSplitPane.border.title=Step 2: Filter which images to show -ArtifactTypeFilterPanel.artifactTypeCheckbox.text=Artifact Type: +ArtifactTypeFilterPanel.artifactTypeCheckbox.text=Result Type: InterestingItemsFilterPanel.interestingItemsCheckbox.text=Interesting Item: DocumentPanel.fileSizeLabel.toolTipText= DocumentPanel.isDeletedLabel.toolTipText= diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form index 2728d1a822..1d5d166863 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form @@ -103,6 +103,9 @@ + + + @@ -128,13 +131,14 @@ + - + @@ -189,7 +193,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java index ca8b9ca96d..d19535fc85 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java @@ -17,7 +17,6 @@ * limitations under the License. */ package org.sleuthkit.autopsy.discovery.ui; - import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import javax.swing.JCheckBox; import javax.swing.JLabel; @@ -74,6 +73,7 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { } }); + daysSpinner.setModel(new javax.swing.SpinnerNumberModel(1, 1, null, 1)); daysSpinner.setEnabled(false); daysSpinner.setPreferredSize(new java.awt.Dimension(75, 26)); daysSpinner.setValue(7); @@ -82,11 +82,12 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { daysLabel.setEnabled(false); buttonGroup1.add(mostRecentRadioButton); + mostRecentRadioButton.setSelected(true); org.openide.awt.Mnemonics.setLocalizedText(mostRecentRadioButton, org.openide.util.NbBundle.getMessage(DateFilterPanel.class, "DateFilterPanel.mostRecentRadioButton.text")); // NOI18N mostRecentRadioButton.setEnabled(false); - mostRecentRadioButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - mostRecentRadioButtonActionPerformed(evt); + mostRecentRadioButton.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + mostRecentRadioButtonStateChanged(evt); } }); @@ -116,9 +117,9 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { buttonGroup1.add(rangeRadioButton); rangeRadioButton.setEnabled(false); - rangeRadioButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - rangeRadioButtonActionPerformed(evt); + rangeRadioButton.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + rangeRadioButtonStateChanged(evt); } }); @@ -182,32 +183,32 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { }// //GEN-END:initComponents private void startCheckBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_startCheckBoxStateChanged - startDatePicker.setEnabled(startCheckBox.isSelected()); + startDatePicker.setEnabled(startCheckBox.isEnabled() && startCheckBox.isSelected()); }//GEN-LAST:event_startCheckBoxStateChanged private void endCheckBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_endCheckBoxStateChanged - endDatePicker.setEnabled(endCheckBox.isSelected()); + endDatePicker.setEnabled(endCheckBox.isEnabled() && endCheckBox.isSelected()); }//GEN-LAST:event_endCheckBoxStateChanged - private void mostRecentRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mostRecentRadioButtonActionPerformed - startCheckBox.setEnabled(false); - endCheckBox.setEnabled(false); - daysSpinner.setEnabled(true); - daysLabel.setEnabled(true); - }//GEN-LAST:event_mostRecentRadioButtonActionPerformed - - private void rangeRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rangeRadioButtonActionPerformed - startCheckBox.setEnabled(true); - endCheckBox.setEnabled(true); - daysSpinner.setEnabled(false); - daysLabel.setEnabled(false); - }//GEN-LAST:event_rangeRadioButtonActionPerformed - private void dateFilterCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dateFilterCheckboxActionPerformed - mostRecentRadioButton.setEnabled(dateFilterCheckbox.isSelected()); rangeRadioButton.setEnabled(dateFilterCheckbox.isSelected()); + mostRecentRadioButton.setEnabled(dateFilterCheckbox.isSelected()); + rangeRadioButton.firePropertyChange("DateFilterChange", true, false); + mostRecentRadioButton.firePropertyChange("DateFilterChange", true, false); }//GEN-LAST:event_dateFilterCheckboxActionPerformed + private void mostRecentRadioButtonStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_mostRecentRadioButtonStateChanged + daysSpinner.setEnabled(mostRecentRadioButton.isSelected()); + daysLabel.setEnabled(mostRecentRadioButton.isSelected()); + }//GEN-LAST:event_mostRecentRadioButtonStateChanged + + private void rangeRadioButtonStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_rangeRadioButtonStateChanged + startCheckBox.setEnabled(rangeRadioButton.isEnabled() && rangeRadioButton.isSelected()); + endCheckBox.setEnabled(rangeRadioButton.isEnabled() &&rangeRadioButton.isSelected()); + endCheckBoxStateChanged(evt); + startCheckBoxStateChanged(evt); + }//GEN-LAST:event_rangeRadioButtonStateChanged + @Override void configurePanel(boolean selected, int[] indicesSelected) { dateFilterCheckbox.setSelected(selected); @@ -218,12 +219,6 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { } else { mostRecentRadioButton.setEnabled(false); rangeRadioButton.setEnabled(false); - daysLabel.setEnabled(false); - daysSpinner.setEnabled(false); - startCheckBox.setEnabled(false); - endCheckBox.setEnabled(false); - startDatePicker.setEnabled(false); - endDatePicker.setEnabled(false); } } @@ -244,15 +239,26 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { @Override String checkForError() { - return "Domain search is not implemented."; + if (dateFilterCheckbox.isSelected()) { + if (!(rangeRadioButton.isSelected() || mostRecentRadioButton.isSelected())) { + return "Range or Only Last must be selected"; + } else if (rangeRadioButton.isSelected()) { + if (!startCheckBox.isSelected() && !endCheckBox.isSelected()) { + return "A start or end date must be specified to use the range filter"; + } else if (startCheckBox.isSelected() && startDatePicker.getDate() == null) { + return "A start date must be specified to use the start date option of the range filter"; + } else if (endCheckBox.isSelected() && endDatePicker.getDate() == null) { + return "An end date must be specified to use the end date option of the range filter"; + } + } + } + return ""; } @Override AbstractFilter getFilter() { return null; } - - // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup buttonGroup1; private javax.swing.JCheckBox dateFilterCheckbox; From 144878b4c46d85c58809437ddbe36350bc410539 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 9 Sep 2020 08:06:43 -0400 Subject: [PATCH 035/130] 6714 return daterangefilter for UI use --- .../discovery/search/Bundle.properties-MERGED | 1 + .../discovery/ui/AbstractFiltersPanel.java | 7 +---- .../discovery/ui/Bundle.properties-MERGED | 2 +- .../autopsy/discovery/ui/DateFilterPanel.java | 27 ++++++++++++++++++- 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED index fbb3240018..b31ec5db26 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED @@ -34,6 +34,7 @@ FileSearchFiltering.TagsFilter.desc=Tagged {0} FileSearchFiltering.TagsFilter.or=, FileSearchFiltering.UserCreatedFilter.desc=that contain EXIF data FileSorter.SortingMethod.datasource.displayName=Data Source +FileSorter.SortingMethod.domain.displayName=Domain FileSorter.SortingMethod.filename.displayName=File Name FileSorter.SortingMethod.filesize.displayName=File Size FileSorter.SortingMethod.filetype.displayName=File Type diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java index 4b4673475c..87dfe5d431 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java @@ -248,12 +248,7 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li synchronized List getFilters() { List filtersToUse = new ArrayList<>(); - if (getType().equals(SearchData.Type.DOMAIN)) { - - } else { - filtersToUse.add(new SearchFiltering.FileTypeFilter(getType())); - } - + filtersToUse.add(new SearchFiltering.FileTypeFilter(getType())); for (AbstractDiscoveryFilterPanel filterPanel : filters) { if (filterPanel.getCheckbox().isSelected()) { AbstractFilter filter = filterPanel.getFilter(); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED index 1c202fbc4a..8f9b2055cd 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED @@ -83,7 +83,7 @@ ResultsSplitPaneDivider.showButton.text= ResultsSplitPaneDivider.hideButton.text= ImageFilterPanel.imageFiltersSplitPane.toolTipText= ImageFilterPanel.imageFiltersSplitPane.border.title=Step 2: Filter which images to show -ArtifactTypeFilterPanel.artifactTypeCheckbox.text=Artifact Type: +ArtifactTypeFilterPanel.artifactTypeCheckbox.text=Result Type: InterestingItemsFilterPanel.interestingItemsCheckbox.text=Interesting Item: DocumentPanel.fileSizeLabel.toolTipText= DocumentPanel.isDeletedLabel.toolTipText= diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java index d19535fc85..d7a94a30c7 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java @@ -17,6 +17,11 @@ * limitations under the License. */ package org.sleuthkit.autopsy.discovery.ui; + +import java.time.Duration; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.temporal.TemporalUnit; import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import javax.swing.JCheckBox; import javax.swing.JLabel; @@ -24,6 +29,7 @@ import javax.swing.JList; import javax.swing.SpinnerNumberModel; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.communications.Utils; +import org.sleuthkit.autopsy.discovery.search.SearchFiltering; /** * Filter panel for allowing the user to filter on date. @@ -32,6 +38,7 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { private static final long serialVersionUID = 1L; private final SpinnerNumberModel numberModel; + private static final long SECS_PER_DAY = 86400; /** * Creates new form DateFilterPanel. @@ -204,7 +211,7 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { private void rangeRadioButtonStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_rangeRadioButtonStateChanged startCheckBox.setEnabled(rangeRadioButton.isEnabled() && rangeRadioButton.isSelected()); - endCheckBox.setEnabled(rangeRadioButton.isEnabled() &&rangeRadioButton.isSelected()); + endCheckBox.setEnabled(rangeRadioButton.isEnabled() && rangeRadioButton.isSelected()); endCheckBoxStateChanged(evt); startCheckBoxStateChanged(evt); }//GEN-LAST:event_rangeRadioButtonStateChanged @@ -257,6 +264,24 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { @Override AbstractFilter getFilter() { + + if (dateFilterCheckbox.isSelected()) { + LocalDate startDate = LocalDate.MIN; + LocalDate endDate = LocalDate.MAX; + ZoneId zone = Utils.getUserPreferredZoneId(); + if (rangeRadioButton.isSelected()) { + if (startCheckBox.isSelected() && startDatePicker.getDate() != null) { + startDate = startDatePicker.getDate(); + } + if (endCheckBox.isSelected() && endDatePicker.getDate() != null) { + endDate = endDatePicker.getDate(); + } + } else if (dateFilterCheckbox.isSelected() && mostRecentRadioButton.isSelected()) { + endDate = LocalDate.now(); + startDate = LocalDate.now().minus(Duration.ofDays((long)daysSpinner.getValue())); + } + return new SearchFiltering.ArtifactDateRangeFilter(startDate.atStartOfDay(zone).toEpochSecond(), endDate.atStartOfDay(zone).toEpochSecond() + SECS_PER_DAY);//to insure end date is inclusive + } return null; } // Variables declaration - do not modify//GEN-BEGIN:variables From d8f0c4cc72768fb4d424359a7105bccc66f55539 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 9 Sep 2020 08:14:25 -0400 Subject: [PATCH 036/130] 6714 return artifactType filter for UI --- .../discovery/ui/ArtifactTypeFilterPanel.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java index 4d80b68e2b..00f3eff06d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java @@ -18,12 +18,15 @@ */ package org.sleuthkit.autopsy.discovery.ui; +import java.util.ArrayList; +import java.util.List; import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; import org.sleuthkit.autopsy.discovery.search.SearchData; +import org.sleuthkit.autopsy.discovery.search.SearchFiltering.ArtifactTypeFilter; import org.sleuthkit.datamodel.BlackboardArtifact; /** @@ -106,7 +109,7 @@ class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { if (artifactTypeCheckbox.isEnabled() && artifactTypeCheckbox.isSelected()) { artifactTypeScrollPane.setEnabled(true); artifactList.setEnabled(true); - if (indicesSelected != null) { + if (indicesSelected != null) { artifactList.setSelectedIndices(indicesSelected); } } else { @@ -133,13 +136,20 @@ class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { @Override String checkForError() { if (artifactTypeCheckbox.isSelected() && artifactList.getSelectedValuesList().isEmpty()) { - return "At least one Result type must be selected."; + return "At least one Result type must be selected."; } return ""; } @Override AbstractFilter getFilter() { + if (artifactTypeCheckbox.isSelected() && !artifactList.getSelectedValuesList().isEmpty()) { + List artifactTypeList = new ArrayList<>(); + for (ArtifactTypeItem item : artifactList.getSelectedValuesList()) { + artifactTypeList.add(item.getArtifactType()); + } + return new ArtifactTypeFilter(artifactTypeList); + } return null; } From f8a9ad319c489276e69dbb29460e95ee33992b73 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 10 Sep 2020 10:39:34 -0400 Subject: [PATCH 037/130] 6714 new date grouping attributes --- .../discovery/search/Bundle.properties-MERGED | 12 +- .../discovery/search/DiscoveryAttributes.java | 32 ++- .../discovery/search/DiscoveryKeyUtils.java | 207 ++++++++++++++++-- .../discovery/search/DomainSearchCache.java | 2 +- .../search/DomainSearchCacheLoader.java | 1 + .../discovery/search/SearchResults.java | 3 +- .../discovery/ui/AbstractFiltersPanel.java | 4 +- .../autopsy/discovery/ui/GroupListPanel.java | 2 + 8 files changed, 231 insertions(+), 32 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED index b31ec5db26..102aaf6890 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED @@ -1,9 +1,11 @@ DiscoveryAttributes.GroupingAttributeType.datasource.displayName=Data Source DiscoveryAttributes.GroupingAttributeType.fileType.displayName=File Type +DiscoveryAttributes.GroupingAttributeType.firstDate.displayName=First Activity Date DiscoveryAttributes.GroupingAttributeType.frequency.displayName=Past Occurrences DiscoveryAttributes.GroupingAttributeType.hash.displayName=Hash Set DiscoveryAttributes.GroupingAttributeType.interestingItem.displayName=Interesting Item DiscoveryAttributes.GroupingAttributeType.keywordList.displayName=Keyword +DiscoveryAttributes.GroupingAttributeType.mostRecentDate.displayName=Most Recent Activity Date DiscoveryAttributes.GroupingAttributeType.none.displayName=None DiscoveryAttributes.GroupingAttributeType.object.displayName=Object Detected DiscoveryAttributes.GroupingAttributeType.parent.displayName=Parent Folder @@ -15,15 +17,17 @@ DiscoveryKeyUtils.DataSourceGroupKey.datasourceAndID={0}(ID: {1}) # {0} - Data source ID DiscoveryKeyUtils.DataSourceGroupKey.idOnly=Data source (ID: {0}) DiscoveryKeyUtils.FileTagGroupKey.noSets=None +DiscoveryKeyUtils.FirstActivityDateGroupKey.noDate=No Date Available +DiscoveryKeyUtils.HashHitsGroupKey.noHashHits=None +DiscoveryKeyUtils.InterestingItemGroupKey.noSets=None +DiscoveryKeyUtils.KeywordListGroupKey.noKeywords=None +DiscoveryKeyUtils.MostRecentActivityDateGroupKey.noDate=No Date Available DiscoveryKeyUtils.NoGroupingGroupKey.allFiles=All Files +DiscoveryKeyUtils.ObjectDetectedGroupKey.noSets=None FileGroup.groupSortingAlgorithm.groupName.text=Group Name FileGroup.groupSortingAlgorithm.groupSize.text=Group Size FileSearch.documentSummary.noBytes=No bytes read for document, unable to display preview. FileSearch.documentSummary.noPreview=No preview available. -FileSearch.HashHitsGroupKey.noHashHits=None -FileSearch.InterestingItemGroupKey.noSets=None -FileSearch.KeywordListGroupKey.noKeywords=None -FileSearch.ObjectDetectedGroupKey.noSets=None FileSearchFiltering.concatenateSetNamesForDisplay.comma=, # {0} - filters FileSearchFiltering.HashSetFilter.desc=Hash set hits in set(s): {0} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java index 178530e072..751b47e849 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java @@ -252,7 +252,7 @@ public class DiscoveryAttributes { CentralRepository centralRepoDb) throws DiscoveryException { List currentFiles = new ArrayList<>(); Set hashesToLookUp = new HashSet<>(); - + for (Result result : results) { if (result.getKnown() == TskData.FileKnown.KNOWN) { result.setFrequency(SearchData.Frequency.KNOWN); @@ -268,8 +268,8 @@ public class DiscoveryAttributes { } else { ResultDomain domain = (ResultDomain) result; try { - CorrelationAttributeInstance.Type domainAttributeType = - centralRepoDb.getCorrelationTypeById(CorrelationAttributeInstance.DOMAIN_TYPE_ID); + CorrelationAttributeInstance.Type domainAttributeType + = centralRepoDb.getCorrelationTypeById(CorrelationAttributeInstance.DOMAIN_TYPE_ID); Long count = centralRepoDb.getCountArtifactInstancesByTypeValue(domainAttributeType, domain.getDomain()); domain.setFrequency(SearchData.Frequency.fromCount(count)); } catch (CentralRepoException ex) { @@ -278,7 +278,7 @@ public class DiscoveryAttributes { logger.log(Level.INFO, "Domain [%s] could not be normalized for central repository querying, skipping...", domain.getDomain()); } } - + if (hashesToLookUp.size() >= BATCH_SIZE) { computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); @@ -483,6 +483,24 @@ public class DiscoveryAttributes { } } + static class MostRecentActivityDateAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(Result result) { + return new DiscoveryKeyUtils.MostRecentActivityDateGroupKey(result); + } + + } + + static class FirstActivityDateAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(Result result) { + return new DiscoveryKeyUtils.FirstActivityDateGroupKey(result); + } + + } + /** * Attribute for grouping/sorting by objects detected */ @@ -605,6 +623,8 @@ public class DiscoveryAttributes { "DiscoveryAttributes.GroupingAttributeType.interestingItem.displayName=Interesting Item", "DiscoveryAttributes.GroupingAttributeType.tag.displayName=Tag", "DiscoveryAttributes.GroupingAttributeType.object.displayName=Object Detected", + "DiscoveryAttributes.GroupingAttributeType.mostRecentDate.displayName=Most Recent Activity Date", + "DiscoveryAttributes.GroupingAttributeType.firstDate.displayName=First Activity Date", "DiscoveryAttributes.GroupingAttributeType.none.displayName=None"}) public enum GroupingAttributeType { FILE_SIZE(new FileSizeAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_size_displayName()), @@ -616,6 +636,8 @@ public class DiscoveryAttributes { INTERESTING_ITEM_SET(new InterestingItemAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_interestingItem_displayName()), FILE_TAG(new FileTagAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_tag_displayName()), OBJECT_DETECTED(new ObjectDetectedAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_object_displayName()), + MOST_RECENT_DATE(new MostRecentActivityDateAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_mostRecentDate_displayName()), + FIRST_DATE(new MostRecentActivityDateAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_firstDate_displayName()), NO_GROUPING(new NoGroupingAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_none_displayName()); private final AttributeType attributeType; @@ -641,7 +663,7 @@ public class DiscoveryAttributes { * @return enums that can be used to group images */ public static List getOptionsForGrouping() { - return Arrays.asList(FILE_SIZE, FREQUENCY, PARENT_PATH, OBJECT_DETECTED, HASH_LIST_NAME, INTERESTING_ITEM_SET); + return Arrays.asList(FILE_SIZE, FREQUENCY, PARENT_PATH, OBJECT_DETECTED, HASH_LIST_NAME, INTERESTING_ITEM_SET, FIRST_DATE, MOST_RECENT_DATE); } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java index 0bcbc20b61..de8df18f8d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java @@ -18,7 +18,9 @@ */ package org.sleuthkit.autopsy.discovery.search; +import java.text.SimpleDateFormat; import java.util.Collections; +import java.util.Date; import java.util.List; import java.util.Objects; import java.util.logging.Level; @@ -64,13 +66,13 @@ public class DiscoveryKeyUtils { SearchKey(String userName, List filters, DiscoveryAttributes.AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, - ResultsSorter.SortingMethod fileSortingMethod, + ResultsSorter.SortingMethod fileSortingMethod, SleuthkitCase sleuthkitCase, CentralRepository centralRepository) { this.groupAttributeType = groupAttributeType; this.groupSortingType = groupSortingType; this.fileSortingMethod = fileSortingMethod; this.filters = filters; - + StringBuilder searchStringBuilder = new StringBuilder(); searchStringBuilder.append(userName); for (AbstractFilter filter : filters) { @@ -81,15 +83,16 @@ public class DiscoveryKeyUtils { this.sleuthkitCase = sleuthkitCase; this.centralRepository = centralRepository; } - + /** - * Construct a SearchKey without a SleuthkitCase or CentralRepositry instance. + * Construct a SearchKey without a SleuthkitCase or CentralRepositry + * instance. */ SearchKey(String userName, List filters, DiscoveryAttributes.AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, ResultsSorter.SortingMethod fileSortingMethod) { - this(userName, filters, groupAttributeType, groupSortingType, + this(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod, null, null); } @@ -109,11 +112,11 @@ public class DiscoveryKeyUtils { } SearchKey otherSearchKey = (SearchKey) otherKey; - if (this.sleuthkitCase != otherSearchKey.getSleuthkitCase() || - this.centralRepository != otherSearchKey.getCentralRepository()) { + if (this.sleuthkitCase != otherSearchKey.getSleuthkitCase() + || this.centralRepository != otherSearchKey.getCentralRepository()) { return false; } - + return getKeyString().equals(otherSearchKey.getKeyString()); } @@ -130,11 +133,11 @@ public class DiscoveryKeyUtils { String getKeyString() { return keyString; } - + List getFilters() { return Collections.unmodifiableList(this.filters); } - + Group.GroupSortingAlgorithm getGroupSortingType() { return groupSortingType; } @@ -146,11 +149,11 @@ public class DiscoveryKeyUtils { ResultsSorter.SortingMethod getFileSortingMethod() { return fileSortingMethod; } - + SleuthkitCase getSleuthkitCase() { return this.sleuthkitCase; } - + CentralRepository getCentralRepository() { return this.centralRepository; } @@ -326,12 +329,12 @@ public class DiscoveryKeyUtils { private final String keywordListNamesString; @NbBundle.Messages({ - "FileSearch.KeywordListGroupKey.noKeywords=None"}) + "DiscoveryKeyUtils.KeywordListGroupKey.noKeywords=None"}) KeywordListGroupKey(ResultFile file) { keywordListNames = file.getKeywordListNames(); if (keywordListNames.isEmpty()) { - keywordListNamesString = Bundle.FileSearch_KeywordListGroupKey_noKeywords(); + keywordListNamesString = Bundle.DiscoveryKeyUtils_KeywordListGroupKey_noKeywords(); } else { keywordListNamesString = String.join(",", keywordListNames); // NON-NLS } @@ -760,12 +763,12 @@ public class DiscoveryKeyUtils { private final String hashSetNamesString; @NbBundle.Messages({ - "FileSearch.HashHitsGroupKey.noHashHits=None"}) + "DiscoveryKeyUtils.HashHitsGroupKey.noHashHits=None"}) HashHitsGroupKey(ResultFile file) { hashSetNames = file.getHashSetNames(); if (hashSetNames.isEmpty()) { - hashSetNamesString = Bundle.FileSearch_HashHitsGroupKey_noHashHits(); + hashSetNamesString = Bundle.DiscoveryKeyUtils_HashHitsGroupKey_noHashHits(); } else { hashSetNamesString = String.join(",", hashSetNames); // NON-NLS } @@ -841,12 +844,12 @@ public class DiscoveryKeyUtils { private final String interestingItemSetNamesString; @NbBundle.Messages({ - "FileSearch.InterestingItemGroupKey.noSets=None"}) + "DiscoveryKeyUtils.InterestingItemGroupKey.noSets=None"}) InterestingItemGroupKey(ResultFile file) { interestingItemSetNames = file.getInterestingSetNames(); if (interestingItemSetNames.isEmpty()) { - interestingItemSetNamesString = Bundle.FileSearch_InterestingItemGroupKey_noSets(); + interestingItemSetNamesString = Bundle.DiscoveryKeyUtils_InterestingItemGroupKey_noSets(); } else { interestingItemSetNamesString = String.join(",", interestingItemSetNames); // NON-NLS } @@ -913,6 +916,170 @@ public class DiscoveryKeyUtils { } } + static class MostRecentActivityDateGroupKey extends GroupKey { + + private final Long epochDate; + private final String dateNameString; + + @NbBundle.Messages({ + "DiscoveryKeyUtils.MostRecentActivityDateGroupKey.noDate=No Date Available"}) + MostRecentActivityDateGroupKey(Result result) { + if (result instanceof ResultDomain) { + epochDate = ((ResultDomain) result).getActivityEnd(); + dateNameString = new SimpleDateFormat("yyyy/MM/dd").format(new Date(epochDate*1000)); + } else { + epochDate = Long.MAX_VALUE; + dateNameString = Bundle.DiscoveryKeyUtils_MostRecentActivityDateGroupKey_noDate(); + } + } + + @Override + String getDisplayName() { + return getDateNameString(); + } + + @Override + public boolean equals(Object otherKey) { + if (otherKey == this) { + return true; + } + + if (!(otherKey instanceof MostRecentActivityDateGroupKey)) { + return false; + } + + MostRecentActivityDateGroupKey dateGroupKey = (MostRecentActivityDateGroupKey) otherKey; + return getDateNameString().equals(dateGroupKey.getDateNameString()); + } + + @Override + public int hashCode() { + return Objects.hash(getDateNameString()); + } + + @Override + public int compareTo(GroupKey otherGroupKey) { + if (otherGroupKey instanceof MostRecentActivityDateGroupKey) { + MostRecentActivityDateGroupKey otherDateGroupKey = (MostRecentActivityDateGroupKey) otherGroupKey; + + // Put the empty list at the end + if (this.getEpochDate().equals(Long.MAX_VALUE)) { + if (otherDateGroupKey.getEpochDate().equals(Long.MAX_VALUE)) { + return 0; + } else { + return 1; + } + } else if (otherDateGroupKey.getEpochDate().equals(Long.MAX_VALUE)) { + return -1; + } + + return getDateNameString().compareTo(otherDateGroupKey.getDateNameString()); + } else { + return compareClassNames(otherGroupKey); + } + } + + /** + * Get the date this group is for as a Long. + * + * @return The date. + */ + Long getEpochDate() { + return epochDate; + } + + /** + * Get the name which identifies this group. + * + * @return The dateNameString + */ + String getDateNameString() { + return dateNameString; + } + } + + static class FirstActivityDateGroupKey extends GroupKey { + + private final Long epochDate; + private final String dateNameString; + + @NbBundle.Messages({ + "DiscoveryKeyUtils.FirstActivityDateGroupKey.noDate=No Date Available"}) + FirstActivityDateGroupKey(Result result) { + if (result instanceof ResultDomain) { + epochDate = ((ResultDomain) result).getActivityStart(); + dateNameString = new SimpleDateFormat("yyyy/MM/dd").format(new Date(epochDate*1000)); + } else { + epochDate = Long.MAX_VALUE; + dateNameString = Bundle.DiscoveryKeyUtils_FirstActivityDateGroupKey_noDate(); + } + } + + @Override + String getDisplayName() { + return getDateNameString(); + } + + @Override + public boolean equals(Object otherKey) { + if (otherKey == this) { + return true; + } + + if (!(otherKey instanceof FirstActivityDateGroupKey)) { + return false; + } + + FirstActivityDateGroupKey dateGroupKey = (FirstActivityDateGroupKey) otherKey; + return getDateNameString().equals(dateGroupKey.getDateNameString()); + } + + @Override + public int hashCode() { + return Objects.hash(getDateNameString()); + } + + @Override + public int compareTo(GroupKey otherGroupKey) { + if (otherGroupKey instanceof FirstActivityDateGroupKey) { + FirstActivityDateGroupKey otherDateGroupKey = (FirstActivityDateGroupKey) otherGroupKey; + + // Put the empty list at the end + if (this.getEpochDate().equals(Long.MAX_VALUE)) { + if (otherDateGroupKey.getEpochDate().equals(Long.MAX_VALUE)) { + return 0; + } else { + return 1; + } + } else if (otherDateGroupKey.getEpochDate().equals(Long.MAX_VALUE)) { + return -1; + } + + return getDateNameString().compareTo(otherDateGroupKey.getDateNameString()); + } else { + return compareClassNames(otherGroupKey); + } + } + + /** + * Get the date this group is for as a Long. + * + * @return The date. + */ + Long getEpochDate() { + return epochDate; + } + + /** + * Get the name which identifies this group. + * + * @return The dateNameString + */ + String getDateNameString() { + return dateNameString; + } + } + /** * Key representing an object detected group */ @@ -922,12 +1089,12 @@ public class DiscoveryKeyUtils { private final String objectDetectedNamesString; @NbBundle.Messages({ - "FileSearch.ObjectDetectedGroupKey.noSets=None"}) + "DiscoveryKeyUtils.ObjectDetectedGroupKey.noSets=None"}) ObjectDetectedGroupKey(ResultFile file) { objectDetectedNames = file.getObjectDetectedNames(); if (objectDetectedNames.isEmpty()) { - objectDetectedNamesString = Bundle.FileSearch_ObjectDetectedGroupKey_noSets(); + objectDetectedNamesString = Bundle.DiscoveryKeyUtils_ObjectDetectedGroupKey_noSets(); } else { objectDetectedNamesString = String.join(",", objectDetectedNames); // NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java index fb29e41078..2a253399a5 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java @@ -64,7 +64,7 @@ class DomainSearchCache { groupSortingType, domainSortingMethod, caseDb, centralRepoDb); return cache.get(searchKey); - } catch (ExecutionException ex) { + } catch (Throwable ex) { throw new DiscoveryException("Error fetching results from cache", ex.getCause()); } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java index 59c47429c4..994e99267a 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java @@ -155,6 +155,7 @@ class DomainSearchCacheLoader extends CacheLoader results) { + System.out.println("RESULT SIZE: "+ results.size()); for (Result result : results) { // Add the file to the appropriate group, creating it if necessary GroupKey groupKey = attrType.getGroupKey(result); - + if (!groupMap.containsKey(groupKey)) { groupMap.put(groupKey, new Group(groupSortingType, groupKey)); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java index 87dfe5d431..dfa283735c 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java @@ -248,7 +248,9 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li synchronized List getFilters() { List filtersToUse = new ArrayList<>(); - filtersToUse.add(new SearchFiltering.FileTypeFilter(getType())); + if (getType() != SearchData.Type.DOMAIN) { //Domain type does not have a file type + filtersToUse.add(new SearchFiltering.FileTypeFilter(getType())); + } for (AbstractDiscoveryFilterPanel filterPanel : filters) { if (filterPanel.getCheckbox().isSelected()) { AbstractFilter filter = filterPanel.getFilter(); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java index 6a185b70ab..80f85575c0 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java @@ -82,6 +82,7 @@ final class GroupListPanel extends javax.swing.JPanel { */ @Subscribe void handleSearchCompleteEvent(DiscoveryEventUtils.SearchCompleteEvent searchCompleteEvent) { + System.out.println("SEARCH COMPLETE EVENT"); groupMap = searchCompleteEvent.getGroupMap(); searchfilters = searchCompleteEvent.getFilters(); groupingAttribute = searchCompleteEvent.getGroupingAttr(); @@ -108,6 +109,7 @@ final class GroupListPanel extends javax.swing.JPanel { */ @Subscribe void handleSearchCancelledEvent(DiscoveryEventUtils.SearchCancelledEvent searchCancelledEvent) { + System.out.println("SEARCH CANCELLED EVENT"); SwingUtilities.invokeLater(() -> { setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); }); From 637e0572b6783fa8f13719acd9b492d1ac2e6380 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 10 Sep 2020 14:19:34 -0400 Subject: [PATCH 038/130] Bug fixes and performance fixes --- .../discovery/search/DiscoveryAttributes.java | 111 +++++++++++++++--- .../discovery/search/DomainSearchCache.java | 13 +- .../search/DomainSearchCacheLoader.java | 21 +++- .../discovery/search/ResultDomain.java | 17 ++- .../discovery/search/ResultsSorter.java | 27 ++++- 5 files changed, 149 insertions(+), 40 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java index 178530e072..ca95a16d08 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java @@ -44,6 +44,8 @@ import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; +import java.util.StringJoiner; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizer; /** * Class which contains the search attributes which can be specified for @@ -220,6 +222,8 @@ public class DiscoveryAttributes { static class FrequencyAttribute extends AttributeType { static final int BATCH_SIZE = 50; // Number of hashes to look up at one time + + static final int DOMAIN_BATCH_SIZE = 500; // Number of domains to look up at one time @Override public DiscoveryKeyUtils.GroupKey getGroupKey(Result file) { @@ -253,10 +257,13 @@ public class DiscoveryAttributes { List currentFiles = new ArrayList<>(); Set hashesToLookUp = new HashSet<>(); + List domainsToQuery = new ArrayList<>(); + for (Result result : results) { if (result.getKnown() == TskData.FileKnown.KNOWN) { result.setFrequency(SearchData.Frequency.KNOWN); } + if (result.getType() != SearchData.Type.DOMAIN) { ResultFile file = (ResultFile) result; if (file.getFrequency() == SearchData.Frequency.UNKNOWN @@ -265,28 +272,98 @@ public class DiscoveryAttributes { hashesToLookUp.add(file.getFirstInstance().getMd5Hash()); currentFiles.add(file); } + + if (hashesToLookUp.size() >= BATCH_SIZE) { + computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); + + hashesToLookUp.clear(); + currentFiles.clear(); + } } else { - ResultDomain domain = (ResultDomain) result; - try { - CorrelationAttributeInstance.Type domainAttributeType = - centralRepoDb.getCorrelationTypeById(CorrelationAttributeInstance.DOMAIN_TYPE_ID); - Long count = centralRepoDb.getCountArtifactInstancesByTypeValue(domainAttributeType, domain.getDomain()); - domain.setFrequency(SearchData.Frequency.fromCount(count)); - } catch (CentralRepoException ex) { - throw new DiscoveryException("Error encountered querying the central repository.", ex); - } catch (CorrelationAttributeNormalizationException ex) { - logger.log(Level.INFO, "Domain [%s] could not be normalized for central repository querying, skipping...", domain.getDomain()); + ResultDomain domainInstance = (ResultDomain) result; + domainsToQuery.add(domainInstance); + + if (domainsToQuery.size() == DOMAIN_BATCH_SIZE) { + queryDomainFrequency(domainsToQuery, centralRepoDb); + + domainsToQuery.clear(); } } - - if (hashesToLookUp.size() >= BATCH_SIZE) { - computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); + } + + queryDomainFrequency(domainsToQuery, centralRepoDb); + computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); + } + } + + private static void queryDomainFrequency(List domainsToQuery, CentralRepository centralRepository) throws DiscoveryException { + if (domainsToQuery.isEmpty()) { + return; + } + + try { + final Map> resultDomainTable = new HashMap<>(); + final StringJoiner joiner = new StringJoiner(", "); - hashesToLookUp.clear(); - currentFiles.clear(); + final CorrelationAttributeInstance.Type attributeType = centralRepository.getCorrelationTypeById(CorrelationAttributeInstance.DOMAIN_TYPE_ID); + for(ResultDomain domainInstance : domainsToQuery) { + try { + final String domainValue = domainInstance.getDomain(); + final String normalizedDomain = CorrelationAttributeNormalizer.normalize(attributeType, domainValue); + final List bucket = resultDomainTable.getOrDefault(normalizedDomain, new ArrayList<>()); + bucket.add(domainInstance); + resultDomainTable.put(normalizedDomain, bucket); + joiner.add("'" + normalizedDomain + "'"); + } catch (CorrelationAttributeNormalizationException ex) { + logger.log(Level.INFO, String.format("Domain [%s] failed normalization, skipping...", domainInstance.getDomain())); } } - computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); + + final String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(attributeType); + final String domainFrequencyQuery = " value AS domain_name, COUNT(*) AS frequency " + + "FROM " + tableName + " " + + "WHERE value IN (" + joiner + ") " + + "GROUP BY value"; + + final DomainFrequencyCallback frequencyCallback = new DomainFrequencyCallback(resultDomainTable); + centralRepository.processSelectClause(domainFrequencyQuery, frequencyCallback); + + if (frequencyCallback.getCause() != null) { + throw frequencyCallback.getCause(); + } + } catch (CentralRepoException | SQLException ex) { + throw new DiscoveryException("Fatal exception encountered querying the CR.", ex); + } + } + + private static class DomainFrequencyCallback implements InstanceTableCallback { + + private final Map> domainLookup; + private SQLException sqlCause; + + private DomainFrequencyCallback(Map> domainLookup) { + this.domainLookup = domainLookup; + } + + @Override + public void process(ResultSet resultSet) { + try { + while (resultSet.next()) { + String domain = resultSet.getString("domain_name"); + Long frequency = resultSet.getLong("frequency"); + + List domainInstances = domainLookup.get(domain); + for(ResultDomain domainInstance : domainInstances) { + domainInstance.setFrequency(SearchData.Frequency.fromCount(frequency)); + } + } + } catch (SQLException ex) { + this.sqlCause = ex; + } + } + + SQLException getCause() { + return this.sqlCause; } } @@ -644,7 +721,7 @@ public class DiscoveryAttributes { return Arrays.asList(FILE_SIZE, FREQUENCY, PARENT_PATH, OBJECT_DETECTED, HASH_LIST_NAME, INTERESTING_ITEM_SET); } } - + /** * Computes the CR frequency of all the given hashes and updates the list of * files. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java index fb29e41078..fca63177e5 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java @@ -36,17 +36,10 @@ import org.sleuthkit.datamodel.SleuthkitCase; class DomainSearchCache { private static final int MAXIMUM_CACHE_SIZE = 10; - private final LoadingCache>> cache; - - DomainSearchCache() { - this(new DomainSearchCacheLoader()); - } - - DomainSearchCache(DomainSearchCacheLoader cacheLoader) { - this.cache = CacheBuilder.newBuilder() + private static final LoadingCache>> cache = + CacheBuilder.newBuilder() .maximumSize(MAXIMUM_CACHE_SIZE) - .build(cacheLoader); - } + .build(new DomainSearchCacheLoader()); /** * Get domain search results matching the given parameters. If no results diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java index 59c47429c4..9bc6e1f417 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java @@ -95,7 +95,7 @@ class DomainSearchCacheLoader extends CacheLoader(); this.skc = skc; } @@ -235,6 +239,8 @@ class DomainSearchCacheLoader extends CacheLoader { case BY_DOMAIN_NAME: comparators.add(getDomainNameComparator()); break; + case BY_MOST_RECENT_DATE_TIME: + comparators.add(getMostRecentDateTimeComparator()); + break; default: // The default comparator will be added afterward break; @@ -112,7 +115,7 @@ public class ResultsSorter implements Comparator { private static Comparator getTypeComparator() { return (Result result1, Result result2) -> Integer.compare(result1.getType().getRanking(), result2.getType().getRanking()); } - + /** * Compare files using a concatenated version of keyword list names. * Alphabetical by the list names with files with no keyword list hits going @@ -244,6 +247,21 @@ public class ResultsSorter implements Comparator { return compareStrings(first.getDomain().toLowerCase(), second.getDomain().toLowerCase()); }; } + + /** + * Sorts results by most recent date time + */ + private static Comparator getMostRecentDateTimeComparator() { + return (Result result1, Result result2) -> { + if(result1.getType() != SearchData.Type.DOMAIN) { + return 0; + } + + ResultDomain first = (ResultDomain) result1; + ResultDomain second = (ResultDomain) result2; + return Long.compare(second.getActivityEnd(), first.getActivityEnd()); + }; + } /** * A final default comparison between two ResultFile objects. Currently this @@ -297,7 +315,8 @@ public class ResultsSorter implements Comparator { "FileSorter.SortingMethod.frequency.displayName=Central Repo Frequency", "FileSorter.SortingMethod.keywordlist.displayName=Keyword List Names", "FileSorter.SortingMethod.fullPath.displayName=Full Path", - "FileSorter.SortingMethod.domain.displayName=Domain"}) + "FileSorter.SortingMethod.domain.displayName=Domain", + "FileSorter.SortingMethod.dateTime.displayName=Most Recent Date"}) public enum SortingMethod { BY_FILE_NAME(new ArrayList<>(), Bundle.FileSorter_SortingMethod_filename_displayName()), // Sort alphabetically by file name @@ -314,7 +333,9 @@ public class ResultsSorter implements Comparator { BY_FULL_PATH(new ArrayList<>(), Bundle.FileSorter_SortingMethod_fullPath_displayName()), // Sort alphabetically by path BY_DOMAIN_NAME(new ArrayList<>(), - Bundle.FileSorter_SortingMethod_domain_displayName()); + Bundle.FileSorter_SortingMethod_domain_displayName()), + BY_MOST_RECENT_DATE_TIME(new ArrayList<>(), + Bundle.FileSorter_SortingMethod_dateTime_displayName()); private final String displayName; private final List requiredAttributes; From ed558cafa0f4ec3ad57091a40210e0cbf7cd6b20 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 11 Sep 2020 07:47:56 -0400 Subject: [PATCH 039/130] 6714 add default date to pickers --- .../org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form | 6 ++++++ .../org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java | 5 +++-- .../org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java | 4 ++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form index 1d5d166863..d7a5c8e1cc 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form @@ -154,6 +154,9 @@ + + + @@ -165,6 +168,9 @@ + + + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java index d7a94a30c7..4758549cdb 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.discovery.ui; import java.time.Duration; import java.time.LocalDate; import java.time.ZoneId; -import java.time.temporal.TemporalUnit; import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import javax.swing.JCheckBox; import javax.swing.JLabel; @@ -106,10 +105,12 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { } }); + startDatePicker.setDate(LocalDate.now()); startDatePicker.setEnabled(false); startDatePicker.setMinimumSize(new java.awt.Dimension(60, 22)); startDatePicker.setPreferredSize(new java.awt.Dimension(110, 22)); + endDatePicker.setDate(LocalDate.now()); endDatePicker.setEnabled(false); endDatePicker.setMinimumSize(new java.awt.Dimension(60, 22)); endDatePicker.setPreferredSize(new java.awt.Dimension(110, 22)); @@ -270,7 +271,7 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { LocalDate endDate = LocalDate.MAX; ZoneId zone = Utils.getUserPreferredZoneId(); if (rangeRadioButton.isSelected()) { - if (startCheckBox.isSelected() && startDatePicker.getDate() != null) { + if (startCheckBox.isSelected() && startDatePicker.getDate().equals(startDate)) { startDate = startDatePicker.getDate(); } if (endCheckBox.isSelected() && endDatePicker.getDate() != null) { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index 94e41c8cf2..474b766910 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -149,8 +149,8 @@ final class DiscoveryDialog extends javax.swing.JDialog { * Set the type buttons to a default state where none are selected. */ private void unselectAllButtons() { - imagesButton.setSelected(false); - imagesButton.setEnabled(true); + imagesButton.setSelected(false); + imagesButton.setEnabled(true); imagesButton.setBackground(UNSELECTED_COLOR); videosButton.setSelected(false); videosButton.setEnabled(true); From b32aa710fe5bfbf6520c6cffd9122b91eabf5f43 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 11 Sep 2020 08:21:49 -0400 Subject: [PATCH 040/130] 6714 fix listeners for date range --- .../autopsy/discovery/ui/Bundle.properties | 2 +- .../autopsy/discovery/ui/DateFilterPanel.form | 6 +- .../autopsy/discovery/ui/DateFilterPanel.java | 70 ++++++++++++------- .../autopsy/discovery/ui/GroupListPanel.java | 2 - 4 files changed, 47 insertions(+), 33 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties index 90bf2dd504..baffc3ee43 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties @@ -36,7 +36,6 @@ DocumentPanel.isDeletedLabel.toolTipText= DomainFilterPanel.domainFiltersSplitPane.toolTipText= DomainFilterPanel.domainFiltersSplitPane.border.title=Step 2: Filter which domains to show SizeFilterPanel.sizeCheckbox.text=File Size: -DateFilterPanel.dateFilterCheckbox.text=Date Filter: DateFilterPanel.endCheckBox.text=End: DateFilterPanel.startCheckBox.text=Start: DateFilterPanel.daysLabel.text=days of activity @@ -54,3 +53,4 @@ DocumentFilterPanel.documentsFiltersSplitPane.border.title=Step 2: Filter which ObjectDetectedFilterPanel.text=Object Detected: DetailsPanel.instancesList.border.title=Instances DateFilterPanel.mostRecentRadioButton.text=Only last: +DateFilterPanel.dateFilterCheckBox.text=Date Filter: diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form index d7a5c8e1cc..8ecca7e27b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form @@ -4,14 +4,14 @@ - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java index 4758549cdb..efb5e03370 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.discovery.ui; +import java.awt.event.ActionListener; import java.time.Duration; import java.time.LocalDate; import java.time.ZoneId; @@ -26,6 +27,7 @@ import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.SpinnerNumberModel; +import javax.swing.event.ListSelectionListener; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.communications.Utils; import org.sleuthkit.autopsy.discovery.search.SearchFiltering; @@ -61,7 +63,7 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { private void initComponents() { buttonGroup1 = new javax.swing.ButtonGroup(); - dateFilterCheckbox = new javax.swing.JCheckBox(); + dateFilterCheckBox = new javax.swing.JCheckBox(); jPanel1 = new javax.swing.JPanel(); daysSpinner = new javax.swing.JSpinner(numberModel); daysLabel = new javax.swing.JLabel(); @@ -72,10 +74,10 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { endCheckBox = new javax.swing.JCheckBox(); rangeRadioButton = new javax.swing.JRadioButton(); - org.openide.awt.Mnemonics.setLocalizedText(dateFilterCheckbox, org.openide.util.NbBundle.getMessage(DateFilterPanel.class, "DateFilterPanel.dateFilterCheckbox.text")); // NOI18N - dateFilterCheckbox.addActionListener(new java.awt.event.ActionListener() { + org.openide.awt.Mnemonics.setLocalizedText(dateFilterCheckBox, org.openide.util.NbBundle.getMessage(DateFilterPanel.class, "DateFilterPanel.dateFilterCheckBox.text")); // NOI18N + dateFilterCheckBox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - dateFilterCheckboxActionPerformed(evt); + dateFilterCheckBoxActionPerformed(evt); } }); @@ -198,12 +200,12 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { endDatePicker.setEnabled(endCheckBox.isEnabled() && endCheckBox.isSelected()); }//GEN-LAST:event_endCheckBoxStateChanged - private void dateFilterCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dateFilterCheckboxActionPerformed - rangeRadioButton.setEnabled(dateFilterCheckbox.isSelected()); - mostRecentRadioButton.setEnabled(dateFilterCheckbox.isSelected()); - rangeRadioButton.firePropertyChange("DateFilterChange", true, false); - mostRecentRadioButton.firePropertyChange("DateFilterChange", true, false); - }//GEN-LAST:event_dateFilterCheckboxActionPerformed + private void dateFilterCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dateFilterCheckBoxActionPerformed + rangeRadioButton.setEnabled(dateFilterCheckBox.isSelected()); + mostRecentRadioButton.setEnabled(dateFilterCheckBox.isSelected()); + rangeRadioButton.firePropertyChange("DateFilterChange", !rangeRadioButton.isEnabled(), rangeRadioButton.isEnabled()); + mostRecentRadioButton.firePropertyChange("DateFilterChange", !mostRecentRadioButton.isEnabled(), mostRecentRadioButton.isEnabled()); + }//GEN-LAST:event_dateFilterCheckBoxActionPerformed private void mostRecentRadioButtonStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_mostRecentRadioButtonStateChanged daysSpinner.setEnabled(mostRecentRadioButton.isSelected()); @@ -219,8 +221,8 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { @Override void configurePanel(boolean selected, int[] indicesSelected) { - dateFilterCheckbox.setSelected(selected); - if (dateFilterCheckbox.isEnabled() && dateFilterCheckbox.isSelected()) { + dateFilterCheckBox.setSelected(selected); + if (dateFilterCheckBox.isEnabled() && dateFilterCheckBox.isSelected()) { mostRecentRadioButton.setEnabled(true); rangeRadioButton.setEnabled(true); mostRecentRadioButton.setSelected(true); @@ -232,7 +234,7 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { @Override JCheckBox getCheckbox() { - return dateFilterCheckbox; + return dateFilterCheckBox; } @Override @@ -245,19 +247,33 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { return null; } + @Override + void addListeners(ActionListener actionListener, ListSelectionListener listListener) { + dateFilterCheckBox.addActionListener(actionListener); + startCheckBox.addActionListener(actionListener); + endCheckBox.addActionListener(actionListener); + } + + @Override + void removeListeners() { + for (ActionListener listener : dateFilterCheckBox.getActionListeners()) { + dateFilterCheckBox.removeActionListener(listener); + } + for (ActionListener listener : startCheckBox.getActionListeners()) { + startCheckBox.removeActionListener(listener); + } + for (ActionListener listener : endCheckBox.getActionListeners()) { + endCheckBox.removeActionListener(listener); + } + } + @Override String checkForError() { - if (dateFilterCheckbox.isSelected()) { + if (dateFilterCheckBox.isSelected()) { if (!(rangeRadioButton.isSelected() || mostRecentRadioButton.isSelected())) { return "Range or Only Last must be selected"; - } else if (rangeRadioButton.isSelected()) { - if (!startCheckBox.isSelected() && !endCheckBox.isSelected()) { - return "A start or end date must be specified to use the range filter"; - } else if (startCheckBox.isSelected() && startDatePicker.getDate() == null) { - return "A start date must be specified to use the start date option of the range filter"; - } else if (endCheckBox.isSelected() && endDatePicker.getDate() == null) { - return "An end date must be specified to use the end date option of the range filter"; - } + } else if (rangeRadioButton.isSelected() && !(startCheckBox.isSelected() || endCheckBox.isSelected())) { + return "A start or end date must be specified to use the range filter"; } } return ""; @@ -266,20 +282,20 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { @Override AbstractFilter getFilter() { - if (dateFilterCheckbox.isSelected()) { + if (dateFilterCheckBox.isSelected()) { LocalDate startDate = LocalDate.MIN; LocalDate endDate = LocalDate.MAX; ZoneId zone = Utils.getUserPreferredZoneId(); - if (rangeRadioButton.isSelected()) { + if (rangeRadioButton.isSelected() && (startCheckBox.isSelected() || endCheckBox.isSelected())) { if (startCheckBox.isSelected() && startDatePicker.getDate().equals(startDate)) { startDate = startDatePicker.getDate(); } if (endCheckBox.isSelected() && endDatePicker.getDate() != null) { endDate = endDatePicker.getDate(); } - } else if (dateFilterCheckbox.isSelected() && mostRecentRadioButton.isSelected()) { + } else if (dateFilterCheckBox.isSelected() && mostRecentRadioButton.isSelected()) { endDate = LocalDate.now(); - startDate = LocalDate.now().minus(Duration.ofDays((long)daysSpinner.getValue())); + startDate = LocalDate.now().minus(Duration.ofDays((long) daysSpinner.getValue())); } return new SearchFiltering.ArtifactDateRangeFilter(startDate.atStartOfDay(zone).toEpochSecond(), endDate.atStartOfDay(zone).toEpochSecond() + SECS_PER_DAY);//to insure end date is inclusive } @@ -287,7 +303,7 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup buttonGroup1; - private javax.swing.JCheckBox dateFilterCheckbox; + private javax.swing.JCheckBox dateFilterCheckBox; private javax.swing.JLabel daysLabel; private javax.swing.JSpinner daysSpinner; private javax.swing.JCheckBox endCheckBox; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java index 80f85575c0..6a185b70ab 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java @@ -82,7 +82,6 @@ final class GroupListPanel extends javax.swing.JPanel { */ @Subscribe void handleSearchCompleteEvent(DiscoveryEventUtils.SearchCompleteEvent searchCompleteEvent) { - System.out.println("SEARCH COMPLETE EVENT"); groupMap = searchCompleteEvent.getGroupMap(); searchfilters = searchCompleteEvent.getFilters(); groupingAttribute = searchCompleteEvent.getGroupingAttr(); @@ -109,7 +108,6 @@ final class GroupListPanel extends javax.swing.JPanel { */ @Subscribe void handleSearchCancelledEvent(DiscoveryEventUtils.SearchCancelledEvent searchCancelledEvent) { - System.out.println("SEARCH CANCELLED EVENT"); SwingUtilities.invokeLater(() -> { setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); }); From 560724ba20a59965b93d04ab806bb5c34bec72a1 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 11 Sep 2020 09:38:43 -0400 Subject: [PATCH 041/130] 6714 remove souts and fix listener again --- .../discovery/search/DiscoveryKeyUtils.java | 5 +++-- .../discovery/search/DomainSearchCacheLoader.java | 1 - .../autopsy/discovery/search/SearchResults.java | 1 - .../discovery/ui/AbstractFiltersPanel.java | 2 +- .../autopsy/discovery/ui/Bundle.properties-MERGED | 2 +- .../autopsy/discovery/ui/DateFilterPanel.java | 15 +++++++++++++-- 6 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java index de8df18f8d..ec5b5516b2 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java @@ -23,6 +23,7 @@ import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Objects; +import java.util.concurrent.TimeUnit; import java.util.logging.Level; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; @@ -926,7 +927,7 @@ public class DiscoveryKeyUtils { MostRecentActivityDateGroupKey(Result result) { if (result instanceof ResultDomain) { epochDate = ((ResultDomain) result).getActivityEnd(); - dateNameString = new SimpleDateFormat("yyyy/MM/dd").format(new Date(epochDate*1000)); + dateNameString = new SimpleDateFormat("yyyy/MM/dd").format(new Date(TimeUnit.SECONDS.toMillis(epochDate))); } else { epochDate = Long.MAX_VALUE; dateNameString = Bundle.DiscoveryKeyUtils_MostRecentActivityDateGroupKey_noDate(); @@ -1008,7 +1009,7 @@ public class DiscoveryKeyUtils { FirstActivityDateGroupKey(Result result) { if (result instanceof ResultDomain) { epochDate = ((ResultDomain) result).getActivityStart(); - dateNameString = new SimpleDateFormat("yyyy/MM/dd").format(new Date(epochDate*1000)); + dateNameString = new SimpleDateFormat("yyyy/MM/dd").format(new Date(TimeUnit.SECONDS.toMillis(epochDate))); } else { epochDate = Long.MAX_VALUE; dateNameString = Bundle.DiscoveryKeyUtils_FirstActivityDateGroupKey_noDate(); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java index 994e99267a..59c47429c4 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java @@ -155,7 +155,6 @@ class DomainSearchCacheLoader extends CacheLoader results) { - System.out.println("RESULT SIZE: "+ results.size()); for (Result result : results) { // Add the file to the appropriate group, creating it if necessary GroupKey groupKey = attrType.getGroupKey(result); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java index dfa283735c..0736708e9c 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java @@ -120,7 +120,7 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li secondColumnY += constraints.gridheight; } } - + /** * Add the panels representing the two columns to the specified JSplitPane. * diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED index 8f9b2055cd..df37ba0e3f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED @@ -90,7 +90,6 @@ DocumentPanel.isDeletedLabel.toolTipText= DomainFilterPanel.domainFiltersSplitPane.toolTipText= DomainFilterPanel.domainFiltersSplitPane.border.title=Step 2: Filter which domains to show SizeFilterPanel.sizeCheckbox.text=File Size: -DateFilterPanel.dateFilterCheckbox.text=Date Filter: DateFilterPanel.endCheckBox.text=End: DateFilterPanel.startCheckBox.text=Start: DateFilterPanel.daysLabel.text=days of activity @@ -108,6 +107,7 @@ DocumentFilterPanel.documentsFiltersSplitPane.border.title=Step 2: Filter which ObjectDetectedFilterPanel.text=Object Detected: DetailsPanel.instancesList.border.title=Instances DateFilterPanel.mostRecentRadioButton.text=Only last: +DateFilterPanel.dateFilterCheckBox.text=Date Filter: VideoThumbnailPanel.bytes.text=bytes VideoThumbnailPanel.deleted.text=All instances of file are deleted. VideoThumbnailPanel.gigaBytes.text=GB diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java index efb5e03370..803c637411 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java @@ -215,8 +215,8 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { private void rangeRadioButtonStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_rangeRadioButtonStateChanged startCheckBox.setEnabled(rangeRadioButton.isEnabled() && rangeRadioButton.isSelected()); endCheckBox.setEnabled(rangeRadioButton.isEnabled() && rangeRadioButton.isSelected()); - endCheckBoxStateChanged(evt); - startCheckBoxStateChanged(evt); + startCheckBox.firePropertyChange("StartButtonChange", true, false); + endCheckBox.firePropertyChange("EndButtonChange", true, false); }//GEN-LAST:event_rangeRadioButtonStateChanged @Override @@ -252,6 +252,8 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { dateFilterCheckBox.addActionListener(actionListener); startCheckBox.addActionListener(actionListener); endCheckBox.addActionListener(actionListener); + rangeRadioButton.addActionListener(actionListener); + mostRecentRadioButton.addActionListener(actionListener); } @Override @@ -259,6 +261,15 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { for (ActionListener listener : dateFilterCheckBox.getActionListeners()) { dateFilterCheckBox.removeActionListener(listener); } + for (ActionListener listener : rangeRadioButton.getActionListeners()) { + rangeRadioButton.removeActionListener(listener); + } + for (ActionListener listener : mostRecentRadioButton.getActionListeners()) { + mostRecentRadioButton.removeActionListener(listener); + } + for (ActionListener listener : rangeRadioButton.getActionListeners()) { + rangeRadioButton.removeActionListener(listener); + } for (ActionListener listener : startCheckBox.getActionListeners()) { startCheckBox.removeActionListener(listener); } From e36e32fd6d20dbc6f3cb655b20be8124e1a05c28 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Fri, 11 Sep 2020 10:02:25 -0400 Subject: [PATCH 042/130] Added tests, removed some logic added for data source domains table --- Core/ivy.xml | 3 + Core/nbproject/project.properties | 4 + Core/nbproject/project.xml | 32 +- .../discovery/search/Bundle.properties-MERGED | 1 + .../search/DomainSearchCacheLoader.java | 11 +- .../discovery/search/ResultDomain.java | 11 +- .../discovery/search/ResultsSorter.java | 10 +- .../search/DomainSearchCacheLoaderTest.java | 157 +++++++ .../discovery/search/DomainSearchTest.java | 413 ++++++++++++++++++ .../search/DomainSearchTestUtils.java | 51 +++ 10 files changed, 658 insertions(+), 35 deletions(-) create mode 100755 Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoaderTest.java create mode 100755 Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTest.java create mode 100755 Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTestUtils.java diff --git a/Core/ivy.xml b/Core/ivy.xml index 63fdd9ed92..1b2acba60d 100644 --- a/Core/ivy.xml +++ b/Core/ivy.xml @@ -54,6 +54,9 @@ + + + diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties index 8dbd7f8d92..37d8de5814 100644 --- a/Core/nbproject/project.properties +++ b/Core/nbproject/project.properties @@ -13,6 +13,8 @@ file.reference.bcpkix-jdk15on-1.60.jar=release\\modules\\ext\\bcpkix-jdk15on-1.6 file.reference.bcprov-ext-jdk15on-1.54.jar=release/modules/ext/bcprov-ext-jdk15on-1.54.jar file.reference.bcprov-jdk15on-1.60.jar=release\\modules\\ext\\bcprov-jdk15on-1.60.jar file.reference.boilerpipe-1.1.0.jar=release\\modules\\ext\\boilerpipe-1.1.0.jar +file.reference.byte-buddy-1.10.13.jar=release\\modules\\ext\\byte-buddy-1.10.13.jar +file.reference.byte-buddy-agent-1.10.13.jar=release\\modules\\ext\\byte-buddy-agent-1.10.13.jar file.reference.c3p0-0.9.5.jar=release/modules/ext/c3p0-0.9.5.jar file.reference.cdm-4.5.5.jar=release\\modules\\ext\\cdm-4.5.5.jar file.reference.commons-codec-1.11.jar=release\\modules\\ext\\commons-codec-1.11.jar @@ -68,7 +70,9 @@ file.reference.jython-standalone-2.7.0.jar=release/modules/ext/jython-standalone file.reference.libphonenumber-3.5.jar=release/modules/ext/libphonenumber-3.5.jar file.reference.mchange-commons-java-0.2.9.jar=release/modules/ext/mchange-commons-java-0.2.9.jar file.reference.metadata-extractor-2.11.0.jar=release\\modules\\ext\\metadata-extractor-2.11.0.jar +file.reference.mockito-core-3.5.7.jar=release\\modules\\ext\\mockito-core-3.5.7.jar file.reference.netcdf4-4.5.5.jar=release\\modules\\ext\\netcdf4-4.5.5.jar +file.reference.objenesis-3.1.jar=release\\modules\\ext\\objenesis-3.1.jar file.reference.openjson-1.0.10.jar=release\\modules\\ext\\openjson-1.0.10.jar file.reference.opennlp-tools-1.9.1.jar=release\\modules\\ext\\opennlp-tools-1.9.1.jar file.reference.parso-2.0.10.jar=release\\modules\\ext\\parso-2.0.10.jar diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 61e6a86b04..5abd3666b7 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -423,6 +423,10 @@ ext/okhttp-2.7.5.jar release/modules/ext/okhttp-2.7.5.jar + + ext/byte-buddy-1.10.13.jar + release\modules\ext\byte-buddy-1.10.13.jar + ext/libphonenumber-3.5.jar release/modules/ext/libphonenumber-3.5.jar @@ -471,10 +475,6 @@ ext/commons-pool2-2.4.2.jar release/modules/ext/commons-pool2-2.4.2.jar - - ext/sleuthkit-4.10.0.jar - release/modules/ext/sleuthkit-4.10.0.jar - ext/jxmapviewer2-2.4.jar release/modules/ext/jxmapviewer2-2.4.jar @@ -611,6 +611,14 @@ ext/grib-4.5.5.jar release\modules\ext\grib-4.5.5.jar + + ext/sleuthkit-4.10.0.jar + release/modules/ext/sleuthkit-4.10.0.jar + + + ext/sleuthkit-caseuco-4.10.0.jar + release/modules/ext/sleuthkit-caseuco-4.10.0.jar + ext/gax-1.44.0.jar release/modules/ext/gax-1.44.0.jar @@ -647,6 +655,10 @@ ext/decodetect-core-0.3.jar release/modules/ext/decodetect-core-0.3.jar + + ext/mockito-core-3.5.7.jar + release\modules\ext\mockito-core-3.5.7.jar + ext/jbig2-imageio-3.0.2.jar release\modules\ext\jbig2-imageio-3.0.2.jar @@ -667,6 +679,10 @@ ext/curator-recipes-2.8.0.jar release/modules/ext/curator-recipes-2.8.0.jar + + ext/objenesis-3.1.jar + release\modules\ext\objenesis-3.1.jar + ext/tagsoup-1.2.1.jar release\modules\ext\tagsoup-1.2.1.jar @@ -779,10 +795,6 @@ ext/curator-client-2.8.0.jar release/modules/ext/curator-client-2.8.0.jar - - ext/sleuthkit-caseuco-4.10.0.jar - release/modules/ext/sleuthkit-caseuco-4.10.0.jar - ext/fontbox-2.0.13.jar release\modules\ext\fontbox-2.0.13.jar @@ -831,6 +843,10 @@ ext/jutf7-1.0.0.jar release/modules/ext/jutf7-1.0.0.jar + + ext/byte-buddy-agent-1.10.13.jar + release\modules\ext\byte-buddy-agent-1.10.13.jar + ext/batik-awt-util-1.6.jar release/modules/ext/batik-awt-util-1.6.jar diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED index fbb3240018..b31ec5db26 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED @@ -34,6 +34,7 @@ FileSearchFiltering.TagsFilter.desc=Tagged {0} FileSearchFiltering.TagsFilter.or=, FileSearchFiltering.UserCreatedFilter.desc=that contain EXIF data FileSorter.SortingMethod.datasource.displayName=Data Source +FileSorter.SortingMethod.domain.displayName=Domain FileSorter.SortingMethod.filename.displayName=File Name FileSorter.SortingMethod.filesize.displayName=File Size FileSorter.SortingMethod.filetype.displayName=File Type diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java index 9bc6e1f417..999aab0425 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java @@ -136,10 +136,6 @@ class DomainSearchCacheLoader extends CacheLoader { case BY_DOMAIN_NAME: comparators.add(getDomainNameComparator()); break; - case BY_MOST_RECENT_DATE_TIME: - comparators.add(getMostRecentDateTimeComparator()); - break; default: // The default comparator will be added afterward break; @@ -315,8 +312,7 @@ public class ResultsSorter implements Comparator { "FileSorter.SortingMethod.frequency.displayName=Central Repo Frequency", "FileSorter.SortingMethod.keywordlist.displayName=Keyword List Names", "FileSorter.SortingMethod.fullPath.displayName=Full Path", - "FileSorter.SortingMethod.domain.displayName=Domain", - "FileSorter.SortingMethod.dateTime.displayName=Most Recent Date"}) + "FileSorter.SortingMethod.domain.displayName=Domain"}) public enum SortingMethod { BY_FILE_NAME(new ArrayList<>(), Bundle.FileSorter_SortingMethod_filename_displayName()), // Sort alphabetically by file name @@ -333,9 +329,7 @@ public class ResultsSorter implements Comparator { BY_FULL_PATH(new ArrayList<>(), Bundle.FileSorter_SortingMethod_fullPath_displayName()), // Sort alphabetically by path BY_DOMAIN_NAME(new ArrayList<>(), - Bundle.FileSorter_SortingMethod_domain_displayName()), - BY_MOST_RECENT_DATE_TIME(new ArrayList<>(), - Bundle.FileSorter_SortingMethod_dateTime_displayName()); + Bundle.FileSorter_SortingMethod_domain_displayName()); private final String displayName; private final List requiredAttributes; diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoaderTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoaderTest.java new file mode 100755 index 0000000000..2a75ca2dc7 --- /dev/null +++ b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoaderTest.java @@ -0,0 +1,157 @@ +/* + * 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.discovery.search; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import static org.mockito.Mockito.*; +import static org.junit.Assert.*; +import org.junit.Test; +import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; +import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.SearchKey; +import org.sleuthkit.datamodel.TskCoreException; + +public class DomainSearchCacheLoaderTest { + + @Test + public void load_GroupByDataSourceSortByGroupNameAndDomain() throws DiscoveryException, TskCoreException, SQLException { + DomainSearchCacheLoader loader = mock(DomainSearchCacheLoader.class); + List domains = Arrays.asList( + DomainSearchTestUtils.mockDomainResult("google.com", 10, 100, 5, 4, 110), + DomainSearchTestUtils.mockDomainResult("yahoo.com", 1, 5, 7, 20, 100), + DomainSearchTestUtils.mockDomainResult("google.com", 5, 20, 1, 4, 105), + DomainSearchTestUtils.mockDomainResult("facebook.com", 2, 2, 1, 3, 110), + DomainSearchTestUtils.mockDomainResult("abc.com", 1, 2, 3, 4, 100), + DomainSearchTestUtils.mockDomainResult("xyz.com", 1, 2, 3, 4, 20) + ); + + SearchKey key = new SearchKey(null, new ArrayList<>(), + new DiscoveryAttributes.DataSourceAttribute(), + Group.GroupSortingAlgorithm.BY_GROUP_NAME, + ResultsSorter.SortingMethod.BY_DOMAIN_NAME); + + when(loader.getResultDomainsFromDatabase(key)).thenReturn(domains); + when(loader.load(key)).thenCallRealMethod(); + Map> results = loader.load(key); + assertEquals(4, results.size()); + for(List group : results.values()) { + ResultDomain previous = null; + for(Result result : group) { + ResultDomain current = (ResultDomain) result; + if (previous != null) { + assertTrue(previous.getDomain().compareTo(current.getDomain()) < 0); + } + previous = current; + } + } + } + + @Test + public void load_GroupByNothingByGroupNameAndDomain() throws DiscoveryException, TskCoreException, SQLException { + DomainSearchCacheLoader loader = mock(DomainSearchCacheLoader.class); + List domains = Arrays.asList( + DomainSearchTestUtils.mockDomainResult("google.com", 10, 100, 5, 4, 110), + DomainSearchTestUtils.mockDomainResult("yahoo.com", 1, 5, 7, 20, 100), + DomainSearchTestUtils.mockDomainResult("facebook.com", 2, 2, 1, 3, 110), + DomainSearchTestUtils.mockDomainResult("abc.com", 1, 2, 3, 4, 100), + DomainSearchTestUtils.mockDomainResult("xyz.com", 1, 2, 3, 4, 20) + ); + + SearchKey key = new SearchKey(null, new ArrayList<>(), + new DiscoveryAttributes.NoGroupingAttribute(), + Group.GroupSortingAlgorithm.BY_GROUP_NAME, + ResultsSorter.SortingMethod.BY_DOMAIN_NAME); + + when(loader.getResultDomainsFromDatabase(key)).thenReturn(domains); + when(loader.load(key)).thenCallRealMethod(); + Map> results = loader.load(key); + assertEquals(1, results.size()); + for(List group : results.values()) { + ResultDomain previous = null; + for(Result result : group) { + ResultDomain current = (ResultDomain) result; + if (previous != null) { + assertTrue(previous.getDomain().compareTo(current.getDomain()) < 0); + } + previous = current; + } + } + } + + @Test + public void load_GroupByNothingSortByNameAndDataSource() throws DiscoveryException, TskCoreException, SQLException { + DomainSearchCacheLoader loader = mock(DomainSearchCacheLoader.class); + List domains = Arrays.asList( + DomainSearchTestUtils.mockDomainResult("google.com", 10, 100, 5, 4, 110), + DomainSearchTestUtils.mockDomainResult("yahoo.com", 1, 5, 7, 20, 100) + ); + + SearchKey key = new SearchKey(null, new ArrayList<>(), + new DiscoveryAttributes.NoGroupingAttribute(), + Group.GroupSortingAlgorithm.BY_GROUP_NAME, + ResultsSorter.SortingMethod.BY_DATA_SOURCE); + + when(loader.getResultDomainsFromDatabase(key)).thenReturn(domains); + when(loader.load(key)).thenCallRealMethod(); + Map> results = loader.load(key); + assertEquals(1, results.size()); + for(List group : results.values()) { + ResultDomain previous = null; + for(Result result : group) { + ResultDomain current = (ResultDomain) result; + if (previous != null) { + assertTrue(Long.compare(previous.getDataSource().getId(), current.getDataSource().getId()) < 0); + } + previous = current; + } + } + } + + @Test + public void load_GroupByDataSourceBySizeAndName() throws DiscoveryException, TskCoreException, SQLException { + DomainSearchCacheLoader loader = mock(DomainSearchCacheLoader.class); + List domains = Arrays.asList( + DomainSearchTestUtils.mockDomainResult("google.com", 10, 100, 5, 4, 110), + DomainSearchTestUtils.mockDomainResult("yahoo.com", 1, 5, 7, 20, 100) + ); + + SearchKey key = new SearchKey(null, new ArrayList<>(), + new DiscoveryAttributes.DataSourceAttribute(), + Group.GroupSortingAlgorithm.BY_GROUP_SIZE, + ResultsSorter.SortingMethod.BY_DOMAIN_NAME); + + when(loader.getResultDomainsFromDatabase(key)).thenReturn(domains); + when(loader.load(key)).thenCallRealMethod(); + Map> results = loader.load(key); + assertEquals(2, results.size()); + for(List group : results.values()) { + ResultDomain previous = null; + for(Result result : group) { + ResultDomain current = (ResultDomain) result; + if (previous != null) { + assertTrue(previous.getDomain().compareTo(current.getDomain()) < 0); + } + previous = current; + } + } + } +} diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTest.java new file mode 100755 index 0000000000..9ddd7db0bf --- /dev/null +++ b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTest.java @@ -0,0 +1,413 @@ +/* + * 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.discovery.search; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Test; + +import static org.mockito.Mockito.*; +import static org.junit.Assert.*; +import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; + +public class DomainSearchTest { + + @Test + public void groupSizes_SingleGroup_ShouldHaveSizeFour() throws DiscoveryException { + DomainSearchCache cache = mock(DomainSearchCache.class); + + DummyKey groupOne = new DummyKey("1"); + Map> dummyData = new HashMap>() { + { + put(groupOne, Arrays.asList( + DomainSearchTestUtils.mockDomainResult("google.com"), + DomainSearchTestUtils.mockDomainResult("yahoo.com"), + DomainSearchTestUtils.mockDomainResult("bing.com"), + DomainSearchTestUtils.mockDomainResult("amazon.com")) + ); + } + }; + when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); + + DomainSearch domainSearch = new DomainSearch(cache); + Map sizes = domainSearch.getGroupSizes(null, + new ArrayList<>(), null, null, null, null, null); + assertEquals(4, sizes.get(groupOne).longValue()); + } + + @Test + public void groupSizes_MultipleGroups_ShouldHaveCorrectGroupSizes() throws DiscoveryException { + DomainSearchCache cache = mock(DomainSearchCache.class); + + DummyKey groupOne = new DummyKey("1"); + DummyKey groupTwo = new DummyKey("2"); + DummyKey groupThree = new DummyKey("3"); + + Map> dummyData = new HashMap>() { + { + put(groupOne, Arrays.asList( + DomainSearchTestUtils.mockDomainResult("google.com"), + DomainSearchTestUtils.mockDomainResult("yahoo.com"), + DomainSearchTestUtils.mockDomainResult("bing.com"), + DomainSearchTestUtils.mockDomainResult("amazon.com")) + ); + put(groupTwo, Arrays.asList( + DomainSearchTestUtils.mockDomainResult("facebook.com"), + DomainSearchTestUtils.mockDomainResult("spotify.com"), + DomainSearchTestUtils.mockDomainResult("netbeans.com")) + ); + put(groupThree, Arrays.asList( + DomainSearchTestUtils.mockDomainResult("youtube.com")) + ); + } + }; + + when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); + + DomainSearch domainSearch = new DomainSearch(cache); + Map sizes = domainSearch.getGroupSizes(null, + new ArrayList<>(), null, null, null, null, null); + assertEquals(4, sizes.get(groupOne).longValue()); + assertEquals(3, sizes.get(groupTwo).longValue()); + assertEquals(1, sizes.get(groupThree).longValue()); + } + + @Test + public void groupSizes_EmptyGroup_ShouldBeSizeZero() throws DiscoveryException { + DomainSearchCache cache = mock(DomainSearchCache.class); + + when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(new HashMap<>()); + + DomainSearch domainSearch = new DomainSearch(cache); + Map sizes = domainSearch.getGroupSizes(null, + new ArrayList<>(), null, null, null, null, null); + assertEquals(0, sizes.size()); + } + + @Test + public void getDomains_SingleGroupFullPage_ShouldContainAllDomains() throws DiscoveryException { + DomainSearchCache cache = mock(DomainSearchCache.class); + + DummyKey groupOne = new DummyKey("1"); + List domains = Arrays.asList( + DomainSearchTestUtils.mockDomainResult("google.com"), + DomainSearchTestUtils.mockDomainResult("yahoo.com"), + DomainSearchTestUtils.mockDomainResult("bing.com"), + DomainSearchTestUtils.mockDomainResult("amazon.com")); + + Map> dummyData = new HashMap>() { + { + put(groupOne, domains); + } + }; + + when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); + + DomainSearch domainSearch = new DomainSearch(cache); + List firstPage = domainSearch.getDomainsInGroup(null, + new ArrayList<>(), null, null, null, groupOne, 0, 3, null, null); + assertEquals(4, firstPage.size()); + for (int i = 0; i < firstPage.size(); i++) { + assertEquals(domains.get(i), firstPage.get(i)); + } + } + + @Test + public void getDomains_SingleGroupOverSizedPage_ShouldContainAllDomains() throws DiscoveryException { + DomainSearchCache cache = mock(DomainSearchCache.class); + + DummyKey groupOne = new DummyKey("1"); + List domains = Arrays.asList( + DomainSearchTestUtils.mockDomainResult("google.com"), + DomainSearchTestUtils.mockDomainResult("yahoo.com"), + DomainSearchTestUtils.mockDomainResult("bing.com"), + DomainSearchTestUtils.mockDomainResult("amazon.com")); + + Map> dummyData = new HashMap>() { + { + put(groupOne, domains); + } + }; + + when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); + + DomainSearch domainSearch = new DomainSearch(cache); + List firstPage = domainSearch.getDomainsInGroup(null, + new ArrayList<>(), null, null, null, groupOne, 0, 100, null, null); + assertEquals(4, firstPage.size()); + for (int i = 0; i < firstPage.size(); i++) { + assertEquals(domains.get(i), firstPage.get(i)); + } + } + + @Test + public void getDomains_SingleGroupHalfPage_ShouldContainHalfDomains() throws DiscoveryException { + DomainSearchCache cache = mock(DomainSearchCache.class); + + DummyKey groupOne = new DummyKey("1"); + List domains = Arrays.asList( + DomainSearchTestUtils.mockDomainResult("google.com"), + DomainSearchTestUtils.mockDomainResult("yahoo.com"), + DomainSearchTestUtils.mockDomainResult("bing.com"), + DomainSearchTestUtils.mockDomainResult("amazon.com")); + + Map> dummyData = new HashMap>() { + { + put(groupOne, domains); + } + }; + + when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); + + DomainSearch domainSearch = new DomainSearch(cache); + List firstPage = domainSearch.getDomainsInGroup(null, + new ArrayList<>(), null, null, null, groupOne, 0, 2, null, null); + assertEquals(2, firstPage.size()); + for (int i = 0; i < firstPage.size(); i++) { + assertEquals(domains.get(i), firstPage.get(i)); + } + } + + @Test + public void getDomains_SingleGroupLastPageLastDomain_ShouldContainLastDomain() throws DiscoveryException { + DomainSearchCache cache = mock(DomainSearchCache.class); + + DummyKey groupOne = new DummyKey("1"); + List domains = Arrays.asList( + DomainSearchTestUtils.mockDomainResult("google.com"), + DomainSearchTestUtils.mockDomainResult("yahoo.com"), + DomainSearchTestUtils.mockDomainResult("bing.com"), + DomainSearchTestUtils.mockDomainResult("amazon.com")); + + Map> dummyData = new HashMap>() { + { + put(groupOne, domains); + } + }; + + when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); + + DomainSearch domainSearch = new DomainSearch(cache); + List firstPage = domainSearch.getDomainsInGroup(null, + new ArrayList<>(), null, null, null, groupOne, 3, 1, null, null); + assertEquals(1, firstPage.size()); + assertEquals(domains.get(domains.size() - 1), firstPage.get(0)); + } + + @Test + public void getDomains_SingleGroupOversizedOffset_ShouldContainNoDomains() throws DiscoveryException { + DomainSearchCache cache = mock(DomainSearchCache.class); + + DummyKey groupOne = new DummyKey("1"); + List domains = Arrays.asList( + DomainSearchTestUtils.mockDomainResult("google.com"), + DomainSearchTestUtils.mockDomainResult("yahoo.com"), + DomainSearchTestUtils.mockDomainResult("bing.com"), + DomainSearchTestUtils.mockDomainResult("amazon.com")); + + Map> dummyData = new HashMap>() { + { + put(groupOne, domains); + } + }; + + when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); + + DomainSearch domainSearch = new DomainSearch(cache); + List firstPage = domainSearch.getDomainsInGroup(null, + new ArrayList<>(), null, null, null, groupOne, 20, 5, null, null); + assertEquals(4, firstPage.size()); + for (int i = 0; i < firstPage.size(); i++) { + assertEquals(domains.get(i), firstPage.get(i)); + } + } + + @Test + public void getDomains_SingleGroupZeroSizedPage_ShouldContainNoDomains() throws DiscoveryException { + DomainSearchCache cache = mock(DomainSearchCache.class); + + DummyKey groupOne = new DummyKey("1"); + List domains = Arrays.asList( + DomainSearchTestUtils.mockDomainResult("google.com"), + DomainSearchTestUtils.mockDomainResult("yahoo.com"), + DomainSearchTestUtils.mockDomainResult("bing.com"), + DomainSearchTestUtils.mockDomainResult("amazon.com")); + + Map> dummyData = new HashMap>() { + { + put(groupOne, domains); + } + }; + + when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); + + DomainSearch domainSearch = new DomainSearch(cache); + List firstPage = domainSearch.getDomainsInGroup(null, + new ArrayList<>(), null, null, null, groupOne, 0, 0, null, null); + assertEquals(0, firstPage.size()); + } + + @Test + public void getDomains_MultipleGroupsFullPage_ShouldContainAllDomainsInGroup() throws DiscoveryException { + DomainSearchCache cache = mock(DomainSearchCache.class); + + DummyKey groupOne = new DummyKey("1"); + DummyKey groupTwo = new DummyKey("2"); + DummyKey groupThree = new DummyKey("3"); + + Map> dummyData = new HashMap>() { + { + put(groupOne, Arrays.asList( + DomainSearchTestUtils.mockDomainResult("google.com"), + DomainSearchTestUtils.mockDomainResult("yahoo.com"), + DomainSearchTestUtils.mockDomainResult("bing.com"), + DomainSearchTestUtils.mockDomainResult("amazon.com")) + ); + put(groupTwo, Arrays.asList( + DomainSearchTestUtils.mockDomainResult("facebook.com"), + DomainSearchTestUtils.mockDomainResult("spotify.com"), + DomainSearchTestUtils.mockDomainResult("netbeans.com")) + ); + put(groupThree, Arrays.asList( + DomainSearchTestUtils.mockDomainResult("youtube.com")) + ); + } + }; + + when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); + + DomainSearch domainSearch = new DomainSearch(cache); + List firstPage = domainSearch.getDomainsInGroup(null, + new ArrayList<>(), null, null, null, groupOne, 0, 3, null, null); + assertEquals(4, firstPage.size()); + } + + @Test + public void getDomains_MultipleGroupsHalfPage_ShouldContainHalfDomainsInGroup() throws DiscoveryException { + DomainSearchCache cache = mock(DomainSearchCache.class); + + DummyKey groupOne = new DummyKey("1"); + DummyKey groupTwo = new DummyKey("2"); + DummyKey groupThree = new DummyKey("3"); + + Map> dummyData = new HashMap>() { + { + put(groupOne, Arrays.asList( + DomainSearchTestUtils.mockDomainResult("google.com"), + DomainSearchTestUtils.mockDomainResult("yahoo.com"), + DomainSearchTestUtils.mockDomainResult("bing.com"), + DomainSearchTestUtils.mockDomainResult("amazon.com")) + ); + put(groupTwo, Arrays.asList( + DomainSearchTestUtils.mockDomainResult("facebook.com"), + DomainSearchTestUtils.mockDomainResult("spotify.com"), + DomainSearchTestUtils.mockDomainResult("netbeans.com")) + ); + put(groupThree, Arrays.asList( + DomainSearchTestUtils.mockDomainResult("youtube.com")) + ); + } + }; + + when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); + + DomainSearch domainSearch = new DomainSearch(cache); + List firstPage = domainSearch.getDomainsInGroup(null, + new ArrayList<>(), null, null, null, groupTwo, 1, 2, null, null); + assertEquals(2, firstPage.size()); + for (int i = 0; i < firstPage.size(); i++) { + assertEquals(dummyData.get(groupTwo).get(i + 1), firstPage.get(i)); + } + } + + @Test + public void getDomains_SingleGroupSimulatedPaging_ShouldPageThroughAllDomains() throws DiscoveryException { + DomainSearchCache cache = mock(DomainSearchCache.class); + + DummyKey groupOne = new DummyKey("1"); + List domains = Arrays.asList( + DomainSearchTestUtils.mockDomainResult("google.com"), + DomainSearchTestUtils.mockDomainResult("yahoo.com"), + DomainSearchTestUtils.mockDomainResult("bing.com"), + DomainSearchTestUtils.mockDomainResult("amazon.com"), + DomainSearchTestUtils.mockDomainResult("facebook.com"), + DomainSearchTestUtils.mockDomainResult("capitalone.com"), + DomainSearchTestUtils.mockDomainResult("spotify.com"), + DomainSearchTestUtils.mockDomainResult("netsuite.com")); + + Map> dummyData = new HashMap>() { + { + put(groupOne, domains); + } + }; + + when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); + + DomainSearch domainSearch = new DomainSearch(cache); + + int start = 0; + int size = 2; + while (start + size <= domains.size()) { + List page = domainSearch.getDomainsInGroup(null, + new ArrayList<>(), null, null, null, groupOne, start, size, null, null); + assertEquals(2, page.size()); + for(int i = 0; i < page.size(); i++) { + assertEquals(domains.get(start + i), page.get(i)); + } + + start += size; + } + } + + private class DummyKey extends GroupKey { + + private final String name; + + public DummyKey(String name) { + this.name = name; + } + + @Override + String getDisplayName() { + return name; + } + + @Override + public boolean equals(Object otherKey) { + if (otherKey instanceof GroupKey) { + return this.getDisplayName().equals(((GroupKey) otherKey).getDisplayName()); + } else { + return false; + } + } + + @Override + public int hashCode() { + return this.name.hashCode(); + } + + @Override + public int compareTo(GroupKey o) { + return this.getDisplayName().compareTo(o.getDisplayName()); + } + } +} diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTestUtils.java b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTestUtils.java new file mode 100755 index 0000000000..a0f19c17a4 --- /dev/null +++ b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTestUtils.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.discovery.search; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import org.sleuthkit.datamodel.Content; + +/** + * Mock utility methods for DomainSearchTests + */ +public class DomainSearchTestUtils { + + private DomainSearchTestUtils() { + + } + + public static ResultDomain mockDomainResult(String domain, long start, long end, + long visits, long filesDownloaded, long dataSourceId) { + Content dataSource = mockDataSource(dataSourceId); + return new ResultDomain(domain, start, end, + visits, filesDownloaded, dataSource); + } + + public static ResultDomain mockDomainResult(String domain) { + return DomainSearchTestUtils.mockDomainResult(domain, 0, 0, 0, 0, 0); + } + + public static Content mockDataSource(long dataSourceId) { + Content dataSource = mock(Content.class); + when(dataSource.getName()).thenReturn(""); + when(dataSource.getId()).thenReturn(dataSourceId); + return dataSource; + } +} From 0ef55c7f6d8cfec7801df449cde936db2c46573f Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 11 Sep 2020 10:29:01 -0400 Subject: [PATCH 043/130] 6714 make grouping and sorting attrs based on search type --- .../discovery/search/DiscoveryAttributes.java | 17 ++- .../discovery/search/ResultsSorter.java | 24 ++-- .../discovery/ui/AbstractFiltersPanel.java | 49 ++++++++ .../autopsy/discovery/ui/DiscoveryDialog.java | 112 ++++++++++++------ .../discovery/ui/DomainFilterPanel.java | 4 + 5 files changed, 156 insertions(+), 50 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java index 751b47e849..b5da230a10 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java @@ -658,12 +658,21 @@ public class DiscoveryAttributes { } /** - * Get the list of enums that are valid for grouping images. + * Get the list of enums that are valid for grouping files. * - * @return enums that can be used to group images + * @return Enums that can be used to group files. */ - public static List getOptionsForGrouping() { - return Arrays.asList(FILE_SIZE, FREQUENCY, PARENT_PATH, OBJECT_DETECTED, HASH_LIST_NAME, INTERESTING_ITEM_SET, FIRST_DATE, MOST_RECENT_DATE); + public static List getOptionsForGroupingForFiles() { + return Arrays.asList(FILE_SIZE, FREQUENCY, PARENT_PATH, OBJECT_DETECTED, HASH_LIST_NAME, INTERESTING_ITEM_SET); + } + + /** + * Get the list of enums that are valid for grouping files. + * + * @return Enums that can be used to group files. + */ + public static List getOptionsForGroupingForDomains() { + return Arrays.asList(MOST_RECENT_DATE, FIRST_DATE); } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultsSorter.java b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultsSorter.java index 27f0fcb202..d20bc4df30 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultsSorter.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultsSorter.java @@ -229,16 +229,16 @@ public class ResultsSorter implements Comparator { return compareStrings(((ResultFile) result1).getFirstInstance().getName().toLowerCase(), (((ResultFile) result2).getFirstInstance().getName().toLowerCase())); }; } - + /** * Sorts domain names in lexographical order, ignoring case. */ private static Comparator getDomainNameComparator() { return (Result domain1, Result domain2) -> { - if(domain1.getType() != SearchData.Type.DOMAIN) { + if (domain1.getType() != SearchData.Type.DOMAIN) { return 0; } - + ResultDomain first = (ResultDomain) domain1; ResultDomain second = (ResultDomain) domain2; return compareStrings(first.getDomain().toLowerCase(), second.getDomain().toLowerCase()); @@ -312,7 +312,7 @@ public class ResultsSorter implements Comparator { BY_KEYWORD_LIST_NAMES(Arrays.asList(new DiscoveryAttributes.KeywordListAttribute()), Bundle.FileSorter_SortingMethod_keywordlist_displayName()), // Sort alphabetically by list of keyword list names found BY_FULL_PATH(new ArrayList<>(), - Bundle.FileSorter_SortingMethod_fullPath_displayName()), // Sort alphabetically by path + Bundle.FileSorter_SortingMethod_fullPath_displayName()), // Sort alphabetically by path BY_DOMAIN_NAME(new ArrayList<>(), Bundle.FileSorter_SortingMethod_domain_displayName()); @@ -334,12 +334,22 @@ public class ResultsSorter implements Comparator { } /** - * Get the list of enums that are valid for ordering images. + * Get the list of enums that are valid for ordering files. * - * @return enums that can be used to ordering images. + * @return Enums that can be used to ordering files. */ - public static List getOptionsForOrdering() { + public static List getOptionsForOrderingFiles() { return Arrays.asList(BY_FILE_SIZE, BY_FULL_PATH, BY_FILE_NAME, BY_DATA_SOURCE); } + + /** + * Get the list of enums that are valid for ordering files. + * + * @return Enums that can be used to ordering files. + */ + public static List getOptionsForOrderingDomains() { + return Arrays.asList(BY_DOMAIN_NAME, BY_DATA_SOURCE); + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java index 0736708e9c..298789bf3b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java @@ -32,6 +32,9 @@ import javax.swing.JSplitPane; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import org.apache.commons.lang3.StringUtils; +import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes.GroupingAttributeType; +import org.sleuthkit.autopsy.discovery.search.Group; +import org.sleuthkit.autopsy.discovery.search.ResultsSorter.SortingMethod; import org.sleuthkit.autopsy.discovery.search.SearchData; import org.sleuthkit.autopsy.discovery.search.SearchFiltering; @@ -55,6 +58,9 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li private final JPanel secondColumnPanel = new JPanel(); private int firstColumnY = 0; private int secondColumnY = 0; + private SortingMethod lastSortingMethod = SortingMethod.BY_FILE_NAME; + private GroupingAttributeType lastGroupingAttributeType = GroupingAttributeType.PARENT_PATH; + private Group.GroupSortingAlgorithm lastGroupSortingAlg = Group.GroupSortingAlgorithm.BY_GROUP_SIZE; /** * Setup necessary for implementations of this abstract class. @@ -64,6 +70,7 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li secondColumnPanel.setLayout(new GridBagLayout()); } + /** * Get the type of results this filters panel is for. * @@ -271,4 +278,46 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li } } + /** + * @return the lastSortingMethod + */ + SortingMethod getLastSortingMethod() { + return lastSortingMethod; + } + + /** + * @param lastSortingMethod the lastSortingMethod to set + */ + final void setLastSortingMethod(SortingMethod lastSortingMethod) { + this.lastSortingMethod = lastSortingMethod; + } + + /** + * @return the lastGroupingAttributeType + */ + GroupingAttributeType getLastGroupingAttributeType() { + return lastGroupingAttributeType; + } + + /** + * @param lastGroupingAttributeType the lastGroupingAttributeType to set + */ + final void setLastGroupingAttributeType(GroupingAttributeType lastGroupingAttributeType) { + this.lastGroupingAttributeType = lastGroupingAttributeType; + } + + /** + * @return the lastGroupSortingAlg + */ + Group.GroupSortingAlgorithm getLastGroupSortingAlg() { + return lastGroupSortingAlg; + } + + /** + * @param lastGroupSortingAlg the lastGroupSortingAlg to set + */ + final void setLastGroupSortingAlg(Group.GroupSortingAlgorithm lastGroupSortingAlg) { + this.lastGroupSortingAlg = lastGroupSortingAlg; + } + } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index 474b766910..cc029c2218 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -21,6 +21,8 @@ package org.sleuthkit.autopsy.discovery.ui; import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import static java.awt.BorderLayout.CENTER; import java.awt.Color; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; @@ -37,16 +39,12 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; import org.sleuthkit.autopsy.discovery.search.Group; import org.sleuthkit.autopsy.discovery.search.Group.GroupSortingAlgorithm; -import static org.sleuthkit.autopsy.discovery.search.Group.GroupSortingAlgorithm.BY_GROUP_SIZE; import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes.GroupingAttributeType; -import static org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes.GroupingAttributeType.PARENT_PATH; import org.sleuthkit.autopsy.discovery.search.ResultsSorter; import org.sleuthkit.autopsy.discovery.search.ResultsSorter.SortingMethod; -import static org.sleuthkit.autopsy.discovery.search.ResultsSorter.SortingMethod.BY_FILE_NAME; import org.sleuthkit.autopsy.discovery.search.SearchData; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -111,12 +109,34 @@ final class DiscoveryDialog extends javax.swing.JDialog { } } }; - for (GroupSortingAlgorithm groupSortAlgorithm : GroupSortingAlgorithm.values()) { - groupSortingComboBox.addItem(groupSortAlgorithm); - } updateSearchSettings(); + groupByCombobox.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (event.getStateChange() == ItemEvent.SELECTED) { + getSelectedFilterPanel().setLastGroupingAttributeType((GroupingAttributeType) groupByCombobox.getSelectedItem()); + } + } + }); + orderByCombobox.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (event.getStateChange() == ItemEvent.SELECTED) { + getSelectedFilterPanel().setLastSortingMethod((SortingMethod) groupByCombobox.getSelectedItem()); + } + } + }); + groupSortingComboBox.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (event.getStateChange() == ItemEvent.SELECTED) { + getSelectedFilterPanel().setLastGroupSortingAlg((GroupSortingAlgorithm) groupByCombobox.getSelectedItem()); + } + } + }); Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, this.new CasePropertyChangeListener()); IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, this.new ModuleChangeListener()); + } /** @@ -140,7 +160,6 @@ final class DiscoveryDialog extends javax.swing.JDialog { add(imageFilterPanel, CENTER); imageFilterPanel.addPropertyChangeListener(listener); updateComboBoxes(); - groupSortingComboBox.setSelectedItem(BY_GROUP_SIZE); pack(); repaint(); } @@ -149,8 +168,8 @@ final class DiscoveryDialog extends javax.swing.JDialog { * Set the type buttons to a default state where none are selected. */ private void unselectAllButtons() { - imagesButton.setSelected(false); - imagesButton.setEnabled(true); + imagesButton.setSelected(false); + imagesButton.setEnabled(true); imagesButton.setBackground(UNSELECTED_COLOR); videosButton.setSelected(false); videosButton.setEnabled(true); @@ -167,20 +186,54 @@ final class DiscoveryDialog extends javax.swing.JDialog { * Private helper method to perform update of comboboxes update. */ private void updateComboBoxes() { - groupByCombobox.removeAllItems(); // Set up the grouping attributes - for (DiscoveryAttributes.GroupingAttributeType groupingType : DiscoveryAttributes.GroupingAttributeType.getOptionsForGrouping()) { + List groupingAttrs = new ArrayList<>(); + List sortingMethods = new ArrayList<>(); + groupByCombobox.removeAllItems(); + if (type == SearchData.Type.DOMAIN) { + groupingAttrs.addAll(GroupingAttributeType.getOptionsForGroupingForDomains()); + sortingMethods.addAll(SortingMethod.getOptionsForOrderingDomains()); + } else { + groupingAttrs.addAll(GroupingAttributeType.getOptionsForGroupingForFiles()); + sortingMethods.addAll(SortingMethod.getOptionsForOrderingFiles()); + } + for (GroupingAttributeType groupingType : groupingAttrs) { addTypeToGroupByComboBox(groupingType); } - groupByCombobox.setSelectedItem(PARENT_PATH); + groupByCombobox.setSelectedItem(getSelectedFilterPanel().getLastGroupingAttributeType()); orderByCombobox.removeAllItems(); // Set up the file order list - for (ResultsSorter.SortingMethod method : ResultsSorter.SortingMethod.getOptionsForOrdering()) { + for (SortingMethod method : sortingMethods) { if (method != SortingMethod.BY_FREQUENCY || CentralRepository.isEnabled()) { orderByCombobox.addItem(method); } } - orderByCombobox.setSelectedItem(BY_FILE_NAME); + orderByCombobox.setSelectedItem(getSelectedFilterPanel().getLastGroupSortingAlg()) + ); + for (GroupSortingAlgorithm groupSortAlgorithm : GroupSortingAlgorithm.values()) { + groupSortingComboBox.addItem(groupSortAlgorithm); + } + groupSortingComboBox.setSelectedItem(getSelectedFilterPanel().getLastGroupSortingAlg()); + } + + private AbstractFiltersPanel getSelectedFilterPanel() { + switch (type) { + case IMAGE: + return imageFilterPanel; + break; + case VIDEO: + return videoFilterPanel; + break; + case DOCUMENT: + return documentFilterPanel; + break; + case DOMAIN: + return domainFilterPanel; + break; + default: + return imageFilterPanel; + break; + } } /** @@ -221,29 +274,9 @@ final class DiscoveryDialog extends javax.swing.JDialog { * Validate the filter settings for File type filters. */ synchronized void validateDialog() { - switch (type) { - case IMAGE: - if (imageFilterPanel != null) { - imageFilterPanel.validateFields(); - } - break; - case VIDEO: - if (videoFilterPanel != null) { - videoFilterPanel.validateFields(); - } - break; - case DOCUMENT: - if (documentFilterPanel != null) { - documentFilterPanel.validateFields(); - } - break; - case DOMAIN: - if (domainFilterPanel != null) { - domainFilterPanel.validateFields(); - } - break; - default: - break; + AbstractFiltersPanel panel = getSelectedFilterPanel(); + if (panel != null) { + panel.validateFields(); } } @@ -554,7 +587,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.SearchStartedEvent(type)); // Get the grouping attribute and group sorting method - DiscoveryAttributes.AttributeType groupingAttr = groupByCombobox.getItemAt(groupByCombobox.getSelectedIndex()).getAttributeType(); + AttributeType groupingAttr = groupByCombobox.getItemAt(groupByCombobox.getSelectedIndex()).getAttributeType(); Group.GroupSortingAlgorithm groupSortAlgorithm = groupSortingComboBox.getItemAt(groupSortingComboBox.getSelectedIndex()); // Get the file sorting method @@ -585,6 +618,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { domainsButton.setForeground(Color.BLACK); type = SearchData.Type.DOMAIN; domainFilterPanel.addPropertyChangeListener(listener); + updateComboBoxes(); validateDialog(); pack(); repaint(); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java index 45ba72338c..cf3209146d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java @@ -19,6 +19,8 @@ package org.sleuthkit.autopsy.discovery.ui; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes; +import org.sleuthkit.autopsy.discovery.search.ResultsSorter; import org.sleuthkit.autopsy.discovery.search.SearchData; /** @@ -44,6 +46,8 @@ public class DomainFilterPanel extends AbstractFiltersPanel { } addFilter(new PastOccurrencesFilterPanel(TYPE), true, pastOccurrencesIndices, 0); addPanelsToScrollPane(domainFiltersSplitPane); + setLastGroupingAttributeType(DiscoveryAttributes.GroupingAttributeType.MOST_RECENT_DATE); + setLastSortingMethod(ResultsSorter.SortingMethod.BY_DOMAIN_NAME); } /** From 67e716f13a5ba82d0a94eaf57c997c2451604c1b Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 11 Sep 2020 10:29:54 -0400 Subject: [PATCH 044/130] 6714 add missing semi-colon --- .../src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index cc029c2218..8220643e0c 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -208,7 +208,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { orderByCombobox.addItem(method); } } - orderByCombobox.setSelectedItem(getSelectedFilterPanel().getLastGroupSortingAlg()) + orderByCombobox.setSelectedItem(getSelectedFilterPanel().getLastGroupSortingAlg()); ); for (GroupSortingAlgorithm groupSortAlgorithm : GroupSortingAlgorithm.values()) { groupSortingComboBox.addItem(groupSortAlgorithm); From 812686e81377e9e64c8cbcb0dd15daacdd4bc060 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 11 Sep 2020 10:30:25 -0400 Subject: [PATCH 045/130] 6714 remove extra symbols --- Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index 8220643e0c..18861dcc38 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -209,7 +209,6 @@ final class DiscoveryDialog extends javax.swing.JDialog { } } orderByCombobox.setSelectedItem(getSelectedFilterPanel().getLastGroupSortingAlg()); - ); for (GroupSortingAlgorithm groupSortAlgorithm : GroupSortingAlgorithm.values()) { groupSortingComboBox.addItem(groupSortAlgorithm); } From 930d603bc27f81bc05f24bf3823dc993d3bc95d7 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 11 Sep 2020 10:33:51 -0400 Subject: [PATCH 046/130] 6714-fix event name for variable --- .../org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index 18861dcc38..d4a5d25e41 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -112,7 +112,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { updateSearchSettings(); groupByCombobox.addItemListener(new ItemListener() { @Override - public void itemStateChanged(ItemEvent e) { + public void itemStateChanged(ItemEvent event) { if (event.getStateChange() == ItemEvent.SELECTED) { getSelectedFilterPanel().setLastGroupingAttributeType((GroupingAttributeType) groupByCombobox.getSelectedItem()); } @@ -120,7 +120,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { }); orderByCombobox.addItemListener(new ItemListener() { @Override - public void itemStateChanged(ItemEvent e) { + public void itemStateChanged(ItemEvent event) { if (event.getStateChange() == ItemEvent.SELECTED) { getSelectedFilterPanel().setLastSortingMethod((SortingMethod) groupByCombobox.getSelectedItem()); } @@ -128,7 +128,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { }); groupSortingComboBox.addItemListener(new ItemListener() { @Override - public void itemStateChanged(ItemEvent e) { + public void itemStateChanged(ItemEvent event) { if (event.getStateChange() == ItemEvent.SELECTED) { getSelectedFilterPanel().setLastGroupSortingAlg((GroupSortingAlgorithm) groupByCombobox.getSelectedItem()); } From 7fc5e77bab05490d46260b39dfcc7972cbb326ed Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 11 Sep 2020 10:42:03 -0400 Subject: [PATCH 047/130] 6714 fix import --- .../org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index d4a5d25e41..fd5860b7cb 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -39,6 +39,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; import org.sleuthkit.autopsy.discovery.search.Group; import org.sleuthkit.autopsy.discovery.search.Group.GroupSortingAlgorithm; @@ -586,7 +587,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.SearchStartedEvent(type)); // Get the grouping attribute and group sorting method - AttributeType groupingAttr = groupByCombobox.getItemAt(groupByCombobox.getSelectedIndex()).getAttributeType(); + DiscoveryAttributes.AttributeType groupingAttr = groupByCombobox.getItemAt(groupByCombobox.getSelectedIndex()).getAttributeType(); Group.GroupSortingAlgorithm groupSortAlgorithm = groupSortingComboBox.getItemAt(groupSortingComboBox.getSelectedIndex()); // Get the file sorting method From 0abd1dfb2740e751eedc449ad0e97e56d7680614 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 11 Sep 2020 10:43:12 -0400 Subject: [PATCH 048/130] 6714 remove unreachable breaks after returns --- .../org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index fd5860b7cb..6098045c6d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -220,19 +220,14 @@ final class DiscoveryDialog extends javax.swing.JDialog { switch (type) { case IMAGE: return imageFilterPanel; - break; case VIDEO: return videoFilterPanel; - break; case DOCUMENT: return documentFilterPanel; - break; case DOMAIN: return domainFilterPanel; - break; default: return imageFilterPanel; - break; } } From d34cc3ccafbbe2c876cd2432d97bc9ac6bf573a9 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 11 Sep 2020 11:06:34 -0400 Subject: [PATCH 049/130] 6714 fix setting previously used settings --- .../org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index 6098045c6d..b7b2ab902e 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -115,7 +115,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { @Override public void itemStateChanged(ItemEvent event) { if (event.getStateChange() == ItemEvent.SELECTED) { - getSelectedFilterPanel().setLastGroupingAttributeType((GroupingAttributeType) groupByCombobox.getSelectedItem()); + getSelectedFilterPanel().setLastGroupingAttributeType((Grouping) groupByCombobox.getSelectedItem()); } } }); @@ -123,7 +123,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { @Override public void itemStateChanged(ItemEvent event) { if (event.getStateChange() == ItemEvent.SELECTED) { - getSelectedFilterPanel().setLastSortingMethod((SortingMethod) groupByCombobox.getSelectedItem()); + getSelectedFilterPanel().setLastSortingMethod((SortingMethod) orderByCombobox.getSelectedItem()); } } }); @@ -131,7 +131,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { @Override public void itemStateChanged(ItemEvent event) { if (event.getStateChange() == ItemEvent.SELECTED) { - getSelectedFilterPanel().setLastGroupSortingAlg((GroupSortingAlgorithm) groupByCombobox.getSelectedItem()); + getSelectedFilterPanel().setLastGroupSortingAlg((GroupingAttributeType) groupSortingComboBox.getSelectedItem()); } } }); From 44c7bc934ef283074968b558e409799deae56eed Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 11 Sep 2020 11:08:08 -0400 Subject: [PATCH 050/130] 6714 fix casting --- .../org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index b7b2ab902e..0c9712d467 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -115,7 +115,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { @Override public void itemStateChanged(ItemEvent event) { if (event.getStateChange() == ItemEvent.SELECTED) { - getSelectedFilterPanel().setLastGroupingAttributeType((Grouping) groupByCombobox.getSelectedItem()); + getSelectedFilterPanel().setLastGroupingAttributeType((GroupingAttributeType) groupByCombobox.getSelectedItem()); } } }); @@ -131,7 +131,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { @Override public void itemStateChanged(ItemEvent event) { if (event.getStateChange() == ItemEvent.SELECTED) { - getSelectedFilterPanel().setLastGroupSortingAlg((GroupingAttributeType) groupSortingComboBox.getSelectedItem()); + getSelectedFilterPanel().setLastGroupSortingAlg((GroupSortingAlgorithm) groupSortingComboBox.getSelectedItem()); } } }); From 0761b8d9d280f178dd06cf3224f0c02a8e10d04d Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 11 Sep 2020 11:10:47 -0400 Subject: [PATCH 051/130] 6714 remove need for casting --- .../org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index 0c9712d467..6e5b2073cf 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -115,7 +115,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { @Override public void itemStateChanged(ItemEvent event) { if (event.getStateChange() == ItemEvent.SELECTED) { - getSelectedFilterPanel().setLastGroupingAttributeType((GroupingAttributeType) groupByCombobox.getSelectedItem()); + getSelectedFilterPanel().setLastGroupingAttributeType(groupByCombobox.getItemAt(groupByCombobox.getSelectedIndex()))); } } }); @@ -123,7 +123,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { @Override public void itemStateChanged(ItemEvent event) { if (event.getStateChange() == ItemEvent.SELECTED) { - getSelectedFilterPanel().setLastSortingMethod((SortingMethod) orderByCombobox.getSelectedItem()); + getSelectedFilterPanel().setLastSortingMethod(orderByCombobox.getItemAt(orderByCombobox.getSelectedIndex()); } } }); @@ -131,7 +131,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { @Override public void itemStateChanged(ItemEvent event) { if (event.getStateChange() == ItemEvent.SELECTED) { - getSelectedFilterPanel().setLastGroupSortingAlg((GroupSortingAlgorithm) groupSortingComboBox.getSelectedItem()); + getSelectedFilterPanel().setLastGroupSortingAlg(groupSortingComboBox.getItemAt(groupSortingComboBox.getSelectedIndex())); } } }); From 75e83325c8bb3308747096a04953ab707f886eff Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 11 Sep 2020 11:14:09 -0400 Subject: [PATCH 052/130] 6714 update settings when buttons other than Domain are selected --- .../org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index 6e5b2073cf..c83ea36fc7 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -497,6 +497,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { imagesButton.setForeground(Color.BLACK); type = SearchData.Type.IMAGE; imageFilterPanel.addPropertyChangeListener(listener); + updateComboBoxes(); validateDialog(); pack(); repaint(); @@ -512,6 +513,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { videosButton.setForeground(Color.BLACK); videoFilterPanel.addPropertyChangeListener(listener); type = SearchData.Type.VIDEO; + updateComboBoxes(); validateDialog(); pack(); repaint(); @@ -527,6 +529,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { documentsButton.setForeground(Color.BLACK); type = SearchData.Type.DOCUMENT; documentFilterPanel.addPropertyChangeListener(listener); + updateComboBoxes(); validateDialog(); pack(); repaint(); From 6db1f06410cbcc58bc39d2aef9a714efd7fd83f3 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 11 Sep 2020 11:16:08 -0400 Subject: [PATCH 053/130] 6714 remove extra parens --- .../org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index c83ea36fc7..e0a3f243b8 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -115,7 +115,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { @Override public void itemStateChanged(ItemEvent event) { if (event.getStateChange() == ItemEvent.SELECTED) { - getSelectedFilterPanel().setLastGroupingAttributeType(groupByCombobox.getItemAt(groupByCombobox.getSelectedIndex()))); + getSelectedFilterPanel().setLastGroupingAttributeType(groupByCombobox.getItemAt(groupByCombobox.getSelectedIndex())); } } }); @@ -131,7 +131,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { @Override public void itemStateChanged(ItemEvent event) { if (event.getStateChange() == ItemEvent.SELECTED) { - getSelectedFilterPanel().setLastGroupSortingAlg(groupSortingComboBox.getItemAt(groupSortingComboBox.getSelectedIndex())); + getSelectedFilterPanel().setLastGroupSortingAlg(groupSortingComboBox.getItemAt(groupSortingComboBox.getSelectedIndex()); } } }); From 0ca3f155d5fdaedb677b3bd9c5ba6b70176b1183 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 11 Sep 2020 11:17:46 -0400 Subject: [PATCH 054/130] 6714 add back parens that should of been there --- .../org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index e0a3f243b8..e3d8639c6e 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -123,7 +123,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { @Override public void itemStateChanged(ItemEvent event) { if (event.getStateChange() == ItemEvent.SELECTED) { - getSelectedFilterPanel().setLastSortingMethod(orderByCombobox.getItemAt(orderByCombobox.getSelectedIndex()); + getSelectedFilterPanel().setLastSortingMethod(orderByCombobox.getItemAt(orderByCombobox.getSelectedIndex())); } } }); @@ -131,7 +131,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { @Override public void itemStateChanged(ItemEvent event) { if (event.getStateChange() == ItemEvent.SELECTED) { - getSelectedFilterPanel().setLastGroupSortingAlg(groupSortingComboBox.getItemAt(groupSortingComboBox.getSelectedIndex()); + getSelectedFilterPanel().setLastGroupSortingAlg(groupSortingComboBox.getItemAt(groupSortingComboBox.getSelectedIndex())); } } }); From d2483bed4b40a1f09341de5a8764834034f5ff66 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 11 Sep 2020 12:13:32 -0400 Subject: [PATCH 055/130] 6714 fix preserving of previous settings --- .../discovery/search/DiscoveryAttributes.java | 2 +- .../autopsy/discovery/ui/DiscoveryDialog.java | 20 ++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java index b5da230a10..3c073c80ba 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java @@ -672,7 +672,7 @@ public class DiscoveryAttributes { * @return Enums that can be used to group files. */ public static List getOptionsForGroupingForDomains() { - return Arrays.asList(MOST_RECENT_DATE, FIRST_DATE); + return Arrays.asList(FREQUENCY, MOST_RECENT_DATE, FIRST_DATE); } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index e3d8639c6e..2c7e942538 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -31,6 +31,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Level; +import javax.swing.SwingUtilities; import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle.Messages; import org.openide.windows.WindowManager; @@ -115,7 +116,10 @@ final class DiscoveryDialog extends javax.swing.JDialog { @Override public void itemStateChanged(ItemEvent event) { if (event.getStateChange() == ItemEvent.SELECTED) { - getSelectedFilterPanel().setLastGroupingAttributeType(groupByCombobox.getItemAt(groupByCombobox.getSelectedIndex())); + SwingUtilities.invokeLater(() -> { + getSelectedFilterPanel().setLastGroupingAttributeType(groupByCombobox.getItemAt(groupByCombobox.getSelectedIndex())); + }); + } } }); @@ -123,7 +127,9 @@ final class DiscoveryDialog extends javax.swing.JDialog { @Override public void itemStateChanged(ItemEvent event) { if (event.getStateChange() == ItemEvent.SELECTED) { - getSelectedFilterPanel().setLastSortingMethod(orderByCombobox.getItemAt(orderByCombobox.getSelectedIndex())); + SwingUtilities.invokeLater(() -> { + getSelectedFilterPanel().setLastSortingMethod(orderByCombobox.getItemAt(orderByCombobox.getSelectedIndex())); + }); } } }); @@ -131,7 +137,9 @@ final class DiscoveryDialog extends javax.swing.JDialog { @Override public void itemStateChanged(ItemEvent event) { if (event.getStateChange() == ItemEvent.SELECTED) { - getSelectedFilterPanel().setLastGroupSortingAlg(groupSortingComboBox.getItemAt(groupSortingComboBox.getSelectedIndex())); + SwingUtilities.invokeLater(() -> { + getSelectedFilterPanel().setLastGroupSortingAlg(groupSortingComboBox.getItemAt(groupSortingComboBox.getSelectedIndex())); + }); } } }); @@ -210,12 +218,18 @@ final class DiscoveryDialog extends javax.swing.JDialog { } } orderByCombobox.setSelectedItem(getSelectedFilterPanel().getLastGroupSortingAlg()); + groupSortingComboBox.removeAllItems(); for (GroupSortingAlgorithm groupSortAlgorithm : GroupSortingAlgorithm.values()) { groupSortingComboBox.addItem(groupSortAlgorithm); } groupSortingComboBox.setSelectedItem(getSelectedFilterPanel().getLastGroupSortingAlg()); } + /** + * Private helper method to get the correct panel for the selected type. + * + * @return The panel that corresponds to the currently selected type. + */ private AbstractFiltersPanel getSelectedFilterPanel() { switch (type) { case IMAGE: From f3c0a1cd38eb89cd71e4cbc7a44a3ee45c9f7532 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 11 Sep 2020 12:21:44 -0400 Subject: [PATCH 056/130] 6714 clean up and fix comments in DiscoveryAttributes --- .../autopsy/discovery/search/DiscoveryAttributes.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java index 3c073c80ba..a9ebbadfb2 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java @@ -483,6 +483,9 @@ public class DiscoveryAttributes { } } + /** + * Attribute for grouping/sorting by date of most recent activity. + */ static class MostRecentActivityDateAttribute extends AttributeType { @Override @@ -492,6 +495,9 @@ public class DiscoveryAttributes { } + /** + * Attribute for grouping/sorting by date of first activity. + */ static class FirstActivityDateAttribute extends AttributeType { @Override From 67827bc5148aa2860542712fbd65c68cf24fdd63 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 11 Sep 2020 14:45:12 -0400 Subject: [PATCH 057/130] 6714 fix bug with saving sort --- Core/nbproject/project.properties | 239 ++++----- Core/nbproject/project.xml | 488 ++++++++---------- .../autopsy/discovery/ui/DiscoveryDialog.java | 2 +- 3 files changed, 325 insertions(+), 404 deletions(-) diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties index 37d8de5814..8d9c857fba 100644 --- a/Core/nbproject/project.properties +++ b/Core/nbproject/project.properties @@ -1,141 +1,118 @@ -file.reference.activemq-all-5.11.1.jar=release/modules/ext/activemq-all-5.11.1.jar -file.reference.apache-mime4j-core-0.8.2.jar=release\\modules\\ext\\apache-mime4j-core-0.8.2.jar -file.reference.apache-mime4j-dom-0.8.2.jar=release\\modules\\ext\\apache-mime4j-dom-0.8.2.jar -file.reference.asm-7.0.jar=release\\modules\\ext\\asm-7.0.jar -file.reference.batik-awt-util-1.6.jar=release/modules/ext/batik-awt-util-1.6.jar -file.reference.batik-dom-1.6.jar=release/modules/ext/batik-dom-1.6.jar -file.reference.batik-svg-dom-1.6.jar=release/modules/ext/batik-svg-dom-1.6.jar -file.reference.batik-svggen-1.6.jar=release/modules/ext/batik-svggen-1.6.jar -file.reference.batik-util-1.6.jar=release/modules/ext/batik-util-1.6.jar -file.reference.batik-xml-1.6.jar=release/modules/ext/batik-xml-1.6.jar -file.reference.bcmail-jdk15on-1.60.jar=release\\modules\\ext\\bcmail-jdk15on-1.60.jar -file.reference.bcpkix-jdk15on-1.60.jar=release\\modules\\ext\\bcpkix-jdk15on-1.60.jar -file.reference.bcprov-ext-jdk15on-1.54.jar=release/modules/ext/bcprov-ext-jdk15on-1.54.jar -file.reference.bcprov-jdk15on-1.60.jar=release\\modules\\ext\\bcprov-jdk15on-1.60.jar -file.reference.boilerpipe-1.1.0.jar=release\\modules\\ext\\boilerpipe-1.1.0.jar -file.reference.byte-buddy-1.10.13.jar=release\\modules\\ext\\byte-buddy-1.10.13.jar -file.reference.byte-buddy-agent-1.10.13.jar=release\\modules\\ext\\byte-buddy-agent-1.10.13.jar -file.reference.c3p0-0.9.5.jar=release/modules/ext/c3p0-0.9.5.jar -file.reference.cdm-4.5.5.jar=release\\modules\\ext\\cdm-4.5.5.jar +file.reference.activemq-all-5.11.1.jar=release\\modules\\ext\\activemq-all-5.11.1.jar +file.reference.animal-sniffer-annotations-1.17.jar=release\\modules\\ext\\animal-sniffer-annotations-1.17.jar +file.reference.api-common-1.7.0.jar=release\\modules\\ext\\api-common-1.7.0.jar +file.reference.batik-awt-util-1.6.jar=release\\modules\\ext\\batik-awt-util-1.6.jar +file.reference.batik-dom-1.6.jar=release\\modules\\ext\\batik-dom-1.6.jar +file.reference.batik-svg-dom-1.6.jar=release\\modules\\ext\\batik-svg-dom-1.6.jar +file.reference.batik-svggen-1.6.jar=release\\modules\\ext\\batik-svggen-1.6.jar +file.reference.batik-util-1.6.jar=release\\modules\\ext\\batik-util-1.6.jar +file.reference.batik-xml-1.6.jar=release\\modules\\ext\\batik-xml-1.6.jar +file.reference.bcpkix-jdk15on-1.54.jar=release\\modules\\ext\\bcpkix-jdk15on-1.54.jar +file.reference.bcprov-ext-jdk15on-1.54.jar=release\\modules\\ext\\bcprov-ext-jdk15on-1.54.jar +file.reference.bcprov-jdk15on-1.52.jar=release\\modules\\ext\\bcprov-jdk15on-1.52.jar +file.reference.bcprov-jdk15on-1.54.jar=release\\modules\\ext\\bcprov-jdk15on-1.54.jar +file.reference.c3p0-0.9.5.jar=release\\modules\\ext\\c3p0-0.9.5.jar +file.reference.checker-compat-qual-2.5.3.jar=release\\modules\\ext\\checker-compat-qual-2.5.3.jar +file.reference.commons-beanutils-1.9.2.jar=release\\modules\\ext\\commons-beanutils-1.9.2.jar file.reference.commons-codec-1.11.jar=release\\modules\\ext\\commons-codec-1.11.jar -file.reference.commons-collections4-4.2.jar=release\\modules\\ext\\commons-collections4-4.2.jar -file.reference.commons-csv-1.6.jar=release\\modules\\ext\\commons-csv-1.6.jar -file.reference.commons-dbcp2-2.1.1.jar=release/modules/ext/commons-dbcp2-2.1.1.jar -file.reference.commons-exec-1.3.jar=release\\modules\\ext\\commons-exec-1.3.jar -file.reference.commons-io-2.6.jar=release\\modules\\ext\\commons-io-2.6.jar -file.reference.commons-lang3-3.8.1.jar=release\\modules\\ext\\commons-lang3-3.8.1.jar -file.reference.commons-pool2-2.4.2.jar=release/modules/ext/commons-pool2-2.4.2.jar -file.reference.cxf-rt-rs-client-3.3.0.jar=release\\modules\\ext\\cxf-rt-rs-client-3.3.0.jar -file.reference.DatCon.jar=release/modules/ext/DatCon.jar -file.reference.dec-0.1.2.jar=release\\modules\\ext\\dec-0.1.2.jar -file.reference.decodetect-core-0.3.jar=release/modules/ext/decodetect-core-0.3.jar -file.reference.fontbox-2.0.13.jar=release\\modules\\ext\\fontbox-2.0.13.jar -file.reference.geoapi-3.0.1.jar=release\\modules\\ext\\geoapi-3.0.1.jar -file.reference.grib-4.5.5.jar=release\\modules\\ext\\grib-4.5.5.jar -file.reference.httpclient-4.5.6.jar=release\\modules\\ext\\httpclient-4.5.6.jar -file.reference.httpmime-4.5.6.jar=release\\modules\\ext\\httpmime-4.5.6.jar -file.reference.httpservices-4.5.5.jar=release\\modules\\ext\\httpservices-4.5.5.jar -file.reference.icepdf-core-6.2.2.jar=release/modules/ext/icepdf-core-6.2.2.jar -file.reference.icepdf-viewer-6.2.2.jar=release/modules/ext/icepdf-viewer-6.2.2.jar -file.reference.isoparser-1.1.22.jar=release\\modules\\ext\\isoparser-1.1.22.jar +file.reference.commons-collections-3.2.2.jar=release\\modules\\ext\\commons-collections-3.2.2.jar +file.reference.commons-dbcp2-2.1.1.jar=release\\modules\\ext\\commons-dbcp2-2.1.1.jar +file.reference.commons-digester-1.8.1.jar=release\\modules\\ext\\commons-digester-1.8.1.jar +file.reference.commons-lang-2.6.jar=release\\modules\\ext\\commons-lang-2.6.jar +file.reference.commons-lang3-3.5.jar=release\\modules\\ext\\commons-lang3-3.5.jar +file.reference.commons-logging-1.2.jar=release\\modules\\ext\\commons-logging-1.2.jar +file.reference.commons-pool2-2.4.2.jar=release\\modules\\ext\\commons-pool2-2.4.2.jar +file.reference.commons-validator-1.6.jar=release\\modules\\ext\\commons-validator-1.6.jar +file.reference.curator-client-2.8.0.jar=release\\modules\\ext\\curator-client-2.8.0.jar +file.reference.curator-framework-2.8.0.jar=release\\modules\\ext\\curator-framework-2.8.0.jar +file.reference.curator-recipes-2.8.0.jar=release\\modules\\ext\\curator-recipes-2.8.0.jar +file.reference.DatCon.jar=release\\modules\\ext\\DatCon.jar +file.reference.decodetect-core-0.3.jar=release\\modules\\ext\\decodetect-core-0.3.jar +file.reference.error_prone_annotations-2.3.2.jar=release\\modules\\ext\\error_prone_annotations-2.3.2.jar +file.reference.failureaccess-1.0.1.jar=release\\modules\\ext\\failureaccess-1.0.1.jar +file.reference.gax-1.44.0.jar=release\\modules\\ext\\gax-1.44.0.jar +file.reference.gax-grpc-1.44.0.jar=release\\modules\\ext\\gax-grpc-1.44.0.jar +file.reference.gax-httpjson-0.61.0.jar=release\\modules\\ext\\gax-httpjson-0.61.0.jar +file.reference.google-api-client-1.27.0.jar=release\\modules\\ext\\google-api-client-1.27.0.jar +file.reference.google-api-services-translate-v2-rev20170525-1.27.0.jar=release\\modules\\ext\\google-api-services-translate-v2-rev20170525-1.27.0.jar +file.reference.google-auth-library-credentials-0.15.0.jar=release\\modules\\ext\\google-auth-library-credentials-0.15.0.jar +file.reference.google-auth-library-oauth2-http-0.15.0.jar=release\\modules\\ext\\google-auth-library-oauth2-http-0.15.0.jar +file.reference.google-cloud-core-1.70.0.jar=release\\modules\\ext\\google-cloud-core-1.70.0.jar +file.reference.google-cloud-core-grpc-1.70.0.jar=release\\modules\\ext\\google-cloud-core-grpc-1.70.0.jar +file.reference.google-cloud-core-http-1.70.0.jar=release\\modules\\ext\\google-cloud-core-http-1.70.0.jar +file.reference.google-cloud-translate-1.70.0.jar=release\\modules\\ext\\google-cloud-translate-1.70.0.jar +file.reference.google-http-client-1.29.0.jar=release\\modules\\ext\\google-http-client-1.29.0.jar +file.reference.google-http-client-appengine-1.29.0.jar=release\\modules\\ext\\google-http-client-appengine-1.29.0.jar +file.reference.google-http-client-jackson2-1.29.0.jar=release\\modules\\ext\\google-http-client-jackson2-1.29.0.jar +file.reference.google-oauth-client-1.28.0.jar=release\\modules\\ext\\google-oauth-client-1.28.0.jar +file.reference.grpc-alts-1.19.0.jar=release\\modules\\ext\\grpc-alts-1.19.0.jar +file.reference.grpc-auth-1.19.0.jar=release\\modules\\ext\\grpc-auth-1.19.0.jar +file.reference.grpc-context-1.19.0.jar=release\\modules\\ext\\grpc-context-1.19.0.jar +file.reference.grpc-core-1.19.0.jar=release\\modules\\ext\\grpc-core-1.19.0.jar +file.reference.grpc-grpclb-1.19.0.jar=release\\modules\\ext\\grpc-grpclb-1.19.0.jar +file.reference.grpc-netty-shaded-1.19.0.jar=release\\modules\\ext\\grpc-netty-shaded-1.19.0.jar +file.reference.grpc-protobuf-1.19.0.jar=release\\modules\\ext\\grpc-protobuf-1.19.0.jar +file.reference.grpc-protobuf-lite-1.19.0.jar=release\\modules\\ext\\grpc-protobuf-lite-1.19.0.jar +file.reference.grpc-stub-1.19.0.jar=release\\modules\\ext\\grpc-stub-1.19.0.jar +file.reference.gson-2.7.jar=release\\modules\\ext\\gson-2.7.jar +file.reference.guava-27.1-android.jar=release\\modules\\ext\\guava-27.1-android.jar +file.reference.httpclient-4.5.5.jar=release\\modules\\ext\\httpclient-4.5.5.jar +file.reference.httpcore-4.4.9.jar=release\\modules\\ext\\httpcore-4.4.9.jar +file.reference.icepdf-core-6.2.2.jar=release\\modules\\ext\\icepdf-core-6.2.2.jar +file.reference.icepdf-viewer-6.2.2.jar=release\\modules\\ext\\icepdf-viewer-6.2.2.jar +file.reference.j2objc-annotations-1.1.jar=release\\modules\\ext\\j2objc-annotations-1.1.jar file.reference.jackcess-2.2.0.jar=release\\modules\\ext\\jackcess-2.2.0.jar file.reference.jackcess-encrypt-2.1.4.jar=release\\modules\\ext\\jackcess-encrypt-2.1.4.jar -file.reference.jackson-annotations-2.9.7.jar=release\\modules\\ext\\jackson-annotations-2.9.7.jar +file.reference.jackson-annotations-2.9.0.jar=release\\modules\\ext\\jackson-annotations-2.9.0.jar file.reference.jackson-core-2.9.7.jar=release\\modules\\ext\\jackson-core-2.9.7.jar file.reference.jackson-databind-2.9.7.jar=release\\modules\\ext\\jackson-databind-2.9.7.jar -file.reference.jai-imageio-core-1.4.0.jar=release\\modules\\ext\\jai-imageio-core-1.4.0.jar -file.reference.jai_core-1.1.3.jar=release/modules/ext/jai_core-1.1.3.jar -file.reference.jai_imageio-1.1.jar=release/modules/ext/jai_imageio-1.1.jar -file.reference.java-libpst-0.8.1.jar=release\\modules\\ext\\java-libpst-0.8.1.jar -file.reference.javax.activation-1.2.0.jar=release\\modules\\ext\\javax.activation-1.2.0.jar +file.reference.jai_core-1.1.3.jar=release\\modules\\ext\\jai_core-1.1.3.jar +file.reference.jai_imageio-1.1.jar=release\\modules\\ext\\jai_imageio-1.1.jar file.reference.javax.annotation-api-1.3.2.jar=release\\modules\\ext\\javax.annotation-api-1.3.2.jar -file.reference.jbig2-imageio-3.0.2.jar=release\\modules\\ext\\jbig2-imageio-3.0.2.jar -file.reference.jcl-over-slf4j-1.7.25.jar=release\\modules\\ext\\jcl-over-slf4j-1.7.25.jar -file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar -file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar -file.reference.jdom2-2.0.6.jar=release\\modules\\ext\\jdom2-2.0.6.jar -file.reference.jempbox-1.8.16.jar=release\\modules\\ext\\jempbox-1.8.16.jar -file.reference.jericho-html-3.3.jar=release/modules/ext/jericho-html-3.3.jar -file.reference.jgraphx-4.1.0.jar=release/modules/ext/jgraphx-4.1.0.jar -file.reference.jhighlight-1.0.3.jar=release\\modules\\ext\\jhighlight-1.0.3.jar -file.reference.jmatio-1.5.jar=release\\modules\\ext\\jmatio-1.5.jar -file.reference.json-simple-1.1.1.jar=release\\modules\\ext\\json-simple-1.1.1.jar -file.reference.jsoup-1.11.3.jar=release\\modules\\ext\\jsoup-1.11.3.jar -file.reference.jul-to-slf4j-1.7.25.jar=release\\modules\\ext\\jul-to-slf4j-1.7.25.jar -file.reference.juniversalchardet-1.0.3.jar=release\\modules\\ext\\juniversalchardet-1.0.3.jar -file.reference.junrar-2.0.0.jar=release\\modules\\ext\\junrar-2.0.0.jar -file.reference.jutf7-1.0.0.jar=release/modules/ext/jutf7-1.0.0.jar -file.reference.jxmapviewer2-2.4.jar=release/modules/ext/jxmapviewer2-2.4.jar -file.reference.jython-standalone-2.7.0.jar=release/modules/ext/jython-standalone-2.7.0.jar -file.reference.libphonenumber-3.5.jar=release/modules/ext/libphonenumber-3.5.jar -file.reference.mchange-commons-java-0.2.9.jar=release/modules/ext/mchange-commons-java-0.2.9.jar +file.reference.javax.ws.rs-api-2.0.jar=release\\modules\\ext\\javax.ws.rs-api-2.0.jar +file.reference.jdom-2.0.5-contrib.jar=release\\modules\\ext\\jdom-2.0.5-contrib.jar +file.reference.jdom-2.0.5.jar=release\\modules\\ext\\jdom-2.0.5.jar +file.reference.jericho-html-3.3.jar=release\\modules\\ext\\jericho-html-3.3.jar +file.reference.jgraphx-4.1.0.jar=release\\modules\\ext\\jgraphx-4.1.0.jar +file.reference.jline-0.9.94.jar=release\\modules\\ext\\jline-0.9.94.jar +file.reference.jsoup-1.10.3.jar=release\\modules\\ext\\jsoup-1.10.3.jar +file.reference.jsr305-3.0.2.jar=release\\modules\\ext\\jsr305-3.0.2.jar +file.reference.junit-3.8.1.jar=release\\modules\\ext\\junit-3.8.1.jar +file.reference.jutf7-1.0.0.jar=release\\modules\\ext\\jutf7-1.0.0.jar +file.reference.jxmapviewer2-2.4.jar=release\\modules\\ext\\jxmapviewer2-2.4.jar +file.reference.jython-standalone-2.7.0.jar=release\\modules\\ext\\jython-standalone-2.7.0.jar +file.reference.libphonenumber-3.5.jar=release\\modules\\ext\\libphonenumber-3.5.jar +file.reference.listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar=release\\modules\\ext\\listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar +file.reference.log4j-1.2.16.jar=release\\modules\\ext\\log4j-1.2.16.jar +file.reference.mchange-commons-java-0.2.9.jar=release\\modules\\ext\\mchange-commons-java-0.2.9.jar file.reference.metadata-extractor-2.11.0.jar=release\\modules\\ext\\metadata-extractor-2.11.0.jar -file.reference.mockito-core-3.5.7.jar=release\\modules\\ext\\mockito-core-3.5.7.jar -file.reference.netcdf4-4.5.5.jar=release\\modules\\ext\\netcdf4-4.5.5.jar -file.reference.objenesis-3.1.jar=release\\modules\\ext\\objenesis-3.1.jar -file.reference.openjson-1.0.10.jar=release\\modules\\ext\\openjson-1.0.10.jar +file.reference.netty-3.7.0.Final.jar=release\\modules\\ext\\netty-3.7.0.Final.jar +file.reference.okhttp-2.7.5.jar=release\\modules\\ext\\okhttp-2.7.5.jar +file.reference.okio-1.6.0.jar=release\\modules\\ext\\okio-1.6.0.jar +file.reference.opencensus-api-0.19.2.jar=release\\modules\\ext\\opencensus-api-0.19.2.jar +file.reference.opencensus-contrib-grpc-metrics-0.19.2.jar=release\\modules\\ext\\opencensus-contrib-grpc-metrics-0.19.2.jar +file.reference.opencensus-contrib-http-util-0.19.2.jar=release\\modules\\ext\\opencensus-contrib-http-util-0.19.2.jar file.reference.opennlp-tools-1.9.1.jar=release\\modules\\ext\\opennlp-tools-1.9.1.jar -file.reference.parso-2.0.10.jar=release\\modules\\ext\\parso-2.0.10.jar -file.reference.pdfbox-2.0.13.jar=release\\modules\\ext\\pdfbox-2.0.13.jar -file.reference.pdfbox-tools-2.0.13.jar=release\\modules\\ext\\pdfbox-tools-2.0.13.jar -file.reference.postgresql-9.4.1211.jre7.jar=release/modules/ext/postgresql-9.4.1211.jre7.jar -file.reference.Rejistry-1.1-SNAPSHOT.jar=release/modules/ext/Rejistry-1.1-SNAPSHOT.jar -file.reference.rome-1.12.0.jar=release\\modules\\ext\\rome-1.12.0.jar -file.reference.sentiment-analysis-parser-0.1.jar=release\\modules\\ext\\sentiment-analysis-parser-0.1.jar -file.reference.sevenzipjbinding-AllPlatforms.jar=release/modules/ext/sevenzipjbinding-AllPlatforms.jar -file.reference.sevenzipjbinding.jar=release/modules/ext/sevenzipjbinding.jar -file.reference.sis-metadata-0.8.jar=release\\modules\\ext\\sis-metadata-0.8.jar -file.reference.sis-netcdf-0.8.jar=release\\modules\\ext\\sis-netcdf-0.8.jar -file.reference.sis-utility-0.8.jar=release\\modules\\ext\\sis-utility-0.8.jar -file.reference.sleuthkit-caseuco-4.10.0.jar=release/modules/ext/sleuthkit-caseuco-4.10.0.jar -file.reference.slf4j-api-1.7.25.jar=release\\modules\\ext\\slf4j-api-1.7.25.jar -file.reference.sqlite-jdbc-3.25.2.jar=release/modules/ext/sqlite-jdbc-3.25.2.jar -file.reference.StixLib.jar=release/modules/ext/StixLib.jar -file.reference.javax.ws.rs-api-2.0.1.jar=release/modules/ext/javax.ws.rs-api-2.0.1.jar -file.reference.cxf-core-3.0.16.jar=release/modules/ext/cxf-core-3.0.16.jar -file.reference.cxf-rt-frontend-jaxrs-3.0.16.jar=release/modules/ext/cxf-rt-frontend-jaxrs-3.0.16.jar -file.reference.cxf-rt-transports-http-3.0.16.jar=release/modules/ext/cxf-rt-transports-http-3.0.16.jar -file.reference.sleuthkit-4.10.0.jar=release/modules/ext/sleuthkit-4.10.0.jar -file.reference.curator-client-2.8.0.jar=release/modules/ext/curator-client-2.8.0.jar -file.reference.curator-framework-2.8.0.jar=release/modules/ext/curator-framework-2.8.0.jar -file.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0.jar -file.reference.tagsoup-1.2.1.jar=release\\modules\\ext\\tagsoup-1.2.1.jar -file.reference.tika-core-1.20.jar=release\\modules\\ext\\tika-core-1.20.jar -file.reference.tika-parsers-1.20.jar=release\\modules\\ext\\tika-parsers-1.20.jar -file.reference.uimafit-core-2.4.0.jar=release\\modules\\ext\\uimafit-core-2.4.0.jar -file.reference.uimaj-core-3.0.1.jar=release\\modules\\ext\\uimaj-core-3.0.1.jar -file.reference.vorbis-java-core-0.8.jar=release\\modules\\ext\\vorbis-java-core-0.8.jar -file.reference.vorbis-java-tika-0.8.jar=release\\modules\\ext\\vorbis-java-tika-0.8.jar -file.reference.webp-imageio-sejda-0.1.0.jar=release/modules/ext/webp-imageio-sejda-0.1.0.jar -file.reference.xmlbeans-3.0.2.jar=release\\modules\\ext\\xmlbeans-3.0.2.jar -file.reference.xmpcore-5.1.3.jar=release/modules/ext/xmpcore-5.1.3.jar -file.reference.xz-1.8.jar=release\\modules\\ext\\xz-1.8.jar -file.reference.zookeeper-3.4.6.jar=release/modules/ext/zookeeper-3.4.6.jar -file.reference.SparseBitSet-1.1.jar=release/modules/ext/SparseBitSet-1.1.jar -file.reference.commons-validator-1.6.jar=release/modules/ext/commons-validator-1.6.jar -file.reference.api-common-1.7.0.jar=release/modules/ext/api-common-1.7.0.jar -file.reference.gax-1.44.0.jar=release/modules/ext/gax-1.44.0.jar -file.reference.gax-grpc-1.44.0.jar=release/modules/ext/gax-grpc-1.44.0.jar -file.reference.gax-httpjson-0.61.0.jar=release/modules/ext/gax-httpjson-0.61.0.jar -file.reference.google-api-client-1.27.0.jar=release/modules/ext/google-api-client-1.27.0.jar -file.reference.google-api-services-translate-v2-rev20170525-1.27.0.jar=release/modules/ext/google-api-services-translate-v2-rev20170525-1.27.0.jar -file.reference.google-auth-library-credentials-0.15.0.jar=release/modules/ext/google-auth-library-credentials-0.15.0.jar -file.reference.google-auth-library-oauth2-http-0.15.0.jar=release/modules/ext/google-auth-library-oauth2-http-0.15.0.jar -file.reference.google-cloud-core-1.70.0.jar=release/modules/ext/google-cloud-core-1.70.0.jar -file.reference.google-cloud-core-http-1.70.0.jar=release/modules/ext/google-cloud-core-http-1.70.0.jar -file.reference.google-cloud-translate-1.70.0.jar=release/modules/ext/google-cloud-translate-1.70.0.jar -file.reference.google-http-client-1.29.0.jar=release/modules/ext/google-http-client-1.29.0.jar -file.reference.google-http-client-appengine-1.29.0.jar=release/modules/ext/google-http-client-appengine-1.29.0.jar -file.reference.google-http-client-jackson2-1.29.0.jar=release/modules/ext/google-http-client-jackson2-1.29.0.jar -file.reference.grpc-context-1.19.0.jar=release/modules/ext/grpc-context-1.19.0.jar -file.reference.opencensus-api-0.19.2.jar=release/modules/ext/opencensus-api-0.19.2.jar -file.reference.opencensus-contrib-http-util-0.19.2.jar=release/modules/ext/opencensus-contrib-http-util-0.19.2.jar -file.reference.threetenbp-1.3.3.jar=release/modules/ext/threetenbp-1.3.3.jar -file.reference.okhttp-2.7.5-javadoc.jar=release/modules/ext/okhttp-2.7.5-javadoc.jar -file.reference.okhttp-2.7.5-sources.jar=release/modules/ext/okhttp-2.7.5-sources.jar -file.reference.okhttp-2.7.5.jar=release/modules/ext/okhttp-2.7.5.jar -file.reference.okio-1.6.0.jar=release/modules/ext/okio-1.6.0.jar -file.reference.datcon.jar=release/modules/ext/DatCon.jar +file.reference.postgresql-9.4.1211.jre7.jar=release\\modules\\ext\\postgresql-9.4.1211.jre7.jar +file.reference.proto-google-cloud-translate-v3beta1-0.53.0.jar=release\\modules\\ext\\proto-google-cloud-translate-v3beta1-0.53.0.jar +file.reference.proto-google-common-protos-1.15.0.jar=release\\modules\\ext\\proto-google-common-protos-1.15.0.jar +file.reference.proto-google-iam-v1-0.12.0.jar=release\\modules\\ext\\proto-google-iam-v1-0.12.0.jar +file.reference.protobuf-java-3.7.0.jar=release\\modules\\ext\\protobuf-java-3.7.0.jar +file.reference.protobuf-java-util-3.7.0.jar=release\\modules\\ext\\protobuf-java-util-3.7.0.jar +file.reference.Rejistry-1.1-SNAPSHOT.jar=release\\modules\\ext\\Rejistry-1.1-SNAPSHOT.jar +file.reference.sevenzipjbinding-AllPlatforms.jar=release\\modules\\ext\\sevenzipjbinding-AllPlatforms.jar +file.reference.sevenzipjbinding.jar=release\\modules\\ext\\sevenzipjbinding.jar +file.reference.sleuthkit-4.10.0.jar=release\\modules\\ext\\sleuthkit-4.10.0.jar +file.reference.sleuthkit-caseuco-4.10.0.jar=release\\modules\\ext\\sleuthkit-caseuco-4.10.0.jar +file.reference.slf4j-api-1.7.6.jar=release\\modules\\ext\\slf4j-api-1.7.6.jar +file.reference.slf4j-log4j12-1.7.6.jar=release\\modules\\ext\\slf4j-log4j12-1.7.6.jar +file.reference.SparseBitSet-1.1.jar=release\\modules\\ext\\SparseBitSet-1.1.jar +file.reference.sqlite-jdbc-3.25.2.jar=release\\modules\\ext\\sqlite-jdbc-3.25.2.jar +file.reference.StixLib.jar=release\\modules\\ext\\StixLib.jar +file.reference.threetenbp-1.3.3.jar=release\\modules\\ext\\threetenbp-1.3.3.jar +file.reference.webp-imageio-sejda-0.1.0.jar=release\\modules\\ext\\webp-imageio-sejda-0.1.0.jar +file.reference.xmpcore-5.1.3.jar=release\\modules\\ext\\xmpcore-5.1.3.jar +file.reference.zookeeper-3.4.6.jar=release\\modules\\ext\\zookeeper-3.4.6.jar javac.source=1.8 javac.compilerargs=-Xlint -Xlint:-serial license.file=../LICENSE-2.0.txt @@ -143,5 +120,5 @@ nbm.homepage=http://www.sleuthkit.org/ nbm.module.author=Brian Carrier nbm.needs.restart=true source.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0-sources.jar -spec.version.base=10.20 +spec.version.base=10.21 diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 5abd3666b7..19c863e6b7 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -6,24 +6,6 @@ org.sleuthkit.autopsy.core - - org.jdesktop.beansbinding - - - - 1 - 1.27.1.121 - - - - org.jdesktop.layout - - - - 1 - 1.33.1 - - org.netbeans.api.progress @@ -245,6 +227,14 @@ 6.55.1 + + org.sleuthkit.autopsy.Tika + + + + 1.0 + + org.sleuthkit.autopsy.corelibs @@ -309,8 +299,6 @@ net.sf.sevenzipjbinding.impl net.sf.sevenzipjbinding.simple net.sf.sevenzipjbinding.simple.impl - org.apache.tika - org.apache.tika.io org.sleuthkit.autopsy.actions org.sleuthkit.autopsy.appservices org.sleuthkit.autopsy.casemodule @@ -352,104 +340,88 @@ org.sleuthkit.datamodel.blackboardutils.attributes - ext/commons-lang3-3.8.1.jar - release\modules\ext\commons-lang3-3.8.1.jar + ext/batik-xml-1.6.jar + release\modules\ext\batik-xml-1.6.jar - ext/batik-xml-1.6.jar - release/modules/ext/batik-xml-1.6.jar + ext/commons-digester-1.8.1.jar + release\modules\ext\commons-digester-1.8.1.jar ext/jai_core-1.1.3.jar - release/modules/ext/jai_core-1.1.3.jar + release\modules\ext\jai_core-1.1.3.jar ext/gax-grpc-1.44.0.jar - release/modules/ext/gax-grpc-1.44.0.jar + release\modules\ext\gax-grpc-1.44.0.jar - ext/cdm-4.5.5.jar - release\modules\ext\cdm-4.5.5.jar + ext/failureaccess-1.0.1.jar + release\modules\ext\failureaccess-1.0.1.jar - ext/sis-utility-0.8.jar - release\modules\ext\sis-utility-0.8.jar + ext/grpc-protobuf-1.19.0.jar + release\modules\ext\grpc-protobuf-1.19.0.jar ext/opencensus-api-0.19.2.jar - release/modules/ext/opencensus-api-0.19.2.jar + release\modules\ext\opencensus-api-0.19.2.jar ext/batik-svg-dom-1.6.jar - release/modules/ext/batik-svg-dom-1.6.jar + release\modules\ext\batik-svg-dom-1.6.jar ext/gax-httpjson-0.61.0.jar - release/modules/ext/gax-httpjson-0.61.0.jar - - - ext/boilerpipe-1.1.0.jar - release\modules\ext\boilerpipe-1.1.0.jar - - - ext/jsoup-1.11.3.jar - release\modules\ext\jsoup-1.11.3.jar + release\modules\ext\gax-httpjson-0.61.0.jar ext/sevenzipjbinding.jar - release/modules/ext/sevenzipjbinding.jar + release\modules\ext\sevenzipjbinding.jar ext/mchange-commons-java-0.2.9.jar - release/modules/ext/mchange-commons-java-0.2.9.jar + release\modules\ext\mchange-commons-java-0.2.9.jar + + + ext/api-common-1.7.0.jar + release\modules\ext\api-common-1.7.0.jar ext/jackson-databind-2.9.7.jar release\modules\ext\jackson-databind-2.9.7.jar - - ext/jai-imageio-core-1.4.0.jar - release\modules\ext\jai-imageio-core-1.4.0.jar - - - ext/api-common-1.7.0.jar - release/modules/ext/api-common-1.7.0.jar - - - ext/jcl-over-slf4j-1.7.25.jar - release\modules\ext\jcl-over-slf4j-1.7.25.jar - ext/okhttp-2.7.5.jar - release/modules/ext/okhttp-2.7.5.jar + release\modules\ext\okhttp-2.7.5.jar - ext/byte-buddy-1.10.13.jar - release\modules\ext\byte-buddy-1.10.13.jar + ext/proto-google-cloud-translate-v3beta1-0.53.0.jar + release\modules\ext\proto-google-cloud-translate-v3beta1-0.53.0.jar + + + ext/error_prone_annotations-2.3.2.jar + release\modules\ext\error_prone_annotations-2.3.2.jar ext/libphonenumber-3.5.jar - release/modules/ext/libphonenumber-3.5.jar - - - ext/tika-core-1.20.jar - release\modules\ext\tika-core-1.20.jar + release\modules\ext\libphonenumber-3.5.jar ext/StixLib.jar - release/modules/ext/StixLib.jar - - - ext/bcprov-jdk15on-1.60.jar - release\modules\ext\bcprov-jdk15on-1.60.jar + release\modules\ext\StixLib.jar ext/google-auth-library-credentials-0.15.0.jar - release/modules/ext/google-auth-library-credentials-0.15.0.jar + release\modules\ext\google-auth-library-credentials-0.15.0.jar - ext/json-simple-1.1.1.jar - release\modules\ext\json-simple-1.1.1.jar + ext/grpc-auth-1.19.0.jar + release\modules\ext\grpc-auth-1.19.0.jar + + + ext/j2objc-annotations-1.1.jar + release\modules\ext\j2objc-annotations-1.1.jar ext/metadata-extractor-2.11.0.jar @@ -459,157 +431,137 @@ ext/commons-codec-1.11.jar release\modules\ext\commons-codec-1.11.jar - - ext/jmatio-1.5.jar - release\modules\ext\jmatio-1.5.jar - - - ext/tika-parsers-1.20.jar - release\modules\ext\tika-parsers-1.20.jar - - - ext/asm-7.0.jar - release\modules\ext\asm-7.0.jar - ext/commons-pool2-2.4.2.jar - release/modules/ext/commons-pool2-2.4.2.jar + release\modules\ext\commons-pool2-2.4.2.jar ext/jxmapviewer2-2.4.jar - release/modules/ext/jxmapviewer2-2.4.jar + release\modules\ext\jxmapviewer2-2.4.jar + + + ext/jfreechart-1.0.19.jar + release/modules/ext/jfreechart-1.0.19.jar + + + ext/jcommon-1.0.23.jar + release/modules/ext/jcommon-1.0.23.jar ext/jdom-2.0.5-contrib.jar - release/modules/ext/jdom-2.0.5-contrib.jar - - - ext/openjson-1.0.10.jar - release\modules\ext\openjson-1.0.10.jar - - - ext/isoparser-1.1.22.jar - release\modules\ext\isoparser-1.1.22.jar + release\modules\ext\jdom-2.0.5-contrib.jar ext/xmpcore-5.1.3.jar - release/modules/ext/xmpcore-5.1.3.jar + release\modules\ext\xmpcore-5.1.3.jar ext/batik-util-1.6.jar - release/modules/ext/batik-util-1.6.jar - - - ext/javax.activation-1.2.0.jar - release\modules\ext\javax.activation-1.2.0.jar - - - ext/rome-1.12.0.jar - release\modules\ext\rome-1.12.0.jar + release\modules\ext\batik-util-1.6.jar ext/javax.annotation-api-1.3.2.jar release\modules\ext\javax.annotation-api-1.3.2.jar - ext/vorbis-java-core-0.8.jar - release\modules\ext\vorbis-java-core-0.8.jar + ext/jgraphx-4.1.0.jar + release\modules\ext\jgraphx-4.1.0.jar - ext/jgraphx-4.1.0.jar - release/modules/ext/jgraphx-4.1.0.jar + ext/jline-0.9.94.jar + release\modules\ext\jline-0.9.94.jar ext/DatCon.jar - release/modules/ext/DatCon.jar - - - ext/java-libpst-0.8.1.jar - release\modules\ext\java-libpst-0.8.1.jar + release\modules\ext\DatCon.jar ext/okio-1.6.0.jar - release/modules/ext/okio-1.6.0.jar + release\modules\ext\okio-1.6.0.jar + + + ext/bcprov-jdk15on-1.54.jar + release\modules\ext\bcprov-jdk15on-1.54.jar ext/curator-framework-2.8.0.jar - release/modules/ext/curator-framework-2.8.0.jar + release\modules\ext\curator-framework-2.8.0.jar ext/commons-dbcp2-2.1.1.jar - release/modules/ext/commons-dbcp2-2.1.1.jar + release\modules\ext\commons-dbcp2-2.1.1.jar ext/google-http-client-appengine-1.29.0.jar - release/modules/ext/google-http-client-appengine-1.29.0.jar + release\modules\ext\google-http-client-appengine-1.29.0.jar - ext/uimafit-core-2.4.0.jar - release\modules\ext\uimafit-core-2.4.0.jar + ext/proto-google-iam-v1-0.12.0.jar + release\modules\ext\proto-google-iam-v1-0.12.0.jar ext/jackcess-encrypt-2.1.4.jar release\modules\ext\jackcess-encrypt-2.1.4.jar - - ext/junrar-2.0.0.jar - release\modules\ext\junrar-2.0.0.jar - ext/google-http-client-1.29.0.jar - release/modules/ext/google-http-client-1.29.0.jar - - - ext/bcpkix-jdk15on-1.60.jar - release\modules\ext\bcpkix-jdk15on-1.60.jar + release\modules\ext\google-http-client-1.29.0.jar ext/opennlp-tools-1.9.1.jar release\modules\ext\opennlp-tools-1.9.1.jar - - ext/slf4j-api-1.7.25.jar - release\modules\ext\slf4j-api-1.7.25.jar - ext/bcprov-ext-jdk15on-1.54.jar - release/modules/ext/bcprov-ext-jdk15on-1.54.jar + release\modules\ext\bcprov-ext-jdk15on-1.54.jar ext/google-cloud-core-1.70.0.jar - release/modules/ext/google-cloud-core-1.70.0.jar + release\modules\ext\google-cloud-core-1.70.0.jar - ext/geoapi-3.0.1.jar - release\modules\ext\geoapi-3.0.1.jar + ext/protobuf-java-3.7.0.jar + release\modules\ext\protobuf-java-3.7.0.jar - ext/httpmime-4.5.6.jar - release\modules\ext\httpmime-4.5.6.jar - - - ext/jdom2-2.0.6.jar - release\modules\ext\jdom2-2.0.6.jar - - - ext/uimaj-core-3.0.1.jar - release\modules\ext\uimaj-core-3.0.1.jar + ext/bcpkix-jdk15on-1.54.jar + release\modules\ext\bcpkix-jdk15on-1.54.jar ext/sqlite-jdbc-3.25.2.jar - release/modules/ext/sqlite-jdbc-3.25.2.jar + release\modules\ext\sqlite-jdbc-3.25.2.jar - ext/cxf-rt-rs-client-3.3.0.jar - release\modules\ext\cxf-rt-rs-client-3.3.0.jar + ext/grpc-protobuf-lite-1.19.0.jar + release\modules\ext\grpc-protobuf-lite-1.19.0.jar - ext/pdfbox-tools-2.0.13.jar - release\modules\ext\pdfbox-tools-2.0.13.jar + ext/httpcore-4.4.9.jar + release\modules\ext\httpcore-4.4.9.jar - ext/grib-4.5.5.jar - release\modules\ext\grib-4.5.5.jar + ext/guava-27.1-android.jar + release\modules\ext\guava-27.1-android.jar + + + ext/bcprov-jdk15on-1.52.jar + release\modules\ext\bcprov-jdk15on-1.52.jar + + + ext/checker-compat-qual-2.5.3.jar + release\modules\ext\checker-compat-qual-2.5.3.jar + + + ext/sleuthkit-4.10.0.jar + release\modules\ext\sleuthkit-4.10.0.jar + + + ext/animal-sniffer-annotations-1.17.jar + release\modules\ext\animal-sniffer-annotations-1.17.jar + + + ext/sleuthkit-caseuco-4.10.0.jar + release\modules\ext\sleuthkit-caseuco-4.10.0.jar ext/sleuthkit-4.10.0.jar @@ -621,255 +573,247 @@ ext/gax-1.44.0.jar - release/modules/ext/gax-1.44.0.jar + release\modules\ext\gax-1.44.0.jar - ext/jempbox-1.8.16.jar - release\modules\ext\jempbox-1.8.16.jar + ext/jsoup-1.10.3.jar + release\modules\ext\jsoup-1.10.3.jar + + + ext/grpc-context-1.19.0.jar + release\modules\ext\grpc-context-1.19.0.jar ext/jackcess-2.2.0.jar release\modules\ext\jackcess-2.2.0.jar - ext/grpc-context-1.19.0.jar - release/modules/ext/grpc-context-1.19.0.jar + ext/slf4j-log4j12-1.7.6.jar + release\modules\ext\slf4j-log4j12-1.7.6.jar ext/jericho-html-3.3.jar - release/modules/ext/jericho-html-3.3.jar + release\modules\ext\jericho-html-3.3.jar - ext/httpservices-4.5.5.jar - release\modules\ext\httpservices-4.5.5.jar - - - ext/xz-1.8.jar - release\modules\ext\xz-1.8.jar + ext/google-cloud-core-grpc-1.70.0.jar + release\modules\ext\google-cloud-core-grpc-1.70.0.jar ext/commons-validator-1.6.jar - release/modules/ext/commons-validator-1.6.jar + release\modules\ext\commons-validator-1.6.jar + + + ext/slf4j-api-1.7.6.jar + release\modules\ext\slf4j-api-1.7.6.jar ext/decodetect-core-0.3.jar - release/modules/ext/decodetect-core-0.3.jar + release\modules\ext\decodetect-core-0.3.jar - ext/mockito-core-3.5.7.jar - release\modules\ext\mockito-core-3.5.7.jar - - - ext/jbig2-imageio-3.0.2.jar - release\modules\ext\jbig2-imageio-3.0.2.jar - - - ext/apache-mime4j-dom-0.8.2.jar - release\modules\ext\apache-mime4j-dom-0.8.2.jar - - - ext/pdfbox-2.0.13.jar - release\modules\ext\pdfbox-2.0.13.jar - - - ext/xmlbeans-3.0.2.jar - release\modules\ext\xmlbeans-3.0.2.jar + ext/httpclient-4.5.5.jar + release\modules\ext\httpclient-4.5.5.jar ext/curator-recipes-2.8.0.jar - release/modules/ext/curator-recipes-2.8.0.jar + release\modules\ext\curator-recipes-2.8.0.jar - ext/objenesis-3.1.jar - release\modules\ext\objenesis-3.1.jar - - - ext/tagsoup-1.2.1.jar - release\modules\ext\tagsoup-1.2.1.jar + ext/jackson-annotations-2.9.0.jar + release\modules\ext\jackson-annotations-2.9.0.jar ext/jackson-core-2.9.7.jar release\modules\ext\jackson-core-2.9.7.jar - ext/sis-metadata-0.8.jar - release\modules\ext\sis-metadata-0.8.jar + ext/commons-lang3-3.5.jar + release\modules\ext\commons-lang3-3.5.jar - ext/parso-2.0.10.jar - release\modules\ext\parso-2.0.10.jar + ext/log4j-1.2.16.jar + release\modules\ext\log4j-1.2.16.jar - ext/apache-mime4j-core-0.8.2.jar - release\modules\ext\apache-mime4j-core-0.8.2.jar + ext/commons-logging-1.2.jar + release\modules\ext\commons-logging-1.2.jar - ext/commons-io-2.6.jar - release\modules\ext\commons-io-2.6.jar + ext/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar + release\modules\ext\listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar + + + ext/protobuf-java-util-3.7.0.jar + release\modules\ext\protobuf-java-util-3.7.0.jar + + + ext/commons-collections-3.2.2.jar + release\modules\ext\commons-collections-3.2.2.jar ext/SparseBitSet-1.1.jar - release/modules/ext/SparseBitSet-1.1.jar + release\modules\ext\SparseBitSet-1.1.jar + + + ext/grpc-grpclb-1.19.0.jar + release\modules\ext\grpc-grpclb-1.19.0.jar ext/batik-svggen-1.6.jar - release/modules/ext/batik-svggen-1.6.jar + release\modules\ext\batik-svggen-1.6.jar ext/c3p0-0.9.5.jar - release/modules/ext/c3p0-0.9.5.jar + release\modules\ext\c3p0-0.9.5.jar ext/zookeeper-3.4.6.jar - release/modules/ext/zookeeper-3.4.6.jar + release\modules\ext\zookeeper-3.4.6.jar - ext/commons-csv-1.6.jar - release\modules\ext\commons-csv-1.6.jar + ext/grpc-alts-1.19.0.jar + release\modules\ext\grpc-alts-1.19.0.jar ext/jdom-2.0.5.jar - release/modules/ext/jdom-2.0.5.jar + release\modules\ext\jdom-2.0.5.jar - ext/jackson-annotations-2.9.7.jar - release\modules\ext\jackson-annotations-2.9.7.jar + ext/gson-2.7.jar + release\modules\ext\gson-2.7.jar ext/google-api-client-1.27.0.jar - release/modules/ext/google-api-client-1.27.0.jar - - - ext/netcdf4-4.5.5.jar - release\modules\ext\netcdf4-4.5.5.jar - - - ext/sis-netcdf-0.8.jar - release\modules\ext\sis-netcdf-0.8.jar - - - ext/sentiment-analysis-parser-0.1.jar - release\modules\ext\sentiment-analysis-parser-0.1.jar - - - ext/commons-collections4-4.2.jar - release\modules\ext\commons-collections4-4.2.jar + release\modules\ext\google-api-client-1.27.0.jar ext/opencensus-contrib-http-util-0.19.2.jar - release/modules/ext/opencensus-contrib-http-util-0.19.2.jar + release\modules\ext\opencensus-contrib-http-util-0.19.2.jar ext/google-auth-library-oauth2-http-0.15.0.jar - release/modules/ext/google-auth-library-oauth2-http-0.15.0.jar - - - ext/juniversalchardet-1.0.3.jar - release\modules\ext\juniversalchardet-1.0.3.jar + release\modules\ext\google-auth-library-oauth2-http-0.15.0.jar ext/jython-standalone-2.7.0.jar - release/modules/ext/jython-standalone-2.7.0.jar + release\modules\ext\jython-standalone-2.7.0.jar - ext/jhighlight-1.0.3.jar - release\modules\ext\jhighlight-1.0.3.jar + ext/commons-lang-2.6.jar + release\modules\ext\commons-lang-2.6.jar - ext/jul-to-slf4j-1.7.25.jar - release\modules\ext\jul-to-slf4j-1.7.25.jar + ext/jsr305-3.0.2.jar + release\modules\ext\jsr305-3.0.2.jar - ext/postgresql-9.4.1211.jre7.jar - release/modules/ext/postgresql-9.4.1211.jre7.jar + ext/proto-google-common-protos-1.15.0.jar + release\modules\ext\proto-google-common-protos-1.15.0.jar + + + ext/netty-3.7.0.Final.jar + release\modules\ext\netty-3.7.0.Final.jar + + + ext/opencensus-contrib-grpc-metrics-0.19.2.jar + release\modules\ext\opencensus-contrib-grpc-metrics-0.19.2.jar ext/jai_imageio-1.1.jar - release/modules/ext/jai_imageio-1.1.jar + release\modules\ext\jai_imageio-1.1.jar - ext/httpclient-4.5.6.jar - release\modules\ext\httpclient-4.5.6.jar + ext/postgresql-9.4.1211.jre7.jar + release\modules\ext\postgresql-9.4.1211.jre7.jar + + + ext/junit-3.8.1.jar + release\modules\ext\junit-3.8.1.jar ext/curator-client-2.8.0.jar - release/modules/ext/curator-client-2.8.0.jar + release\modules\ext\curator-client-2.8.0.jar - ext/fontbox-2.0.13.jar - release\modules\ext\fontbox-2.0.13.jar + ext/grpc-core-1.19.0.jar + release\modules\ext\grpc-core-1.19.0.jar + + + ext/javax.ws.rs-api-2.0.jar + release\modules\ext\javax.ws.rs-api-2.0.jar ext/icepdf-core-6.2.2.jar - release/modules/ext/icepdf-core-6.2.2.jar + release\modules\ext\icepdf-core-6.2.2.jar ext/activemq-all-5.11.1.jar - release/modules/ext/activemq-all-5.11.1.jar + release\modules\ext\activemq-all-5.11.1.jar ext/google-cloud-core-http-1.70.0.jar - release/modules/ext/google-cloud-core-http-1.70.0.jar + release\modules\ext\google-cloud-core-http-1.70.0.jar ext/Rejistry-1.1-SNAPSHOT.jar - release/modules/ext/Rejistry-1.1-SNAPSHOT.jar + release\modules\ext\Rejistry-1.1-SNAPSHOT.jar - ext/dec-0.1.2.jar - release\modules\ext\dec-0.1.2.jar + ext/commons-beanutils-1.9.2.jar + release\modules\ext\commons-beanutils-1.9.2.jar ext/batik-dom-1.6.jar - release/modules/ext/batik-dom-1.6.jar + release\modules\ext\batik-dom-1.6.jar ext/google-http-client-jackson2-1.29.0.jar - release/modules/ext/google-http-client-jackson2-1.29.0.jar + release\modules\ext\google-http-client-jackson2-1.29.0.jar ext/threetenbp-1.3.3.jar - release/modules/ext/threetenbp-1.3.3.jar + release\modules\ext\threetenbp-1.3.3.jar ext/google-cloud-translate-1.70.0.jar - release/modules/ext/google-cloud-translate-1.70.0.jar + release\modules\ext\google-cloud-translate-1.70.0.jar + + + ext/grpc-stub-1.19.0.jar + release\modules\ext\grpc-stub-1.19.0.jar + + + ext/google-oauth-client-1.28.0.jar + release\modules\ext\google-oauth-client-1.28.0.jar ext/sevenzipjbinding-AllPlatforms.jar - release/modules/ext/sevenzipjbinding-AllPlatforms.jar + release\modules\ext\sevenzipjbinding-AllPlatforms.jar ext/jutf7-1.0.0.jar - release/modules/ext/jutf7-1.0.0.jar - - - ext/byte-buddy-agent-1.10.13.jar - release\modules\ext\byte-buddy-agent-1.10.13.jar + release\modules\ext\jutf7-1.0.0.jar ext/batik-awt-util-1.6.jar - release/modules/ext/batik-awt-util-1.6.jar + release\modules\ext\batik-awt-util-1.6.jar ext/google-api-services-translate-v2-rev20170525-1.27.0.jar - release/modules/ext/google-api-services-translate-v2-rev20170525-1.27.0.jar - - - ext/webp-imageio-sejda-0.1.0.jar - release/modules/ext/webp-imageio-sejda-0.1.0.jar + release\modules\ext\google-api-services-translate-v2-rev20170525-1.27.0.jar ext/icepdf-viewer-6.2.2.jar - release/modules/ext/icepdf-viewer-6.2.2.jar + release\modules\ext\icepdf-viewer-6.2.2.jar - ext/bcmail-jdk15on-1.60.jar - release\modules\ext\bcmail-jdk15on-1.60.jar + ext/webp-imageio-sejda-0.1.0.jar + release\modules\ext\webp-imageio-sejda-0.1.0.jar - ext/vorbis-java-tika-0.8.jar - release\modules\ext\vorbis-java-tika-0.8.jar + ext/grpc-netty-shaded-1.19.0.jar + release\modules\ext\grpc-netty-shaded-1.19.0.jar diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index 2c7e942538..9b7525bbd1 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -217,7 +217,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { orderByCombobox.addItem(method); } } - orderByCombobox.setSelectedItem(getSelectedFilterPanel().getLastGroupSortingAlg()); + orderByCombobox.setSelectedItem(getSelectedFilterPanel().getLastSortingMethod()); groupSortingComboBox.removeAllItems(); for (GroupSortingAlgorithm groupSortAlgorithm : GroupSortingAlgorithm.values()) { groupSortingComboBox.addItem(groupSortAlgorithm); From c2e2f1fea86d21ff9d4c5704a7ad2c0809c83956 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Fri, 11 Sep 2020 15:49:10 -0400 Subject: [PATCH 058/130] Fixed tests --- .../autopsy/discovery/search/DomainSearchTest.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTest.java index 9ddd7db0bf..9cc4f5c49c 100755 --- a/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTest.java @@ -125,7 +125,7 @@ public class DomainSearchTest { DomainSearch domainSearch = new DomainSearch(cache); List firstPage = domainSearch.getDomainsInGroup(null, new ArrayList<>(), null, null, null, groupOne, 0, 3, null, null); - assertEquals(4, firstPage.size()); + assertEquals(3, firstPage.size()); for (int i = 0; i < firstPage.size(); i++) { assertEquals(domains.get(i), firstPage.get(i)); } @@ -235,10 +235,7 @@ public class DomainSearchTest { DomainSearch domainSearch = new DomainSearch(cache); List firstPage = domainSearch.getDomainsInGroup(null, new ArrayList<>(), null, null, null, groupOne, 20, 5, null, null); - assertEquals(4, firstPage.size()); - for (int i = 0; i < firstPage.size(); i++) { - assertEquals(domains.get(i), firstPage.get(i)); - } + assertEquals(0, firstPage.size()); } @Test @@ -298,7 +295,7 @@ public class DomainSearchTest { DomainSearch domainSearch = new DomainSearch(cache); List firstPage = domainSearch.getDomainsInGroup(null, new ArrayList<>(), null, null, null, groupOne, 0, 3, null, null); - assertEquals(4, firstPage.size()); + assertEquals(3, firstPage.size()); } @Test From 9188c299f47639aff1fd2ebc681fb8d2242d323d Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Fri, 11 Sep 2020 15:51:26 -0400 Subject: [PATCH 059/130] Removed my local path from the project files --- Core/nbproject/project.properties | 8 ++++---- Core/nbproject/project.xml | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties index d0cbf8d9a1..91f9aa13e0 100644 --- a/Core/nbproject/project.properties +++ b/Core/nbproject/project.properties @@ -11,8 +11,8 @@ file.reference.bcpkix-jdk15on-1.54.jar=release\\modules\\ext\\bcpkix-jdk15on-1.5 file.reference.bcprov-ext-jdk15on-1.54.jar=release\\modules\\ext\\bcprov-ext-jdk15on-1.54.jar file.reference.bcprov-jdk15on-1.52.jar=release\\modules\\ext\\bcprov-jdk15on-1.52.jar file.reference.bcprov-jdk15on-1.54.jar=release\\modules\\ext\\bcprov-jdk15on-1.54.jar -file.reference.byte-buddy-1.10.13.jar=C:\\cygwin64\\home\\dsmyda\\autopsy\\Core\\release\\modules\\ext\\byte-buddy-1.10.13.jar -file.reference.byte-buddy-agent-1.10.13.jar=C:\\cygwin64\\home\\dsmyda\\autopsy\\Core\\release\\modules\\ext\\byte-buddy-agent-1.10.13.jar +file.reference.byte-buddy-1.10.13.jar=release\\modules\\ext\\byte-buddy-1.10.13.jar +file.reference.byte-buddy-agent-1.10.13.jar=release\\modules\\ext\\byte-buddy-agent-1.10.13.jar file.reference.c3p0-0.9.5.jar=release\\modules\\ext\\c3p0-0.9.5.jar file.reference.checker-compat-qual-2.5.3.jar=release\\modules\\ext\\checker-compat-qual-2.5.3.jar file.reference.commons-beanutils-1.9.2.jar=release\\modules\\ext\\commons-beanutils-1.9.2.jar @@ -90,9 +90,9 @@ file.reference.listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar=re file.reference.log4j-1.2.16.jar=release\\modules\\ext\\log4j-1.2.16.jar file.reference.mchange-commons-java-0.2.9.jar=release\\modules\\ext\\mchange-commons-java-0.2.9.jar file.reference.metadata-extractor-2.11.0.jar=release\\modules\\ext\\metadata-extractor-2.11.0.jar -file.reference.mockito-core-3.5.7.jar=C:\\cygwin64\\home\\dsmyda\\autopsy\\Core\\release\\modules\\ext\\mockito-core-3.5.7.jar +file.reference.mockito-core-3.5.7.jar=release\\modules\\ext\\mockito-core-3.5.7.jar file.reference.netty-3.7.0.Final.jar=release\\modules\\ext\\netty-3.7.0.Final.jar -file.reference.objenesis-3.1.jar=C:\\cygwin64\\home\\dsmyda\\autopsy\\Core\\release\\modules\\ext\\objenesis-3.1.jar +file.reference.objenesis-3.1.jar=release\\modules\\ext\\objenesis-3.1.jar file.reference.okhttp-2.7.5.jar=release\\modules\\ext\\okhttp-2.7.5.jar file.reference.okio-1.6.0.jar=release\\modules\\ext\\okio-1.6.0.jar file.reference.opencensus-api-0.19.2.jar=release\\modules\\ext\\opencensus-api-0.19.2.jar diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 89484c1177..ae69a4e5c6 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -401,7 +401,7 @@ ext/byte-buddy-1.10.13.jar - C:\cygwin64\home\dsmyda\autopsy\Core\release\modules\ext\byte-buddy-1.10.13.jar + release\modules\ext\byte-buddy-1.10.13.jar ext/error_prone_annotations-2.3.2.jar @@ -601,7 +601,7 @@ ext/mockito-core-3.5.7.jar - C:\cygwin64\home\dsmyda\autopsy\Core\release\modules\ext\mockito-core-3.5.7.jar + release\modules\ext\mockito-core-3.5.7.jar ext/httpclient-4.5.5.jar @@ -617,7 +617,7 @@ ext/objenesis-3.1.jar - C:\cygwin64\home\dsmyda\autopsy\Core\release\modules\ext\objenesis-3.1.jar + release\modules\ext\objenesis-3.1.jar ext/jackson-core-2.9.7.jar @@ -801,7 +801,7 @@ ext/byte-buddy-agent-1.10.13.jar - C:\cygwin64\home\dsmyda\autopsy\Core\release\modules\ext\byte-buddy-agent-1.10.13.jar + release\modules\ext\byte-buddy-agent-1.10.13.jar ext/batik-awt-util-1.6.jar From 6a7daa5a972499803b41e065a998b723672d2050 Mon Sep 17 00:00:00 2001 From: apriestman Date: Mon, 14 Sep 2020 14:15:24 -0400 Subject: [PATCH 060/130] Add extractor for web account role --- .../autopsy/datamodel/utils/IconsUtil.java | 2 + .../sleuthkit/autopsy/images/domain_role.png | Bin 0 -> 1016 bytes .../report/modules/html/HTMLReport.java | 3 + .../autopsy/recentactivity/Bundle.properties | 2 + .../recentactivity/Bundle.properties-MERGED | 2 + .../recentactivity/ExtractWebAccountType.java | 370 ++++++++++++++++++ .../recentactivity/RAImageIngestModule.java | 2 + 7 files changed, 381 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/images/domain_role.png create mode 100644 RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractWebAccountType.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/utils/IconsUtil.java b/Core/src/org/sleuthkit/autopsy/datamodel/utils/IconsUtil.java index e4fbb55ce2..0e2065da38 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/utils/IconsUtil.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/utils/IconsUtil.java @@ -103,6 +103,8 @@ public final class IconsUtil { imageFile = "devices.png"; //NON-NLS } else if (typeID == ARTIFACT_TYPE.TSK_VERIFICATION_FAILED.getTypeID()) { imageFile = "validationFailed.png"; //NON-NLS + } else if (typeID == ARTIFACT_TYPE.TSK_WEB_ACCOUNT_TYPE.getTypeID()) { + imageFile = "domain_role.png"; //NON-NLS } else { imageFile = "artifact-icon.png"; //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/images/domain_role.png b/Core/src/org/sleuthkit/autopsy/images/domain_role.png new file mode 100644 index 0000000000000000000000000000000000000000..cf12fef643d2a2902416c8ebf819e7813218c8e5 GIT binary patch literal 1016 zcmVEX>4Tx04R}tkv&MmKpe$iTcs*34rUN>$j~}j5S8L6RV;#q(pG5I!Q|2}XktiG zTpR`0f`cE6RRU5saWpZjx!m7>W2pGZ8*bi*QECysAg zI_G_2fmI}h_?&p$pbHW|a$R=$jdR&yKhG45TxO0~AQsDAEO#-h7%K5JaYRuy%J=78 zRyc2QR%>F_EGDgol5`@u$fpldB3w zj(KcAh2;3b|KNAGW@&2DO$sG|-WS{chyuY~pw+PL?_=9;odAJn;7aTGH=4lAC+Urj z7C8b2w}Ff6jwbH`mpj1llP(#OBL!&sOC{j_jJ~M=4BY|)t8Q=YeVjf3IqGWZ1~@nb z#>$kv=JD>n?%w`A)9&vF)=_fLLQ=Ew00009a7bBm000XU000XU0RWnu7ytkO2XskI zMF->w4h}Oh1LdxE0000PbVXQnLvL+uWo~o;Lvm$dbY)~9cWHEJAV*0}P*;Ht7XSbO z;z>k7R5;6>lF>_3Q5?s==hp6yce`G<-P~nS+moRXL_x9~Vy%VXTlUaX5ExYKMgI*U zg#v@#dI)^;#g}TO!jgny5cpt3bCS-xX?NXqJ@;Pl_>j1zcUXSmy!`llzlSfsA2{dm zdcX+O?mX1)Jb)3j;>aJkAwp)*KNQz~cEuhuiKYR7S}Ye@S)W>%t!;2V@HgKaK*)Ps z%68qXXpvV2rDvK!h1pJLxjIyMw(^$q>j!h88A=VSv5FR%K5Pbn8ug16Ei#=NR%6X` zq4E1XjCeF_P#Q)H8I*>Ncr;7M{Lz3^CIBYUK^!9{(ZN(E;9cP)ItVD~F8s`%JI>%| z_FPGKj|Qw3k_dlYe=0l9ZY#55+qKZQjmgzQ(z}AYX?>5Dx9%vmZF-nZRo}j^uUVy* zcK`qvuYE-Oc{yR6>l|~am;nHhId3}F^e4YcX7S61UhhMC{=&e^*FQjfLV71G_w2~h zRZa-qhgh3wEwyc%%iP_~-Me)b4 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.recentactivity; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.Collection; +import java.util.Objects; +import java.util.logging.Level; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress; +import org.sleuthkit.autopsy.ingest.IngestJobContext; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.TskCoreException; + + +/** + * Attempts to determine a user's role on a domain based on the URL. + */ +class ExtractWebAccountType extends Extract { + + private static final Logger logger = Logger.getLogger(ExtractWebAccountType.class.getName()); + + ExtractWebAccountType() { + moduleName = NbBundle.getMessage(ExtractWebAccountType.class, "ExtractWebAccountType.moduleName.text"); + } + + private void extractDomainRoles(Content dataSource, IngestJobContext context) { + try { + // Get web history blackboard artifacts + Collection listArtifacts = currentCase.getSleuthkitCase().getBlackboard().getArtifacts( + Arrays.asList(new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY)), + Arrays.asList(dataSource.getId())); + logger.log(Level.INFO, "Processing {0} blackboard artifacts.", listArtifacts.size()); //NON-NLS + + // Set up collector for roles + RoleProcessor roleProcessor = new RoleProcessor(context); + + // Process each URL + for (BlackboardArtifact artifact : listArtifacts) { + if (context.dataSourceIngestIsCancelled()) { + return; + } + + findRolesForUrl(artifact, roleProcessor); + } + + // Create artifacts + roleProcessor.createArtifacts(); + + } catch (TskCoreException e) { + logger.log(Level.SEVERE, "Encountered error retrieving artifacts for domain role analysis", e); //NON-NLS + } + } + + /** + * Extract and store any role found in the given artifact. + * + * @param artifact The original artifact + * @param roleProcessor Object to collect and process domain roles. + * + * @throws TskCoreException + */ + private void findRolesForUrl(BlackboardArtifact artifact, RoleProcessor roleProcessor) throws TskCoreException { + + BlackboardAttribute urlAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL)); + if (urlAttr == null) { + return; + } + String url = urlAttr.getValueString(); + + BlackboardAttribute domainAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN)); + if (domainAttr == null) { + return; + } + String domain = domainAttr.getValueString(); + + findMyBbRole(url, domain, artifact, roleProcessor); + findPhpBbRole(url, domain, artifact, roleProcessor); + findJoomlaRole(url, domain, artifact, roleProcessor); + findWordPressRole(url, domain, artifact, roleProcessor); + } + + /** + * Extract myBB role. + * + * @param url The full URL. + * @param domain The domain. + * @param artifact The original artifact. + * @param roleProcessor Object to collect and process domain roles. + */ + private void findMyBbRole(String url, String domain, BlackboardArtifact artifact, RoleProcessor roleProcessor) { + String platformName = "myBB platform"; // NON-NLS + + if (url.contains("/admin/index.php")) { + roleProcessor.addRole(domain, platformName, Role.ADMIN, url, artifact); + } else if (url.contains("/modcp.php")) { + roleProcessor.addRole(domain, platformName, Role.MOD, url, artifact); + } else if (url.contains("/usercp.php")) { + roleProcessor.addRole(domain, platformName, Role.USER, url, artifact); + } + } + + /** + * Extract phpBB role. + * + * @param url The full URL. + * @param domain The domain. + * @param artifact The original artifact. + * @param roleProcessor Object to collect and process domain roles. + */ + private void findPhpBbRole(String url, String domain, BlackboardArtifact artifact, RoleProcessor roleProcessor) { + String platformName = "phpBB platform"; // NON-NLS + + if (url.contains("/adm/index.php")) { + roleProcessor.addRole(domain, platformName, Role.ADMIN, url, artifact); + } else if (url.contains("/mcp.php")) { + roleProcessor.addRole(domain, platformName, Role.MOD, url, artifact); + } else if (url.contains("/ucp.php")) { + roleProcessor.addRole(domain, platformName, Role.USER, url, artifact); + } + } + + /** + * Extract Joomla role. + * + * @param url The full URL. + * @param domain The domain. + * @param artifact The original artifact. + * @param roleProcessor Object to collect and process domain roles. + */ + private void findJoomlaRole(String url, String domain, BlackboardArtifact artifact, RoleProcessor roleProcessor) { + String platformName = "Joomla platform"; // NON-NLS + + if (url.contains("/administrator/index.php")) { // NON-NLS + roleProcessor.addRole(domain, platformName, Role.ADMIN, url, artifact); + } + } + + /** + * Extract WordPress role. + * + * @param url The full URL. + * @param domain The domain. + * @param artifact The original artifact. + * @param roleProcessor Object to collect and process domain roles. + */ + private void findWordPressRole(String url, String domain, BlackboardArtifact artifact, RoleProcessor roleProcessor) { + String platformName = "WordPress platform"; // NON-NLS + + // For WordPress, any logged in user can get to /wp-admin/, /wp-admin/index.php and /wp-admin/profile.php, so + // assume that any other .php file will indicate an administrator + if (url.contains("/wp-admin/")) { + + if (url.endsWith("/wp-admin/") + || url.contains("/wp-admin/index.php") + || url.contains("/wp-admin/profile.php")) { + roleProcessor.addRole(domain, platformName, Role.USER, url, artifact); + } else { + roleProcessor.addRole(domain, platformName, Role.ADMIN, url, artifact); + } + } + } + + @Override + void process(Content dataSource, IngestJobContext context, DataSourceIngestModuleProgress progressBar) { + extractDomainRoles(dataSource, context); + } + + + /** + * Collects data for making blackboard artifacts. + * + * We only want a max of one role per domain, and the role should be the + * highest level found. The full URL and associated file will belong to the first + * artifact found with the recorded level. + */ + private class RoleProcessor { + private final IngestJobContext context; + private final Map roles = new HashMap<>(); + + RoleProcessor(IngestJobContext context) { + this.context = context; + } + + /** + * Add a role to the map if: + * - This is the first time we've seen this domain/platform + * - The level of the role is higher than previously seen for this domain/platform + * + * @param domain The domain. + * @param platform The probable platform for this role. + * @param role The role level. + * @param url The URL (stored for efficiency). + * @param artifact The original blackboard artifact the URL came from. + */ + void addRole(String domain, String platform, Role role, String url, BlackboardArtifact artifact) { + RoleKey key = new RoleKey(domain, platform); + if ((! roles.containsKey(key)) || + (roles.containsKey(key) && (role.getRank() > roles.get(key).getRole().getRank()))) { + roles.put(key, new DomainRole(domain, platform, role, url, artifact)); + } + } + + /** + * Create artifacts for the domain roles. + */ + void createArtifacts() { + + if (roles.isEmpty()) { + logger.log(Level.INFO, "Didn't find any web accounts."); + return; + } else { + logger.log(Level.INFO, "Found {0} web accounts.", roles.keySet().size()); + } + + try { + for (RoleKey key : roles.keySet()) { + if (context.dataSourceIngestIsCancelled()) { + return; + } + + DomainRole role = roles.get(key); + + AbstractFile file = tskCase.getAbstractFileById(role.getArtifact().getObjectID()); + if (file == null) { + continue; + } + + String desc = role.getRole().getDesc() + " role (" + role.getPlatform() + ")"; // NON-NLS + + Collection bbattributes = new ArrayList<>(); + bbattributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, + NbBundle.getMessage(this.getClass(), + "ExtractWebAccountType.parentModuleName"), role.getDomain())); + bbattributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, + NbBundle.getMessage(this.getClass(), + "ExtractWebAccountType.parentModuleName"), desc)); + bbattributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL, + NbBundle.getMessage(this.getClass(), + "ExtractWebAccountType.parentModuleName"), role.getUrl())); + + postArtifact(createArtifactWithAttributes(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_ACCOUNT_TYPE, file, bbattributes)); + } + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Error creating web accounts", ex); + } + } + } + + /** + * Possible roles with rank and display name. + */ + private enum Role { + USER("User", 0), + MOD("Moderator", 1), + ADMIN("Administrator", 2); + + private final String desc; + private final int rank; + + Role(String desc, int rank) { + this.desc = desc; + this.rank = rank; + } + + String getDesc() { + return desc; + } + + int getRank() { + return rank; + } + } + + /** + * Holds key to retrieve data for a given domain/platform. + */ + private class RoleKey { + private final String domain; + private final String platform; + + RoleKey(String domain, String platform) { + this.domain = domain; + this.platform = platform; + } + + @Override + public boolean equals(Object other) { + if (! (other instanceof RoleKey)) { + return false; + } + + RoleKey otherKey = (RoleKey)other; + return (domain.equals(otherKey.domain) + && platform.equals(otherKey.platform)); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 79 * hash + Objects.hashCode(this.domain); + hash = 79 * hash + Objects.hashCode(this.platform); + return hash; + } + } + + /** + * Holds full data for a domain role + */ + private class DomainRole { + final String domain; + final String platform; + final Role role; + final String url; + final BlackboardArtifact artifact; + + DomainRole(String domain, String platform, Role role, String url, BlackboardArtifact artifact) { + this.domain = domain; + this.role = role; + this.platform = platform; + this.url = url; + this.artifact = artifact; + } + + String getDomain() { + return domain; + } + + String getPlatform() { + return platform; + } + + Role getRole() { + return role; + } + + String getUrl() { + return url; + } + + BlackboardArtifact getArtifact() { + return artifact; + } + } +} diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java index 488448d434..e5dc27b3ba 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java @@ -80,6 +80,7 @@ public final class RAImageIngestModule implements DataSourceIngestModule { Extract recycleBin = new ExtractRecycleBin(); Extract sru = new ExtractSru(); Extract prefetch = new ExtractPrefetch(); + Extract domainRole = new ExtractWebAccountType(); extractors.add(chrome); extractors.add(firefox); @@ -88,6 +89,7 @@ public final class RAImageIngestModule implements DataSourceIngestModule { extractors.add(safari); extractors.add(recentDocuments); extractors.add(SEUQA); // this needs to run after the web browser modules + extractors.add(domainRole); // this needs to run after the web browser modules extractors.add(registry); // this should run after quicker modules like the browser modules and needs to run before the DataSourceUsageAnalyzer extractors.add(osExtract); // this needs to run before the DataSourceUsageAnalyzer extractors.add(dataSourceAnalyzer); //this needs to run after ExtractRegistry and ExtractOs From ed74732c1d5677eeeecaa38986b95568d8de3f8b Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Mon, 14 Sep 2020 14:17:26 -0400 Subject: [PATCH 061/130] Implemented domain discovery thumbnail API --- .../discovery/search/DomainSearch.java | 23 ++- .../search/DomainSearchArtifactsCache.java | 55 +++++++ .../search/DomainSearchArtifactsLoader.java | 61 ++++++++ .../search/DomainSearchArtifactsRequest.java | 73 +++++++++ .../search/DomainSearchThumbnailLoader.java | 143 ++++++++++++++++++ .../search/DomainSearchThumbnailRequest.java | 51 +++++++ 6 files changed, 404 insertions(+), 2 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsCache.java create mode 100755 Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsLoader.java create mode 100755 Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsRequest.java create mode 100755 Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java create mode 100755 Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailRequest.java diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java index 94ad264155..8faf1822a7 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.discovery.search; +import java.awt.Image; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -26,6 +27,7 @@ import java.util.Map; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; /** * Main class to perform the domain search. @@ -33,13 +35,15 @@ import org.sleuthkit.datamodel.SleuthkitCase; public class DomainSearch { private final DomainSearchCache searchCache; + private final DomainSearchThumbnailLoader thumbnailLoader; public DomainSearch() { - this(new DomainSearchCache()); + this(new DomainSearchCache(), new DomainSearchThumbnailLoader()); } - DomainSearch(DomainSearchCache cache) { + DomainSearch(DomainSearchCache cache, DomainSearchThumbnailLoader thumbnailLoader) { this.searchCache = cache; + this.thumbnailLoader = thumbnailLoader; } /** @@ -123,4 +127,19 @@ public class DomainSearch { return page; } + + /** + * Get a thumbnail representation of a domain name. See + * DomainSearchThumbnailRequest for more details. + * + * @param thumbnailRequest Thumbnail request for domain + * @return An Image instance or null if no thumbnail is available. + * + * @throws TskCoreException If there is an error reaching the case databases + * @throws DiscoveryException If there is an error with Discovery related + * processing + */ + public Image getThumbnail(DomainSearchThumbnailRequest thumbnailRequest) throws TskCoreException, DiscoveryException { + return thumbnailLoader.load(thumbnailRequest); + } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsCache.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsCache.java new file mode 100755 index 0000000000..e1a11690d7 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsCache.java @@ -0,0 +1,55 @@ +/* + * 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.discovery.search; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.LoadingCache; +import java.util.List; +import java.util.concurrent.ExecutionException; +import org.sleuthkit.datamodel.BlackboardArtifact; + +/** + * Caches artifact hits for a domain request. + */ +public class DomainSearchArtifactsCache { + + private static final int MAXIMUM_CACHE_SIZE = 5; + private static final LoadingCache> cache + = CacheBuilder.newBuilder() + .maximumSize(MAXIMUM_CACHE_SIZE) + .build(new DomainSearchArtifactsLoader()); + + /** + * Get artifact instances that match the requested criteria. If the request + * is new, the results will be automatically loaded. + * + * @param request Artifact request, specifies type, Case, and domain name. + * @return A list of matching artifacts + * + * @throws DiscoveryException Any error that occurs during the loading + * process. + */ + public List get(DomainSearchArtifactsRequest request) throws DiscoveryException { + try { + return cache.get(request); + } catch (ExecutionException ex) { + throw new DiscoveryException("Error fetching artifacts from cache", ex.getCause()); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsLoader.java new file mode 100755 index 0000000000..20772f2c12 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsLoader.java @@ -0,0 +1,61 @@ +/* + * 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.discovery.search; + +import com.google.common.cache.CacheLoader; +import java.util.List; +import java.util.ArrayList; +import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; +import org.sleuthkit.datamodel.BlackboardAttribute.Type; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.BlackboardArtifact; + +/** + * Loads artifacts for the given request. Searches TSK_DOMAIN and TSK_URL + * attributes for the requested domain name. TSK_DOMAIN is exact match (ignoring + * case). TSK_URL is sub-string match (ignoring case). + */ +public class DomainSearchArtifactsLoader extends CacheLoader> { + + private static final Type TSK_DOMAIN = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DOMAIN); + private static final Type TSK_URL = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_URL); + + @Override + public List load(DomainSearchArtifactsRequest artifactsRequest) throws TskCoreException { + final SleuthkitCase caseDb = artifactsRequest.getSleuthkitCase(); + final String normalizedDomain = artifactsRequest.getDomain().toLowerCase(); + final List artifacts = caseDb.getBlackboardArtifacts(artifactsRequest.getArtifactType()); + final List matchingDomainArtifacts = new ArrayList<>(); + + for (BlackboardArtifact artifact : artifacts) { + final BlackboardAttribute tskDomain = artifact.getAttribute(TSK_DOMAIN); + final BlackboardAttribute tskUrl = artifact.getAttribute(TSK_URL); + + if (tskDomain != null && tskDomain.getValueString().toLowerCase().equals(normalizedDomain)) { + matchingDomainArtifacts.add(artifact); + } else if (tskUrl != null && tskUrl.getValueString().toLowerCase().contains(normalizedDomain)) { + matchingDomainArtifacts.add(artifact); + } + } + + return matchingDomainArtifacts; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsRequest.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsRequest.java new file mode 100755 index 0000000000..13f607eb6c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsRequest.java @@ -0,0 +1,73 @@ +/* + * 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.discovery.search; + +import java.util.Objects; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; + +/** + * Requests artifacts of a specific type and domain from a given Case. + */ +public class DomainSearchArtifactsRequest { + + private final SleuthkitCase sleuthkitCase; + private final String domain; + private final ARTIFACT_TYPE artifactType; + + public DomainSearchArtifactsRequest(SleuthkitCase sleuthkitCase, + String domain, ARTIFACT_TYPE artifactType) { + this.sleuthkitCase = sleuthkitCase; + this.domain = domain; + this.artifactType = artifactType; + } + + public SleuthkitCase getSleuthkitCase() { + return sleuthkitCase; + } + + public String getDomain() { + return domain; + } + + public ARTIFACT_TYPE getArtifactType() { + return artifactType; + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + if (!(other instanceof DomainSearchArtifactsRequest)) { + return false; + } + + DomainSearchArtifactsRequest otherRequest = (DomainSearchArtifactsRequest) other; + return this.sleuthkitCase == otherRequest.getSleuthkitCase() + && this.domain.equals(otherRequest.getDomain()) + && this.artifactType == otherRequest.getArtifactType(); + } + + @Override + public int hashCode() { + return 79 * 5 + Objects.hash(this.domain, this.artifactType); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java new file mode 100755 index 0000000000..f2a447c73c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java @@ -0,0 +1,143 @@ +/* + * 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.discovery.search; + +import java.awt.Image; +import java.util.List; +import java.util.ArrayList; +import java.util.Collections; +import org.sleuthkit.autopsy.coreutils.ImageUtils; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.AbstractFile; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD; +import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Loads a thumbnail for the given request. Thumbnail candidates are JPEG files + * that are either TSK_WEB_DOWNLOAD or TSK_WEB_CACHE artifacts. JPEG files are + * sorted by most recent if sourced from TSK_WEB_DOWNLOADs. JPEG files are + * sorted by size if sourced from TSK_WEB_CACHE artifacts. Artifacts are first + * loaded from the DomainSearchArtifactsCache and then further analyzed. + */ +public class DomainSearchThumbnailLoader { + + private static final String JPG_EXTENSION = "jpg"; + private static final String JPG_MIME_TYPE = "image/jpeg"; + private final DomainSearchArtifactsCache artifactsCache; + + public DomainSearchThumbnailLoader() { + this(new DomainSearchArtifactsCache()); + } + + DomainSearchThumbnailLoader(DomainSearchArtifactsCache artifactsCache) { + this.artifactsCache = artifactsCache; + } + + public Image load(DomainSearchThumbnailRequest thumbnailRequest) throws TskCoreException, DiscoveryException { + + final SleuthkitCase caseDb = thumbnailRequest.getSleuthkitCase(); + + final DomainSearchArtifactsRequest webDownloadsRequest = new DomainSearchArtifactsRequest( + caseDb, thumbnailRequest.getDomain(), TSK_WEB_DOWNLOAD); + + final List webDownloads = artifactsCache.get(webDownloadsRequest); + final List webDownloadPictures = getJpegsFromWebDownload(caseDb, webDownloads); + Collections.sort(webDownloadPictures, (file1, file2) -> Long.compare(file1.getCrtime(), file2.getCrtime())); + + for (int i = webDownloadPictures.size() - 1; i >= 0; i--) { + // Get the most recent image, according to creation time. + final AbstractFile mostRecent = webDownloadPictures.get(i); + + final Image candidateThumbnail = ImageUtils.getThumbnail(mostRecent, thumbnailRequest.getIconSize()); + if (candidateThumbnail != ImageUtils.getDefaultThumbnail()) { + return candidateThumbnail; + } + } + + final DomainSearchArtifactsRequest webCacheRequest = new DomainSearchArtifactsRequest( + caseDb, thumbnailRequest.getDomain(), TSK_WEB_CACHE); + + final List webCacheArtifacts = artifactsCache.get(webCacheRequest); + final List webCachePictures = getJpegsFromWebCache(caseDb, webCacheArtifacts); + Collections.sort(webCachePictures, (file1, file2) -> Long.compare(file1.getSize(), file2.getSize())); + + for (int i = webCachePictures.size() - 1; i >= 0; i--) { + // Get the largest image, according to file size. + final AbstractFile largest = webCachePictures.get(i); + + final Image candidateThumbnail = ImageUtils.getThumbnail(largest, thumbnailRequest.getIconSize()); + if (candidateThumbnail != ImageUtils.getDefaultThumbnail()) { + return candidateThumbnail; + } + } + + return null; + } + + /** + * Finds all JPEG source files from TSK_WEB_DOWNLOAD instances. + */ + private List getJpegsFromWebDownload(SleuthkitCase caseDb, List artifacts) throws TskCoreException { + final List jpegs = new ArrayList<>(); + + for (BlackboardArtifact artifact : artifacts) { + final Content sourceContent = caseDb.getContentById(artifact.getObjectID()); + addIfJpeg(jpegs, sourceContent); + } + + return jpegs; + } + + /** + * Finds all JPEG source files from TSK_WEB_CACHE instances. + */ + private List getJpegsFromWebCache(SleuthkitCase caseDb, List artifacts) throws TskCoreException { + final BlackboardAttribute.Type TSK_PATH_ID = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH_ID); + + final List jpegs = new ArrayList<>(); + for (BlackboardArtifact artifact : artifacts) { + final BlackboardAttribute tskPathId = artifact.getAttribute(TSK_PATH_ID); + if (tskPathId != null) { + final Content sourceContent = caseDb.getContentById(tskPathId.getValueLong()); + addIfJpeg(jpegs, sourceContent); + } + } + + return jpegs; + } + + /** + * Checks if the candidate source content is indeed a JPEG file. + */ + private void addIfJpeg(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())) { + files.add(file); + } + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailRequest.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailRequest.java new file mode 100755 index 0000000000..b3806ebeb1 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailRequest.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.discovery.search; + +import org.sleuthkit.datamodel.SleuthkitCase; + +/** + * Requests a thumbnail to be generated for a given Case, domain and + * size. IconSize should be a value obtained from ImageUtils. + */ +public class DomainSearchThumbnailRequest { + + private final SleuthkitCase sleuthkitCase; + private final String domain; + private final int iconSize; + + public DomainSearchThumbnailRequest(SleuthkitCase sleuthkitCase, + String domain, int iconSize) { + this.sleuthkitCase = sleuthkitCase; + this.domain = domain; + this.iconSize = iconSize; + } + + public SleuthkitCase getSleuthkitCase() { + return sleuthkitCase; + } + + public String getDomain() { + return domain; + } + + public int getIconSize() { + return iconSize; + } +} From 62733e0722a28722b9a78db696c5144c03e06f51 Mon Sep 17 00:00:00 2001 From: apriestman Date: Mon, 14 Sep 2020 14:18:07 -0400 Subject: [PATCH 062/130] Renamed icon --- .../autopsy/datamodel/utils/IconsUtil.java | 2 +- .../{domain_role.png => web-account-type.png} | Bin .../autopsy/report/modules/html/HTMLReport.java | 2 +- .../autopsy/recentactivity/RAImageIngestModule.java | 4 ++-- 4 files changed, 4 insertions(+), 4 deletions(-) rename Core/src/org/sleuthkit/autopsy/images/{domain_role.png => web-account-type.png} (100%) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/utils/IconsUtil.java b/Core/src/org/sleuthkit/autopsy/datamodel/utils/IconsUtil.java index 0e2065da38..634e85c0e2 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/utils/IconsUtil.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/utils/IconsUtil.java @@ -104,7 +104,7 @@ public final class IconsUtil { } else if (typeID == ARTIFACT_TYPE.TSK_VERIFICATION_FAILED.getTypeID()) { imageFile = "validationFailed.png"; //NON-NLS } else if (typeID == ARTIFACT_TYPE.TSK_WEB_ACCOUNT_TYPE.getTypeID()) { - imageFile = "domain_role.png"; //NON-NLS + imageFile = "web-account-type.png"; //NON-NLS } else { imageFile = "artifact-icon.png"; //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/images/domain_role.png b/Core/src/org/sleuthkit/autopsy/images/web-account-type.png similarity index 100% rename from Core/src/org/sleuthkit/autopsy/images/domain_role.png rename to Core/src/org/sleuthkit/autopsy/images/web-account-type.png diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/html/HTMLReport.java b/Core/src/org/sleuthkit/autopsy/report/modules/html/HTMLReport.java index e3dcf0eac7..36fced7a15 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/html/HTMLReport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/html/HTMLReport.java @@ -358,7 +358,7 @@ public class HTMLReport implements TableReportModule { in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/images/validationFailed.png"); //NON-NLS break; case TSK_WEB_ACCOUNT_TYPE: - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/images/domain_role.png"); //NON-NLS + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/images/web-account-type.png.png"); //NON-NLS break; default: logger.log(Level.WARNING, "useDataTypeIcon: unhandled artifact type = {0}", dataType); //NON-NLS diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java index e5dc27b3ba..220317313b 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java @@ -80,7 +80,7 @@ public final class RAImageIngestModule implements DataSourceIngestModule { Extract recycleBin = new ExtractRecycleBin(); Extract sru = new ExtractSru(); Extract prefetch = new ExtractPrefetch(); - Extract domainRole = new ExtractWebAccountType(); + Extract webAccountType = new ExtractWebAccountType(); extractors.add(chrome); extractors.add(firefox); @@ -89,7 +89,7 @@ public final class RAImageIngestModule implements DataSourceIngestModule { extractors.add(safari); extractors.add(recentDocuments); extractors.add(SEUQA); // this needs to run after the web browser modules - extractors.add(domainRole); // this needs to run after the web browser modules + extractors.add(webAccountType); // this needs to run after the web browser modules extractors.add(registry); // this should run after quicker modules like the browser modules and needs to run before the DataSourceUsageAnalyzer extractors.add(osExtract); // this needs to run before the DataSourceUsageAnalyzer extractors.add(dataSourceAnalyzer); //this needs to run after ExtractRegistry and ExtractOs From 95007b15d76d8097f1dc94e2da1d4da5d55479d1 Mon Sep 17 00:00:00 2001 From: apriestman Date: Mon, 14 Sep 2020 15:32:11 -0400 Subject: [PATCH 063/130] Codacy --- .../autopsy/recentactivity/ExtractWebAccountType.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractWebAccountType.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractWebAccountType.java index 6d89b76ac8..c4fbb8fcba 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractWebAccountType.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractWebAccountType.java @@ -21,9 +21,7 @@ package org.sleuthkit.autopsy.recentactivity; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; -import java.util.Set; import java.util.Collection; import java.util.Objects; import java.util.logging.Level; @@ -91,12 +89,13 @@ class ExtractWebAccountType extends Extract { if (urlAttr == null) { return; } - String url = urlAttr.getValueString(); - + BlackboardAttribute domainAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN)); if (domainAttr == null) { return; } + + String url = urlAttr.getValueString(); String domain = domainAttr.getValueString(); findMyBbRole(url, domain, artifact, roleProcessor); From 39cb3424cffe2581346762bf24f85d65433690ad Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Mon, 14 Sep 2020 16:45:37 -0400 Subject: [PATCH 064/130] Fixed tests and added cache for thumbnails --- .../discovery/search/DomainSearch.java | 14 +++-- .../search/DomainSearchArtifactsCache.java | 2 +- .../search/DomainSearchThumbnailCache.java | 53 +++++++++++++++++++ .../search/DomainSearchThumbnailLoader.java | 4 +- .../search/DomainSearchThumbnailRequest.java | 22 ++++++++ .../discovery/search/DomainSearchTest.java | 24 ++++----- 6 files changed, 97 insertions(+), 22 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailCache.java diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java index 8faf1822a7..be1b04ed1b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java @@ -27,7 +27,6 @@ import java.util.Map; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; import org.sleuthkit.datamodel.SleuthkitCase; -import org.sleuthkit.datamodel.TskCoreException; /** * Main class to perform the domain search. @@ -35,15 +34,15 @@ import org.sleuthkit.datamodel.TskCoreException; public class DomainSearch { private final DomainSearchCache searchCache; - private final DomainSearchThumbnailLoader thumbnailLoader; + private final DomainSearchThumbnailCache thumbnailCache; public DomainSearch() { - this(new DomainSearchCache(), new DomainSearchThumbnailLoader()); + this(new DomainSearchCache(), new DomainSearchThumbnailCache()); } - DomainSearch(DomainSearchCache cache, DomainSearchThumbnailLoader thumbnailLoader) { + DomainSearch(DomainSearchCache cache, DomainSearchThumbnailCache thumbnailCache) { this.searchCache = cache; - this.thumbnailLoader = thumbnailLoader; + this.thumbnailCache = thumbnailCache; } /** @@ -135,11 +134,10 @@ public class DomainSearch { * @param thumbnailRequest Thumbnail request for domain * @return An Image instance or null if no thumbnail is available. * - * @throws TskCoreException If there is an error reaching the case databases * @throws DiscoveryException If there is an error with Discovery related * processing */ - public Image getThumbnail(DomainSearchThumbnailRequest thumbnailRequest) throws TskCoreException, DiscoveryException { - return thumbnailLoader.load(thumbnailRequest); + public Image getThumbnail(DomainSearchThumbnailRequest thumbnailRequest) throws DiscoveryException { + return thumbnailCache.get(thumbnailRequest); } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsCache.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsCache.java index e1a11690d7..7efc42e219 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsCache.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsCache.java @@ -25,7 +25,7 @@ import java.util.concurrent.ExecutionException; import org.sleuthkit.datamodel.BlackboardArtifact; /** - * Caches artifact hits for a domain request. + * Caches artifact requests. */ public class DomainSearchArtifactsCache { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailCache.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailCache.java new file mode 100755 index 0000000000..2a02cce9af --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailCache.java @@ -0,0 +1,53 @@ +/* + * 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.discovery.search; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.LoadingCache; +import java.awt.Image; +import java.util.concurrent.ExecutionException; + +/** + * Caches thumbnail requests. + */ +public class DomainSearchThumbnailCache { + + private static final int MAXIMUM_CACHE_SIZE = 500; + private static final LoadingCache cache + = CacheBuilder.newBuilder() + .maximumSize(MAXIMUM_CACHE_SIZE) + .build(new DomainSearchThumbnailLoader()); + + /** + * Get a thumbnail for the requested domain. If the request is new, the + * thumbnail will be automatically loaded. + * + * @param request Requested domain to thumbnail + * @return The thumbnail Image instance, or null if no thumbnail is available + * + * @throws DiscoveryException If any error occurs during thumbnail generation. + */ + public Image get(DomainSearchThumbnailRequest request) throws DiscoveryException { + try { + return cache.get(request); + } catch (ExecutionException ex) { + throw new DiscoveryException("Error fetching artifacts from cache", ex.getCause()); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java index f2a447c73c..0a6a34bf8c 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.discovery.search; +import com.google.common.cache.CacheLoader; import java.awt.Image; import java.util.List; import java.util.ArrayList; @@ -41,7 +42,7 @@ import org.sleuthkit.datamodel.TskCoreException; * sorted by size if sourced from TSK_WEB_CACHE artifacts. Artifacts are first * loaded from the DomainSearchArtifactsCache and then further analyzed. */ -public class DomainSearchThumbnailLoader { +public class DomainSearchThumbnailLoader extends CacheLoader { private static final String JPG_EXTENSION = "jpg"; private static final String JPG_MIME_TYPE = "image/jpeg"; @@ -55,6 +56,7 @@ public class DomainSearchThumbnailLoader { this.artifactsCache = artifactsCache; } + @Override public Image load(DomainSearchThumbnailRequest thumbnailRequest) throws TskCoreException, DiscoveryException { final SleuthkitCase caseDb = thumbnailRequest.getSleuthkitCase(); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailRequest.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailRequest.java index b3806ebeb1..ca2bbcdc5a 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailRequest.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailRequest.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.discovery.search; +import java.util.Objects; import org.sleuthkit.datamodel.SleuthkitCase; /** @@ -48,4 +49,25 @@ public class DomainSearchThumbnailRequest { public int getIconSize() { return iconSize; } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + if (!(other instanceof DomainSearchThumbnailRequest)) { + return false; + } + + DomainSearchThumbnailRequest otherRequest = (DomainSearchThumbnailRequest) other; + return this.sleuthkitCase == otherRequest.getSleuthkitCase() + && this.domain.equals(otherRequest.getDomain()) + && this.iconSize == otherRequest.getIconSize(); + } + + @Override + public int hashCode() { + return 79 * 5 + Objects.hash(this.domain, this.iconSize); + } } diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTest.java index 9cc4f5c49c..76fa103104 100755 --- a/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTest.java @@ -48,7 +48,7 @@ public class DomainSearchTest { }; when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); - DomainSearch domainSearch = new DomainSearch(cache); + DomainSearch domainSearch = new DomainSearch(cache, null); Map sizes = domainSearch.getGroupSizes(null, new ArrayList<>(), null, null, null, null, null); assertEquals(4, sizes.get(groupOne).longValue()); @@ -83,7 +83,7 @@ public class DomainSearchTest { when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); - DomainSearch domainSearch = new DomainSearch(cache); + DomainSearch domainSearch = new DomainSearch(cache, null); Map sizes = domainSearch.getGroupSizes(null, new ArrayList<>(), null, null, null, null, null); assertEquals(4, sizes.get(groupOne).longValue()); @@ -97,7 +97,7 @@ public class DomainSearchTest { when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(new HashMap<>()); - DomainSearch domainSearch = new DomainSearch(cache); + DomainSearch domainSearch = new DomainSearch(cache, null); Map sizes = domainSearch.getGroupSizes(null, new ArrayList<>(), null, null, null, null, null); assertEquals(0, sizes.size()); @@ -122,7 +122,7 @@ public class DomainSearchTest { when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); - DomainSearch domainSearch = new DomainSearch(cache); + DomainSearch domainSearch = new DomainSearch(cache, null); List firstPage = domainSearch.getDomainsInGroup(null, new ArrayList<>(), null, null, null, groupOne, 0, 3, null, null); assertEquals(3, firstPage.size()); @@ -150,7 +150,7 @@ public class DomainSearchTest { when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); - DomainSearch domainSearch = new DomainSearch(cache); + DomainSearch domainSearch = new DomainSearch(cache, null); List firstPage = domainSearch.getDomainsInGroup(null, new ArrayList<>(), null, null, null, groupOne, 0, 100, null, null); assertEquals(4, firstPage.size()); @@ -178,7 +178,7 @@ public class DomainSearchTest { when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); - DomainSearch domainSearch = new DomainSearch(cache); + DomainSearch domainSearch = new DomainSearch(cache, null); List firstPage = domainSearch.getDomainsInGroup(null, new ArrayList<>(), null, null, null, groupOne, 0, 2, null, null); assertEquals(2, firstPage.size()); @@ -206,7 +206,7 @@ public class DomainSearchTest { when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); - DomainSearch domainSearch = new DomainSearch(cache); + DomainSearch domainSearch = new DomainSearch(cache, null); List firstPage = domainSearch.getDomainsInGroup(null, new ArrayList<>(), null, null, null, groupOne, 3, 1, null, null); assertEquals(1, firstPage.size()); @@ -232,7 +232,7 @@ public class DomainSearchTest { when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); - DomainSearch domainSearch = new DomainSearch(cache); + DomainSearch domainSearch = new DomainSearch(cache, null); List firstPage = domainSearch.getDomainsInGroup(null, new ArrayList<>(), null, null, null, groupOne, 20, 5, null, null); assertEquals(0, firstPage.size()); @@ -257,7 +257,7 @@ public class DomainSearchTest { when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); - DomainSearch domainSearch = new DomainSearch(cache); + DomainSearch domainSearch = new DomainSearch(cache, null); List firstPage = domainSearch.getDomainsInGroup(null, new ArrayList<>(), null, null, null, groupOne, 0, 0, null, null); assertEquals(0, firstPage.size()); @@ -292,7 +292,7 @@ public class DomainSearchTest { when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); - DomainSearch domainSearch = new DomainSearch(cache); + DomainSearch domainSearch = new DomainSearch(cache, null); List firstPage = domainSearch.getDomainsInGroup(null, new ArrayList<>(), null, null, null, groupOne, 0, 3, null, null); assertEquals(3, firstPage.size()); @@ -327,7 +327,7 @@ public class DomainSearchTest { when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); - DomainSearch domainSearch = new DomainSearch(cache); + DomainSearch domainSearch = new DomainSearch(cache, null); List firstPage = domainSearch.getDomainsInGroup(null, new ArrayList<>(), null, null, null, groupTwo, 1, 2, null, null); assertEquals(2, firstPage.size()); @@ -359,7 +359,7 @@ public class DomainSearchTest { when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); - DomainSearch domainSearch = new DomainSearch(cache); + DomainSearch domainSearch = new DomainSearch(cache, null); int start = 0; int size = 2; From c8facbe5c72c0473e8406a114767ace75d84abdd Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 15 Sep 2020 12:23:33 -0400 Subject: [PATCH 065/130] 6715 domain summary viewer --- .../autopsy/discovery/ui/Bundle.properties | 3 + .../discovery/ui/DomainSummaryPanel.form | 115 ++++++++++++ .../discovery/ui/DomainSummaryPanel.java | 172 ++++++++++++++++++ .../discovery/ui/DomainSummaryViewer.form | 43 +++++ .../discovery/ui/DomainSummaryViewer.java | 86 +++++++++ .../autopsy/discovery/ui/DomainWrapper.java | 72 ++++++++ .../autopsy/discovery/ui/ResultsPanel.java | 70 ++++++- 7 files changed, 558 insertions(+), 3 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.form create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.java create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.form create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.java create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/ui/DomainWrapper.java diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties index baffc3ee43..3c7409d6b8 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties @@ -54,3 +54,6 @@ ObjectDetectedFilterPanel.text=Object Detected: DetailsPanel.instancesList.border.title=Instances DateFilterPanel.mostRecentRadioButton.text=Only last: DateFilterPanel.dateFilterCheckBox.text=Date Filter: +DomainSummaryPanel.activityLabel.text= +DomainSummaryPanel.pagesLabel.text= +DomainSummaryPanel.filesDownloadedLabel.text= diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.form new file mode 100644 index 0000000000..db3cda4dfe --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.form @@ -0,0 +1,115 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.java new file mode 100644 index 0000000000..bcbbd93e43 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.java @@ -0,0 +1,172 @@ +/* + * Autopsy + * + * 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.discovery.ui; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Point; +import java.awt.event.MouseEvent; +import java.text.SimpleDateFormat; +import java.util.Date; +import javax.swing.GroupLayout; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.JList; +import javax.swing.ListCellRenderer; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.coreutils.ImageUtils; + +/** + * Class which displays a preview and details about a document. + */ +class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer { + + private static final long serialVersionUID = 1L; + private static final Color SELECTION_COLOR = new Color(0, 120, 215); + private static final int MAX_NAME_STRING = 90; + private static final SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd yyyy"); + + /** + * Creates new form DocumentPanel. + */ + DomainSummaryPanel() { + initComponents(); + domainNameLabel.setFont(domainNameLabel.getFont().deriveFont(domainNameLabel.getFont().getSize() + 6)); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + domainNameLabel = new javax.swing.JLabel(); + sampleImageLabel = new javax.swing.JLabel(); + numberOfImagesLabel = new javax.swing.JLabel(); + activityLabel = new javax.swing.JLabel(); + pagesLabel = new javax.swing.JLabel(); + filesDownloadedLabel = new javax.swing.JLabel(); + + setBorder(javax.swing.BorderFactory.createEtchedBorder()); + + sampleImageLabel.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + sampleImageLabel.setIconTextGap(0); + sampleImageLabel.setMaximumSize(new java.awt.Dimension(100, 100)); + sampleImageLabel.setMinimumSize(new java.awt.Dimension(100, 100)); + sampleImageLabel.setPreferredSize(new java.awt.Dimension(100, 100)); + + org.openide.awt.Mnemonics.setLocalizedText(activityLabel, org.openide.util.NbBundle.getMessage(DomainSummaryPanel.class, "DomainSummaryPanel.activityLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(pagesLabel, org.openide.util.NbBundle.getMessage(DomainSummaryPanel.class, "DomainSummaryPanel.pagesLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(filesDownloadedLabel, org.openide.util.NbBundle.getMessage(DomainSummaryPanel.class, "DomainSummaryPanel.filesDownloadedLabel.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(domainNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 586, Short.MAX_VALUE) + .addComponent(activityLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(pagesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(filesDownloadedLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(numberOfImagesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(sampleImageLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(numberOfImagesLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 17, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(sampleImageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + .addGroup(layout.createSequentialGroup() + .addComponent(domainNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(activityLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(pagesLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(filesDownloadedLabel) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) + ); + }// //GEN-END:initComponents + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel activityLabel; + private javax.swing.JLabel domainNameLabel; + private javax.swing.JLabel filesDownloadedLabel; + private javax.swing.JLabel numberOfImagesLabel; + private javax.swing.JLabel pagesLabel; + private javax.swing.JLabel sampleImageLabel; + // End of variables declaration//GEN-END:variables + + @NbBundle.Messages({"# {0} - startDate", + "# {1} - endDate", + "DomainSummaryPanel.activity.text=Activity: {0} to {1}", + "DomainSummaryPanel.pages.text=Pages in past 60 days: ", + "DomainSummaryPanel.downloads.text=Files downloaded: "}) + @Override + public Component getListCellRendererComponent(JList list, DomainWrapper value, int index, boolean isSelected, boolean cellHasFocus) { + domainNameLabel.setText(value.getResultDomain().getDomain()); + String startDate = dateFormat.format(new Date(value.getResultDomain().getActivityStart()*1000)); + String endDate =dateFormat.format(new Date(value.getResultDomain().getActivityEnd()*1000)); + activityLabel.setText(Bundle.DomainSummaryPanel_activity_text(startDate, endDate)); + pagesLabel.setText(Bundle.DomainSummaryPanel_pages_text() + value.getResultDomain().getVisitsInLast60()); + filesDownloadedLabel.setText(Bundle.DomainSummaryPanel_downloads_text() + value.getResultDomain().getFilesDownloaded()); + if (value.getThumbnail() == null) { + numberOfImagesLabel.setText(Bundle.DocumentPanel_numberOfImages_noImages()); + sampleImageLabel.setIcon(new ImageIcon(ImageUtils.getDefaultThumbnail())); + } + setBackground(isSelected ? SELECTION_COLOR : list.getBackground()); + return this; + } + + @Override + public String getToolTipText(MouseEvent event) { + if (event != null) { + //gets tooltip of internal panel item mouse is over + Point point = event.getPoint(); + for (Component comp : getComponents()) { + if (DiscoveryUiUtils.isPointOnIcon(comp, point)) { + String toolTip = ((JComponent) comp).getToolTipText(); + if (toolTip == null || toolTip.isEmpty()) { + return null; + } else { + return toolTip; + } + } + } + } + return null; + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.form new file mode 100644 index 0000000000..715f837f05 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.form @@ -0,0 +1,43 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.java new file mode 100644 index 0000000000..068a47de31 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.java @@ -0,0 +1,86 @@ +/* + * Autopsy + * + * 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.discovery.ui; + +import javax.swing.DefaultListModel; + +/** + * + * @author wschaefer + */ +public class DomainSummaryViewer extends javax.swing.JPanel { + + private static final long serialVersionUID = 1L; + + private final DefaultListModel domainListModel = new DefaultListModel<>(); + + /** + * Clear the list of documents being displayed. + */ + void clearViewer() { + synchronized (this) { + domainListModel.removeAllElements(); + domainScrollPane.getVerticalScrollBar().setValue(0); + } + } + + /** + * Creates new form DomainSummaryPanel + */ + public DomainSummaryViewer() { + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + domainScrollPane = new javax.swing.JScrollPane(); + domainList = new javax.swing.JList<>(); + + setLayout(new java.awt.BorderLayout()); + + domainScrollPane.setViewportView(domainList); + + add(domainScrollPane, java.awt.BorderLayout.CENTER); + }// //GEN-END:initComponents + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JList domainList; + private javax.swing.JScrollPane domainScrollPane; + // End of variables declaration//GEN-END:variables + + /** + * Add the summary for a domain to the panel. + * + * @param domainWrapper The object which contains the domain summary which + * will be displayed. + */ + void addDomain(DomainWrapper domainWrapper) { + synchronized (this) { + domainListModel.addElement(domainWrapper); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainWrapper.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainWrapper.java new file mode 100644 index 0000000000..47ae242360 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainWrapper.java @@ -0,0 +1,72 @@ +/* + * Autopsy + * + * 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.discovery.ui; + +import java.awt.Image; +import org.sleuthkit.autopsy.discovery.search.ResultDomain; + +/** + * + * @author wschaefer + */ +public class DomainWrapper { + + private ResultDomain domain; + private Image thumbnail = null; + + /** + * Construct a new DocumentWrapper. + * + * @param file The ResultFile which represents the document which the + * summary is created for. + */ + DomainWrapper(ResultDomain domain) { + this.domain = domain; + } + + /** + * Set the thumbnail which exists. + * + * @param thumbnail The Image object which will be used to represent this + * domain object. + */ + void setThumnail(Image thumbnail) { + this.thumbnail = thumbnail; + } + + /** + * Get the ResultDomain which represents the Domain the summary was created + * for. + * + * @return The ResultDomain which represents the domain attribute which the + * summary was created for. + */ + ResultDomain getResultDomain() { + return domain; + } + + /** + * Get the image to be used for the domain. + * + * @return The Image which represents the domain. + */ + Image getThumbnail() { + return thumbnail; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java index 64f68d5515..702f4cedf8 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java @@ -46,6 +46,7 @@ import org.sleuthkit.autopsy.discovery.search.FileSearch; import org.sleuthkit.autopsy.discovery.search.SearchData; import org.sleuthkit.autopsy.discovery.search.ResultsSorter; import org.sleuthkit.autopsy.discovery.search.Result; +import org.sleuthkit.autopsy.discovery.search.ResultDomain; import org.sleuthkit.autopsy.discovery.search.ResultFile; import org.sleuthkit.autopsy.textsummarizer.TextSummary; @@ -60,6 +61,7 @@ final class ResultsPanel extends javax.swing.JPanel { private final VideoThumbnailViewer videoThumbnailViewer; private final ImageThumbnailViewer imageThumbnailViewer; private final DocumentPreviewViewer documentPreviewViewer; + private final DomainSummaryViewer domainSummaryViewer; private List searchFilters; private DiscoveryAttributes.AttributeType groupingAttribute; private Group.GroupSortingAlgorithm groupSort; @@ -82,6 +84,7 @@ final class ResultsPanel extends javax.swing.JPanel { imageThumbnailViewer = new ImageThumbnailViewer(); videoThumbnailViewer = new VideoThumbnailViewer(); documentPreviewViewer = new DocumentPreviewViewer(); + domainSummaryViewer = new DomainSummaryViewer(); videoThumbnailViewer.addListSelectionListener((e) -> { if (resultType == SearchData.Type.VIDEO) { if (!e.getValueIsAdjusting()) { @@ -116,6 +119,7 @@ final class ResultsPanel extends javax.swing.JPanel { } } }); + //JIRA-TODO } /** @@ -182,6 +186,8 @@ final class ResultsPanel extends javax.swing.JPanel { resultsViewerPanel.add(documentPreviewViewer); break; case DOMAIN: + populateDomainViewer(pageRetrievedEvent.getSearchResults()); + resultsViewerPanel.add(domainSummaryViewer); break; default: break; @@ -201,6 +207,7 @@ final class ResultsPanel extends javax.swing.JPanel { resultsViewerPanel.remove(imageThumbnailViewer); resultsViewerPanel.remove(videoThumbnailViewer); resultsViewerPanel.remove(documentPreviewViewer); + resultsViewerPanel.remove(domainSummaryViewer); //cancel any unfished thumb workers for (SwingWorker thumbWorker : resultContentWorkers) { if (!thumbWorker.isDone()) { @@ -212,13 +219,14 @@ final class ResultsPanel extends javax.swing.JPanel { videoThumbnailViewer.clearViewer(); imageThumbnailViewer.clearViewer(); documentPreviewViewer.clearViewer(); + domainSummaryViewer.clearViewer(); } /** * Populate the video thumbnail viewer, cancelling any thumbnails which are * currently being created first. * - * @param files The list of ResultFiles to populate the video viewer with. + * @param results The list of ResultFiles to populate the video viewer with. */ synchronized void populateVideoViewer(List results) { for (Result result : results) { @@ -233,7 +241,7 @@ final class ResultsPanel extends javax.swing.JPanel { * Populate the image thumbnail viewer, cancelling any thumbnails which are * currently being created first. * - * @param files The list of ResultFiles to populate the image viewer with. + * @param results The list of ResultFiles to populate the image viewer with. */ synchronized void populateImageViewer(List results) { for (Result result : results) { @@ -248,7 +256,7 @@ final class ResultsPanel extends javax.swing.JPanel { * Populate the document preview viewer, cancelling any content which is * currently being created first. * - * @param files The list of ResultFiles to populate the image viewer with. + * @param results The list of ResultFiles to populate the document viewer with. */ synchronized void populateDocumentViewer(List results) { for (Result result : results) { @@ -259,6 +267,21 @@ final class ResultsPanel extends javax.swing.JPanel { } } + /** + * Populate the domain summary viewer, cancelling any content which is + * currently being created first. + * + * @param results The list of ResultDomains to populate the domain summary viewer with. + */ + synchronized void populateDomainViewer(List results) { + for (Result result : results) { + DomainThumbnailWorker domainWorker = new DomainThumbnailWorker((ResultDomain) result); + domainWorker.execute(); + //keep track of thumb worker for possible cancelation + resultContentWorkers.add(domainWorker); + } + } + /** * Subscribe and respond to GroupSelectedEvents. * @@ -293,6 +316,7 @@ final class ResultsPanel extends javax.swing.JPanel { videoThumbnailViewer.clearViewer(); imageThumbnailViewer.clearViewer(); documentPreviewViewer.clearViewer(); + domainSummaryViewer.clearViewer(); resultsViewerPanel.revalidate(); resultsViewerPanel.repaint(); }); @@ -763,4 +787,44 @@ final class ResultsPanel extends javax.swing.JPanel { } + /** + * Swing worker to handle the retrieval of domain thumbnails and population + * of the Domain Summary Viewer. + */ + private class DomainThumbnailWorker extends SwingWorker { + + private final DomainWrapper domainWrapper; + + /** + * Construct a new DomainThumbnailWorker. + * + * @param file The ResultFile which represents the domain attribute the + * preview is being retrieved for. + */ + DomainThumbnailWorker(ResultDomain domain) { + domainWrapper = new DomainWrapper(domain); + domainSummaryViewer.addDomain(domainWrapper); + } + + @Override + protected Void doInBackground() throws Exception { + domainWrapper.setThumnail(null); + return null; + } + + @Override + protected void done() { + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + domainWrapper.setThumnail(null); + logger.log(Level.WARNING, "Document Worker Exception", ex); + } catch (CancellationException ignored) { + domainWrapper.setThumnail(null); + //we want to do nothing in response to this since we allow it to be cancelled + } + documentPreviewViewer.repaint(); + } + + } } From b9160bc045ea5fecbd26b7bea0b37390a61cdbde Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 15 Sep 2020 12:34:52 -0400 Subject: [PATCH 066/130] 6715 fix domain list model --- .../discovery/ui/Bundle.properties-MERGED | 8 ++++++++ .../autopsy/discovery/ui/DomainSummaryPanel.java | 5 ++--- .../discovery/ui/DomainSummaryViewer.form | 4 ++-- .../discovery/ui/DomainSummaryViewer.java | 3 ++- .../autopsy/discovery/ui/ResultsPanel.java | 16 ++++++++++------ 5 files changed, 24 insertions(+), 12 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED index df37ba0e3f..48f0a1aab7 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED @@ -36,6 +36,11 @@ DocumentPanel.numberOfImages.noImages=No images # {0} - numberOfImages DocumentPanel.numberOfImages.text=1 of {0} images DocumentWrapper.previewInitialValue=Preview not generated yet. +# {0} - startDate +# {1} - endDate +DomainSummaryPanel.activity.text=Activity: {0} to {1} +DomainSummaryPanel.downloads.text=Files downloaded: +DomainSummaryPanel.pages.text=Pages in past 60 days: GroupsListPanel.noResults.message.text=No results were found for the selected filters.\n\nReminder:\n -The File Type Identification module must be run on each data source you want to find results in.\n -The Hash Lookup module must be run on each data source if you want to filter by past occurrence.\n -The Exif module must be run on each data source if you are filtering by User Created content. GroupsListPanel.noResults.title.text=No results found ImageThumbnailPanel.isDeleted.text=All instances of file are deleted. @@ -108,6 +113,9 @@ ObjectDetectedFilterPanel.text=Object Detected: DetailsPanel.instancesList.border.title=Instances DateFilterPanel.mostRecentRadioButton.text=Only last: DateFilterPanel.dateFilterCheckBox.text=Date Filter: +DomainSummaryPanel.activityLabel.text= +DomainSummaryPanel.pagesLabel.text= +DomainSummaryPanel.filesDownloadedLabel.text= VideoThumbnailPanel.bytes.text=bytes VideoThumbnailPanel.deleted.text=All instances of file are deleted. VideoThumbnailPanel.gigaBytes.text=GB diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.java index bcbbd93e43..359b94c2a8 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.java @@ -24,7 +24,6 @@ import java.awt.Point; import java.awt.event.MouseEvent; import java.text.SimpleDateFormat; import java.util.Date; -import javax.swing.GroupLayout; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JList; @@ -33,7 +32,7 @@ import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.ImageUtils; /** - * Class which displays a preview and details about a document. + * Class which displays a preview and details about a domain. */ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer { @@ -43,7 +42,7 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer< private static final SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd yyyy"); /** - * Creates new form DocumentPanel. + * Creates new form DomainPanel. */ DomainSummaryPanel() { initComponents(); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.form index 715f837f05..a81f8e5223 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.form @@ -30,11 +30,11 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.java index 068a47de31..a9199ab1be 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.java @@ -61,6 +61,7 @@ public class DomainSummaryViewer extends javax.swing.JPanel { setLayout(new java.awt.BorderLayout()); + domainList.setModel(domainListModel); domainScrollPane.setViewportView(domainList); add(domainScrollPane, java.awt.BorderLayout.CENTER); @@ -68,7 +69,7 @@ public class DomainSummaryViewer extends javax.swing.JPanel { // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JList domainList; + private javax.swing.JList domainList; private javax.swing.JScrollPane domainScrollPane; // End of variables declaration//GEN-END:variables diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java index 702f4cedf8..54de9aa693 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java @@ -48,6 +48,7 @@ import org.sleuthkit.autopsy.discovery.search.ResultsSorter; import org.sleuthkit.autopsy.discovery.search.Result; import org.sleuthkit.autopsy.discovery.search.ResultDomain; import org.sleuthkit.autopsy.discovery.search.ResultFile; +import static org.sleuthkit.autopsy.discovery.search.SearchData.Type.DOMAIN; import org.sleuthkit.autopsy.textsummarizer.TextSummary; /** @@ -166,8 +167,9 @@ final class ResultsPanel extends javax.swing.JPanel { void handlePageRetrievedEvent(DiscoveryEventUtils.PageRetrievedEvent pageRetrievedEvent) { SwingUtilities.invokeLater(() -> { //send populateMesage - DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.PopulateInstancesListEvent(getInstancesForSelected())); - + if (pageRetrievedEvent.getType() != DOMAIN) { + DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.PopulateInstancesListEvent(getInstancesForSelected())); + } currentPage = pageRetrievedEvent.getPageNumber(); updateControls(); resetResultViewer(); @@ -256,7 +258,8 @@ final class ResultsPanel extends javax.swing.JPanel { * Populate the document preview viewer, cancelling any content which is * currently being created first. * - * @param results The list of ResultFiles to populate the document viewer with. + * @param results The list of ResultFiles to populate the document viewer + * with. */ synchronized void populateDocumentViewer(List results) { for (Result result : results) { @@ -267,11 +270,12 @@ final class ResultsPanel extends javax.swing.JPanel { } } - /** + /** * Populate the domain summary viewer, cancelling any content which is * currently being created first. * - * @param results The list of ResultDomains to populate the domain summary viewer with. + * @param results The list of ResultDomains to populate the domain summary + * viewer with. */ synchronized void populateDomainViewer(List results) { for (Result result : results) { @@ -281,7 +285,7 @@ final class ResultsPanel extends javax.swing.JPanel { resultContentWorkers.add(domainWorker); } } - + /** * Subscribe and respond to GroupSelectedEvents. * From 342195ad0f0720303bd0eec8bda52d7f0be99fa6 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 15 Sep 2020 12:39:22 -0400 Subject: [PATCH 067/130] 6715 fix cell renderer --- .../sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.form | 3 +++ .../sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.java | 1 + 2 files changed, 4 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.form index a81f8e5223..7489c56609 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.form @@ -32,6 +32,9 @@ + + +
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.java index a9199ab1be..849c9a9afd 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.java @@ -62,6 +62,7 @@ public class DomainSummaryViewer extends javax.swing.JPanel { setLayout(new java.awt.BorderLayout()); domainList.setModel(domainListModel); + domainList.setCellRenderer(new DomainSummaryPanel()); domainScrollPane.setViewportView(domainList); add(domainScrollPane, java.awt.BorderLayout.CENTER); From 15f088300dbe3c41d1886f5c80f830888fd540db Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 15 Sep 2020 13:09:59 -0400 Subject: [PATCH 068/130] 6715 make domain name font larger --- .../sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.java index 359b94c2a8..cb29bff5cc 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.java @@ -46,7 +46,7 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer< */ DomainSummaryPanel() { initComponents(); - domainNameLabel.setFont(domainNameLabel.getFont().deriveFont(domainNameLabel.getFont().getSize() + 6)); + domainNameLabel.setFont(domainNameLabel.getFont().deriveFont(domainNameLabel.getFont().getStyle(), domainNameLabel.getFont().getSize() + 6)); } /** @@ -136,8 +136,8 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer< @Override public Component getListCellRendererComponent(JList list, DomainWrapper value, int index, boolean isSelected, boolean cellHasFocus) { domainNameLabel.setText(value.getResultDomain().getDomain()); - String startDate = dateFormat.format(new Date(value.getResultDomain().getActivityStart()*1000)); - String endDate =dateFormat.format(new Date(value.getResultDomain().getActivityEnd()*1000)); + String startDate = dateFormat.format(new Date(value.getResultDomain().getActivityStart() * 1000)); + String endDate = dateFormat.format(new Date(value.getResultDomain().getActivityEnd() * 1000)); activityLabel.setText(Bundle.DomainSummaryPanel_activity_text(startDate, endDate)); pagesLabel.setText(Bundle.DomainSummaryPanel_pages_text() + value.getResultDomain().getVisitsInLast60()); filesDownloadedLabel.setText(Bundle.DomainSummaryPanel_downloads_text() + value.getResultDomain().getFilesDownloaded()); From 0865cd9fc7c43336b6757ef237892dde4502dd1e Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Tue, 15 Sep 2020 16:36:12 -0400 Subject: [PATCH 069/130] Removed email message artifacts from the drop down list --- Core/src/org/sleuthkit/autopsy/discovery/search/SearchData.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchData.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchData.java index 88f0b91e10..5effd4b65d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchData.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchData.java @@ -36,7 +36,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact; public final class SearchData { private final static long BYTES_PER_MB = 1000000; - private static final Set DOMAIN_ARTIFACT_TYPES = EnumSet.of(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY, BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG); + private static final Set DOMAIN_ARTIFACT_TYPES = EnumSet.of(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY); /** * Enum representing how often the file occurs in the Central Repository. From 71c0b08f707e31d43ee7222e2184f4f5ee3555dc Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 15 Sep 2020 17:17:06 -0400 Subject: [PATCH 070/130] Added tool tips to various lists and tables --- .../guiutils/SimpleListCellRenderer.java | 42 +++++++++++++++++++ .../guiutils/SimpleTableCellRenderer.java | 41 ++++++++++++++++++ .../interestingitems/FilesSetDefsPanel.form | 6 ++- .../interestingitems/FilesSetDefsPanel.java | 3 ++ ...PortableCaseInterestingItemsListPanel.java | 4 +- .../PortableCaseTagsListPanel.java | 4 +- .../SaveTaggedHashesToHashDbConfigPanel.java | 5 ++- .../DropdownListSearchPanel.java | 3 ++ .../keywordsearch/GlobalEditListPanel.java | 2 + .../GlobalListsManagementPanel.java | 2 + .../KeywordSearchJobSettingsPanel.form | 3 ++ .../KeywordSearchJobSettingsPanel.java | 22 +--------- 12 files changed, 113 insertions(+), 24 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/guiutils/SimpleListCellRenderer.java create mode 100755 Core/src/org/sleuthkit/autopsy/guiutils/SimpleTableCellRenderer.java diff --git a/Core/src/org/sleuthkit/autopsy/guiutils/SimpleListCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/SimpleListCellRenderer.java new file mode 100755 index 0000000000..589ce35a34 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/guiutils/SimpleListCellRenderer.java @@ -0,0 +1,42 @@ +/* + * 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.guiutils; + +import java.awt.Component; +import javax.swing.DefaultListCellRenderer; +import javax.swing.JLabel; +import javax.swing.JList; + +/** + * Simple extension of DefaultListCellRenderer that adds support for tooltips. + * The the tooltip text will be the same as the label text. + */ +public class SimpleListCellRenderer extends DefaultListCellRenderer{ + + private static final long serialVersionUID = 1L; + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + label.setToolTipText(label.getText()); + + return label; + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/guiutils/SimpleTableCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/SimpleTableCellRenderer.java new file mode 100755 index 0000000000..bbc5d995f5 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/guiutils/SimpleTableCellRenderer.java @@ -0,0 +1,41 @@ +/* + * 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.guiutils; + +import java.awt.Component; +import javax.swing.JLabel; +import javax.swing.JTable; +import javax.swing.table.DefaultTableCellRenderer; + +/** + * Simple Cell renderer for JTables that will set the value of the labels tooltip + * to be the same as the label. + */ +public class SimpleTableCellRenderer extends DefaultTableCellRenderer{ + + private static final long serialVersionUID = 1L; + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + label.setToolTipText(label.getText()); + return label; + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.form index cca6a8b5c8..5655a0ddd9 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.form @@ -329,6 +329,7 @@ +
@@ -401,9 +402,12 @@ - + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java index 7b41f71e25..1033c60dda 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java @@ -46,6 +46,7 @@ import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.guiutils.SimpleListCellRenderer; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; import org.sleuthkit.autopsy.ingest.IngestProfiles; @@ -648,6 +649,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp rulesList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); rulesListScrollPane.setViewportView(rulesList); + rulesList.setCellRenderer(new SimpleListCellRenderer()); setDescScrollPanel.setMinimumSize(new java.awt.Dimension(10, 22)); setDescScrollPanel.setPreferredSize(new java.awt.Dimension(14, 40)); @@ -676,6 +678,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp setsList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); setsListScrollPane.setViewportView(setsList); + setsList.setCellRenderer(new SimpleListCellRenderer()); fileNameButtonGroup.add(fileNameExtensionRadioButton); org.openide.awt.Mnemonics.setLocalizedText(fileNameExtensionRadioButton, org.openide.util.NbBundle.getMessage(FilesSetDefsPanel.class, "FilesSetDefsPanel.fileNameExtensionRadioButton.text")); // NOI18N diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/PortableCaseInterestingItemsListPanel.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/PortableCaseInterestingItemsListPanel.java index 55da66a73d..dd11137a0a 100644 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/PortableCaseInterestingItemsListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/PortableCaseInterestingItemsListPanel.java @@ -207,7 +207,9 @@ class PortableCaseInterestingItemsListPanel extends javax.swing.JPanel { setFont(list.getFont()); setBackground(list.getBackground()); setForeground(list.getForeground()); - setText(value + " (" + setCounts.get(value) + ")"); // NON-NLS + String text = value + " (" + setCounts.get(value) + ")"; + setText(text); // NON-NLS + setToolTipText(text); return this; } return new JLabel(); diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/PortableCaseTagsListPanel.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/PortableCaseTagsListPanel.java index 247db77517..2e4a8c98cd 100644 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/PortableCaseTagsListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/PortableCaseTagsListPanel.java @@ -203,7 +203,9 @@ class PortableCaseTagsListPanel extends javax.swing.JPanel { setFont(list.getFont()); setBackground(list.getBackground()); setForeground(list.getForeground()); - setText(value + " (" + tagCounts.get(value) + ")"); // NON-NLS + String text = value + " (" + tagCounts.get(value) + ")"; + setText(text); + setToolTipText(text); return this; } return new JLabel(); diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/taggedhashes/SaveTaggedHashesToHashDbConfigPanel.java b/Core/src/org/sleuthkit/autopsy/report/modules/taggedhashes/SaveTaggedHashesToHashDbConfigPanel.java index 9520b28706..081aa03b61 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/taggedhashes/SaveTaggedHashesToHashDbConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/taggedhashes/SaveTaggedHashesToHashDbConfigPanel.java @@ -221,7 +221,10 @@ class SaveTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { setFont(list.getFont()); setBackground(list.getBackground()); setForeground(list.getForeground()); - setText(TagUtils.getDecoratedTagDisplayName(value)); + + String text = TagUtils.getDecoratedTagDisplayName(value); + setText(text); + this.setToolTipText(text); return this; } return new JLabel(); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.java index d12f6a0012..7b84080217 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/DropdownListSearchPanel.java @@ -42,6 +42,7 @@ import javax.swing.table.TableColumn; import org.openide.util.NbBundle; import org.openide.util.actions.SystemAction; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.guiutils.SimpleTableCellRenderer; import org.sleuthkit.autopsy.ingest.IngestManager; /** @@ -94,6 +95,7 @@ class DropdownListSearchPanel extends AdHocSearchPanel { column.setCellRenderer(new LeftCheckBoxRenderer()); } else { column.setPreferredWidth(((int) (leftWidth * 0.89))); + column.setCellRenderer(new SimpleTableCellRenderer()); } } final int rightWidth = rightPane.getPreferredSize().width; @@ -105,6 +107,7 @@ class DropdownListSearchPanel extends AdHocSearchPanel { column.setPreferredWidth(((int) (rightWidth * 0.38))); } } + keywordsTable.setDefaultRenderer(String.class, new SimpleTableCellRenderer()); loader = XmlKeywordSearchList.getCurrent(); listsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalEditListPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalEditListPanel.java index 8dbf3032a4..35b141f98c 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalEditListPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalEditListPanel.java @@ -36,6 +36,7 @@ import org.netbeans.spi.options.OptionsPanelController; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.guiutils.SimpleTableCellRenderer; import org.sleuthkit.autopsy.ingest.IngestManager; /** @@ -76,6 +77,7 @@ class GlobalEditListPanel extends javax.swing.JPanel implements ListSelectionLis } keywordTable.setCellSelectionEnabled(false); keywordTable.setRowSelectionAllowed(true); + keywordTable.setDefaultRenderer(String.class, new SimpleTableCellRenderer()); final ListSelectionModel lsm = keywordTable.getSelectionModel(); lsm.addListSelectionListener(new ListSelectionListener() { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListsManagementPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListsManagementPanel.java index 554f791d05..b086ffc614 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListsManagementPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListsManagementPanel.java @@ -38,6 +38,7 @@ import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.sleuthkit.autopsy.guiutils.SimpleTableCellRenderer; import org.sleuthkit.autopsy.ingest.IngestManager; /** @@ -63,6 +64,7 @@ class GlobalListsManagementPanel extends javax.swing.JPanel implements OptionsPa listsTable.setTableHeader(null); listsTable.setShowHorizontalLines(false); listsTable.setShowVerticalLines(false); + listsTable.setDefaultRenderer(String.class, new SimpleTableCellRenderer()); exportButton.setToolTipText(NbBundle.getMessage(this.getClass(), "KeywordSearchEditListPanel.customizeComponents.exportToFile")); copyListButton.setToolTipText(NbBundle.getMessage(this.getClass(), "KeywordSearchEditListPanel.customizeComponents.saveCurrentWIthNewNameToolTip")); listsTable.getParent().setBackground(listsTable.getBackground()); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchJobSettingsPanel.form b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchJobSettingsPanel.form index ae97e69fb1..ac3cdd5782 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchJobSettingsPanel.form +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchJobSettingsPanel.form @@ -99,6 +99,9 @@ + + +
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchJobSettingsPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchJobSettingsPanel.java index ae8797b992..a71485cbb1 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchJobSettingsPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchJobSettingsPanel.java @@ -32,6 +32,7 @@ import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableColumn; import org.sleuthkit.autopsy.coreutils.StringExtract.StringExtractUnicodeTable.SCRIPT; +import org.sleuthkit.autopsy.guiutils.SimpleTableCellRenderer; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; import org.sleuthkit.autopsy.keywordsearch.KeywordSearchIngestModule.StringsExtractOptions; @@ -84,7 +85,6 @@ public final class KeywordSearchJobSettingsPanel extends IngestModuleIngestJobSe if (i == 0) { column.setPreferredWidth(((int) (width * 0.07))); } else { - column.setCellRenderer(new KeywordTableCellRenderer()); column.setPreferredWidth(((int) (width * 0.92))); } } @@ -183,25 +183,6 @@ public final class KeywordSearchJobSettingsPanel extends IngestModuleIngestJobSe displayEncodings(); tableModel.fireTableDataChanged(); } - - /** - * Simple TableCellRenderer to add tool tips to cells. - */ - private static final class KeywordTableCellRenderer extends DefaultTableCellRenderer{ - - private static final long serialVersionUID = 1L; - - @Override - public Component getTableCellRendererComponent( - JTable table, Object value, - boolean isSelected, boolean hasFocus, - int row, int column) { - JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - label.setToolTipText(label.getText()); - return label; - } - - } private class KeywordListsTableModel extends AbstractTableModel { @@ -278,6 +259,7 @@ public final class KeywordSearchJobSettingsPanel extends IngestModuleIngestJobSe listsTable.setShowHorizontalLines(false); listsTable.setShowVerticalLines(false); listsScrollPane.setViewportView(listsTable); + listsTable.setDefaultRenderer(String.class, new SimpleTableCellRenderer()); titleLabel.setText(org.openide.util.NbBundle.getMessage(KeywordSearchJobSettingsPanel.class, "KeywordSearchJobSettingsPanel.titleLabel.text")); // NOI18N From 0d75e9330014852c3e6378664e64329fe335e795 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Tue, 15 Sep 2020 18:13:34 -0400 Subject: [PATCH 071/130] Added a number of visits group by option --- .../discovery/search/Bundle.properties-MERGED | 4 ++ .../discovery/search/DiscoveryAttributes.java | 12 +++- .../discovery/search/DiscoveryKeyUtils.java | 63 +++++++++++++++++++ .../search/DomainSearchCacheLoader.java | 11 +++- .../discovery/search/ResultDomain.java | 10 ++- .../autopsy/discovery/ui/Bundle.properties | 1 + .../discovery/ui/Bundle.properties-MERGED | 2 + .../discovery/ui/DomainSummaryPanel.form | 21 +++++-- .../discovery/ui/DomainSummaryPanel.java | 23 +++++-- 9 files changed, 133 insertions(+), 14 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED index 102aaf6890..e1cbc654a1 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED @@ -7,6 +7,7 @@ DiscoveryAttributes.GroupingAttributeType.interestingItem.displayName=Interestin DiscoveryAttributes.GroupingAttributeType.keywordList.displayName=Keyword DiscoveryAttributes.GroupingAttributeType.mostRecentDate.displayName=Most Recent Activity Date DiscoveryAttributes.GroupingAttributeType.none.displayName=None +DiscoveryAttributes.GroupingAttributeType.numberOfVisits.displayName=Number of Visits DiscoveryAttributes.GroupingAttributeType.object.displayName=Object Detected DiscoveryAttributes.GroupingAttributeType.parent.displayName=Parent Folder DiscoveryAttributes.GroupingAttributeType.size.displayName=File Size @@ -23,6 +24,9 @@ DiscoveryKeyUtils.InterestingItemGroupKey.noSets=None DiscoveryKeyUtils.KeywordListGroupKey.noKeywords=None DiscoveryKeyUtils.MostRecentActivityDateGroupKey.noDate=No Date Available DiscoveryKeyUtils.NoGroupingGroupKey.allFiles=All Files +# {0} - totalVisits +DiscoveryKeyUtils.NumberOfVisitsGroupKey.displayName={0} visits +DiscoveryKeyUtils.NumberOfVisitsGroupKey.noVisits=No visits DiscoveryKeyUtils.ObjectDetectedGroupKey.noSets=None FileGroup.groupSortingAlgorithm.groupName.text=Group Name FileGroup.groupSortingAlgorithm.groupSize.text=Group Size diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java index 90cb880cc2..e8180749c4 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java @@ -596,6 +596,14 @@ public class DiscoveryAttributes { } } + + static class NumberOfVisitsAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(Result result) { + return new DiscoveryKeyUtils.NumberOfVisitsGroupKey(result); + } + } /** * Attribute for grouping/sorting by objects detected @@ -721,6 +729,7 @@ public class DiscoveryAttributes { "DiscoveryAttributes.GroupingAttributeType.object.displayName=Object Detected", "DiscoveryAttributes.GroupingAttributeType.mostRecentDate.displayName=Most Recent Activity Date", "DiscoveryAttributes.GroupingAttributeType.firstDate.displayName=First Activity Date", + "DiscoveryAttributes.GroupingAttributeType.numberOfVisits.displayName=Number of Visits", "DiscoveryAttributes.GroupingAttributeType.none.displayName=None"}) public enum GroupingAttributeType { FILE_SIZE(new FileSizeAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_size_displayName()), @@ -734,6 +743,7 @@ public class DiscoveryAttributes { OBJECT_DETECTED(new ObjectDetectedAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_object_displayName()), MOST_RECENT_DATE(new MostRecentActivityDateAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_mostRecentDate_displayName()), FIRST_DATE(new MostRecentActivityDateAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_firstDate_displayName()), + NUMBER_OF_VISITS(new NumberOfVisitsAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_numberOfVisits_displayName()), NO_GROUPING(new NoGroupingAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_none_displayName()); private final AttributeType attributeType; @@ -768,7 +778,7 @@ public class DiscoveryAttributes { * @return Enums that can be used to group files. */ public static List getOptionsForGroupingForDomains() { - return Arrays.asList(FREQUENCY, MOST_RECENT_DATE, FIRST_DATE); + return Arrays.asList(FREQUENCY, MOST_RECENT_DATE, FIRST_DATE, NUMBER_OF_VISITS); } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java index b00fee63e8..059f66a675 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java @@ -1101,6 +1101,69 @@ public class DiscoveryKeyUtils { return dateNameString; } } + + static class NumberOfVisitsGroupKey extends GroupKey { + + private final String displayName; + private final Long visits; + + @NbBundle.Messages({ + "DiscoveryKeyUtils.NumberOfVisitsGroupKey.noVisits=No visits"}) + NumberOfVisitsGroupKey(Result result) { + if (result instanceof ResultDomain) { + Long totalVisits = ((ResultDomain) result).getTotalVisits(); + if (totalVisits == null) { + totalVisits = 0L; + } + displayName = Long.toString(totalVisits); + visits = totalVisits; + } else { + displayName = Bundle.DiscoveryKeyUtils_NumberOfVisitsGroupKey_noVisits(); + visits = -1L; + } + } + + @Override + @NbBundle.Messages({ + "# {0} - totalVisits", + "DiscoveryKeyUtils.NumberOfVisitsGroupKey.displayName={0} visits"}) + String getDisplayName() { + return Bundle.DiscoveryKeyUtils_NumberOfVisitsGroupKey_displayName(Long.toString(visits)); + } + + @Override + public int hashCode() { + return Objects.hash(displayName); + } + + Long getVisits() { + return visits; + } + + @Override + public boolean equals(Object otherKey) { + if (otherKey == this) { + return true; + } + + if (!(otherKey instanceof NumberOfVisitsGroupKey)) { + return false; + } + + NumberOfVisitsGroupKey visitsKey = (NumberOfVisitsGroupKey) otherKey; + return visits.equals(visitsKey.getVisits()); + } + + @Override + public int compareTo(GroupKey otherGroupKey) { + if (otherGroupKey instanceof NumberOfVisitsGroupKey) { + NumberOfVisitsGroupKey visitsKey = (NumberOfVisitsGroupKey) otherGroupKey; + return Long.compare(getVisits(), visitsKey.getVisits()); + } else { + return compareClassNames(otherGroupKey); + } + } + } /** * Key representing an object detected group diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java index 999aab0425..99101cf053 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java @@ -136,6 +136,10 @@ class DomainSearchCacheLoader extends CacheLoader - + + + + + @@ -49,19 +53,21 @@ - - + + + - + + @@ -111,5 +117,12 @@
+ + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.java index cb29bff5cc..ccf0eb96c4 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.java @@ -64,6 +64,7 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer< activityLabel = new javax.swing.JLabel(); pagesLabel = new javax.swing.JLabel(); filesDownloadedLabel = new javax.swing.JLabel(); + totalVisitsLabel = new javax.swing.JLabel(); setBorder(javax.swing.BorderFactory.createEtchedBorder()); @@ -79,6 +80,8 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer< org.openide.awt.Mnemonics.setLocalizedText(filesDownloadedLabel, org.openide.util.NbBundle.getMessage(DomainSummaryPanel.class, "DomainSummaryPanel.filesDownloadedLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(totalVisitsLabel, org.openide.util.NbBundle.getMessage(DomainSummaryPanel.class, "DomainSummaryPanel.totalVisitsLabel.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -86,10 +89,13 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer< .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(domainNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 586, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(domainNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 539, Short.MAX_VALUE) + .addGap(47, 47, 47)) .addComponent(activityLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(pagesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(filesDownloadedLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(filesDownloadedLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(totalVisitsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addComponent(numberOfImagesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) @@ -104,17 +110,19 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer< .addGroup(layout.createSequentialGroup() .addComponent(numberOfImagesLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 17, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(sampleImageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) + .addComponent(sampleImageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(layout.createSequentialGroup() .addComponent(domainNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(activityLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGap(11, 11, 11) + .addComponent(totalVisitsLabel) + .addGap(11, 11, 11) .addComponent(pagesLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(filesDownloadedLabel) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) + .addGap(0, 0, Short.MAX_VALUE))) + .addContainerGap()) ); }// //GEN-END:initComponents @@ -126,12 +134,14 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer< private javax.swing.JLabel numberOfImagesLabel; private javax.swing.JLabel pagesLabel; private javax.swing.JLabel sampleImageLabel; + private javax.swing.JLabel totalVisitsLabel; // End of variables declaration//GEN-END:variables @NbBundle.Messages({"# {0} - startDate", "# {1} - endDate", "DomainSummaryPanel.activity.text=Activity: {0} to {1}", "DomainSummaryPanel.pages.text=Pages in past 60 days: ", + "DomainSummaryPanel.totalPages.text=Total visits: ", "DomainSummaryPanel.downloads.text=Files downloaded: "}) @Override public Component getListCellRendererComponent(JList list, DomainWrapper value, int index, boolean isSelected, boolean cellHasFocus) { @@ -139,6 +149,7 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer< String startDate = dateFormat.format(new Date(value.getResultDomain().getActivityStart() * 1000)); String endDate = dateFormat.format(new Date(value.getResultDomain().getActivityEnd() * 1000)); activityLabel.setText(Bundle.DomainSummaryPanel_activity_text(startDate, endDate)); + totalVisitsLabel.setText(Bundle.DomainSummaryPanel_totalPages_text() + value.getResultDomain().getTotalVisits()); pagesLabel.setText(Bundle.DomainSummaryPanel_pages_text() + value.getResultDomain().getVisitsInLast60()); filesDownloadedLabel.setText(Bundle.DomainSummaryPanel_downloads_text() + value.getResultDomain().getFilesDownloaded()); if (value.getThumbnail() == null) { From 15ced57a034ce98f5527172dee9c89d760e842af Mon Sep 17 00:00:00 2001 From: apriestman Date: Tue, 15 Sep 2020 18:23:09 -0400 Subject: [PATCH 072/130] Updated command line doc --- docs/doxygen-user/command_line_ingest.dox | 49 +++++++++++++++--- .../images/command_line_ingest_options.png | Bin 31524 -> 24634 bytes .../images/command_line_ingest_profile.png | Bin 0 -> 31547 bytes 3 files changed, 41 insertions(+), 8 deletions(-) create mode 100644 docs/doxygen-user/images/command_line_ingest_profile.png diff --git a/docs/doxygen-user/command_line_ingest.dox b/docs/doxygen-user/command_line_ingest.dox index 97c521c685..431f96865b 100644 --- a/docs/doxygen-user/command_line_ingest.dox +++ b/docs/doxygen-user/command_line_ingest.dox @@ -6,15 +6,25 @@ The Command Line Ingest feature allows you to run many of Autopsy's functions fr \section command_line_ingest_config Configuration -Go to Tools->Options and then select the "Command Line Ingest" tab. +To configure command line ingest, go to Tools->Options and then select the "Command Line Ingest" tab. If you would like to create or open multi-user cases, you'll need to \ref install_multiuser_page "configure the multi-user settings". \image html command_line_ingest_options.png -Use the ingest module settings to configure how you want to run ingest. This is the same as normal \ref ingest_page "ingest module" configuration - choose a file filter then enable or disable the individual ingest modules, changing their settings if desired. Press "OK" to save your settings. +\subsection command_line_ingest_profile Configuring Ingest Profiles -Use the report module settings to choose and configure a report type. Only the selected report type will be generated. Configuration is generally the same as normal \ref reporting_page "report generation" with some slight differences. This is mainly seen in places where your options are dependent on the open case, such as choosing \ref tagging_page "tags" to report on or \ref interesting_files_identifier_page "interesting file" set names to include. For example, the HTML report normally allows you to choose specific tags to include but for command line ingest it will only have the option to include all tags. +From the options panel you can configure the default ingest profile. This is the same as normal \ref ingest_page "ingest module" configuration - choose a file filter then enable or disable the individual ingest modules, changing their settings if desired. Press "OK" to save your settings. -If you would like to create or open multi-user cases, you'll need to \ref install_multiuser_page "configure the multi-user settings". +Currently custom ingest profiles can not be configured on the command line ingest options panel but they can be created through the \ref ingest_page "ingest options panel" and then used on the command line. Here we've created an ingest profile that will only process image file types and will only run certain ingest modules. + +\image html command_line_ingest_profile.png + +See the section on \ref command_line_ds "running ingest" below for instructions on specifying an ingest profile on the command line. + +\subsection command_line_report_profile Configuring Report Profiles + +You can set up report profiles to use with command line ingest. You'll start with a "default" profile and can create additional profiles. Each profile will allow you to generate one type of report. Configuration is generally the same as normal \ref reporting_page "report generation" with some slight differences. This is mainly seen in places where your options are dependent on the open case, such as choosing \ref tagging_page "tags" to report on or \ref interesting_files_identifier_page "interesting file" set names to include. For example, the HTML report normally allows you to choose specific tags to include but for command line ingest it will only have the option to include all tags. + +If you wish to create additional report profiles, select "Make new profile" in the drop-down menu and then click the "Configure" button. You'll be prompted to name your new report profile and then will go through the normal report configuration. Having multiple report profiles will allow you to easily generate different report types from the command line. For example, you might have an "htmlReport" report profile that creates the HTML report and another report profile to generate KML reports. See the \ref command_line_report "report generation" section below for directions on how to specifiy a report profile on the command line. \section command_line_ingest_commands Command Options @@ -35,11 +45,15 @@ The table below shows a summary of the command line operations. You can run one Open Existing Case 
--caseDir
--caseDir="C:\work\Cases\test5_2019_09_20_11_01_29"
Add a Data Source
--addDataSource
---runIngest (optional)
--dataSourcePath
--addDataSource --dataSourcePath="R:\work\images\small2.img" --runIngest
+--runIngest (optional)
--dataSourcePath
+--ingestProfile (optional)
--addDataSource --dataSourcePath="R:\work\images\small2.img" --runIngest
-Run Ingest on Existing Data Source
--runIngest
--dataSourceObjectId
--runIngest --dataSourceObjectId=1
+Run Ingest on Existing Data Source
--runIngest
--dataSourceObjectId
+--ingestProfile (optional)
--runIngest --dataSourceObjectId=1
-Generate Reports
--generateReports
 
--generateReports
+Generate Reports
--generateReports
+--generateReports=(report profile name)
 
--generateReports
+--generateReports="kmlReport"
Create List of Data Sources
--listAllDataSources
 
--listAllDataSources
@@ -92,6 +106,13 @@ autopsy64.exe --caseDir="C:\work\cases\test6_2019_09_20_13_00_51" --addDataSourc --dataSourcePath="R:\work\images\green_images.img" \endverbatim +Next we'll add a third data source ("red_images.img") to the case and run ingest using a custom ingest profile "imageAnalysis" created as described in the \ref command_line_ingest_profile "Configuring Ingest Profiles" section above. + +\verbatim +autopsy64.exe --caseDir="C:\work\cases\test6_2019_09_20_13_00_51" --addDataSource --runIngest + --dataSourcePath="R:\work\images\red_images.img" --ingestProfile="imageAnalysis" +\endverbatim + Finally we'll add a folder ("Test files") as a logical file set to a new case ("test9"). \verbatim @@ -132,6 +153,12 @@ autopsy64.exe --caseDir="C:\work\cases\test6_2019_09_20_13_00_51" --addDataSourc --dataSourcePath="R:\work\images\small2.img" --runIngest --generateReports \endverbatim +The example above uses the default report profile. If you set up a custom report profile as described in the \ref command_line_report_profile "Configuring Ingest Profiles section" above, you can specify that profile after the --generateReports option. + +\verbatim +autopsy64.exe --caseDir="C:\work\cases\test6_2019_09_20_13_00_51" --generateReports="html" +\endverbatim + \subsection command_line_listds Listing All Data Sources You can add the --listAllDataSources at any time to output a list of all data sources currently in the case along with their object IDs, to be used when \ref command_line_existing_ds "running on an existing data source". This command can even be run alone with just the path to the case. @@ -160,7 +187,13 @@ If everything works correctly, you'll see a log of the processing being done and \section command_line_ingest_results Viewing Results -You can open the case created on the command line like any other Autopsy case. Simply go to "Open Case" and then browse to the output folder you set up in the \ref command_line_ingest_config section and look for the folder starting with your case name. It will have a timestamp appended to the name you specified. +You can open the case you created directly from the command line by specifying either the case folder or the path to the ".aut" file. Remember that the folder name will have a timestamp appended to your case name. +\verbatim +autopsy64.exe "C:\work\cases\xpCase_2019_09_20_14_39_25" +autopsy64.exe "C:\work\cases\xpCase_2019_09_20_14_39_25\xpCase.aut" +\endverbatim + +You can also open the case normally through Autopsy. Simply go to "Open Case" and then browse to the output folder you set up in the \ref command_line_ingest_config section and look for the folder starting with your case name. It will have a timestamp appended to the name you specified. \image html command_line_ingest_open_case.png diff --git a/docs/doxygen-user/images/command_line_ingest_options.png b/docs/doxygen-user/images/command_line_ingest_options.png index 015c2dee455d8f3c71619f9ac324856b91e42ba8..4e42611368837edc763e884d1d216de444d0d6cc 100644 GIT binary patch literal 24634 zcmd43bx>Si(=|$Pm*5^8g1bZT5Zv9JV1qls-Q9z`6WrYi!QFKj-1Sa=&-2#z-B<2+ z>;84Cpo*C}XYVt6_wLoJS2y8`@=_>>1c(q25Gc}L#g!o-AY~vRKJ385g5P%xd!Kn;w}NY6-odofV9#Mtcx2yd)=t#v}Z zOcJO}<{*5TXP`)w4SVd1!1I<6?n6hH&^0d38DrYp;_W)y-UaGKS$O0=I|U`@k3!^r z6&QE!C)cNmvDfB1^fC5VqYQq?a$oz2^ikMR&-F3dY1v448Y@cIJVx^q&bS_f8*2sL z=SvQNxDw~s{h^*Zk3B&ByURisjh|6zDWgTJyc3o*19>oq_(*9%1OdZ<<@{IH_`KJk zP``o8l2NL}3Pi~m51TK+dk?+uTW-zfR@Q&y5UGA_;I6)fLH6qXoUa9)o2=SpL-<>4 zeFHvlXY@?a97o6C@It~i`$qy}sLwy7^7mXMGT|psz*s)XP;I?Nb(KLNuR}sr*x7@8 zvV+k)WmRm%wif{Ehq?+5oH zVOQ{*aL&?l5^#G6XxK<}HOqO-;J5IdB{ZGI>}_q$?3^LQ9Lb`Q?>E*3D-}?T(!JhaWobJ#K9~2ihA`w*_u}JU<#&}Zcp{Z%b zLEe_uowvsdyFX7*@U3t``=^Ach!^6{{R4mKoTN-IJdqN;HYNFv$V9XQ8af-Ms2zL5 z{o7le1vUGq>{%Sd^z-c)J-gRkFVD*LB9ye?Nv68A$l&u7EJAe_by`m*TwM(*H$H4&}W2 z-M5G9eGwZQ+xuol3c@mjngr+XP1`HzGWy2G#_paosc-iMifWT~Lr0__@QgZDoVr%Pcx z%0KD)_Tr&?cfH0f6uepEhYiuN9585{*VdMC5_zjiOjqy#tYJ-;P0;)J&x6$08TG@K zmzRtB>Z_>@hM*AgsTCI$@LOkuEZZEM`@Qp9D3Dl8RjFv+9@y#o`LN?!108s?vjkic z3X&~a4@0(z-uCPZb^UyL+KPV?Ef0nen{_oKG*6jLVd)%pnrte(rLZL&Oy$uV;Qlk; z*kLamY2j8?^N8ox2Uujh-`{AlJ8p5%gdVnvFl6*q)yxbYS(AofWzCVM-|y~QbnQ4$ z^7BoO7MXMEXDwPT7gm299Jl`#9i6IjauR?Xo_c#>+?&Pdbq>-ajQDyHL9vQ;uqPW& zivgZ3=zH1+DA>5$9;hnlL=9RPOeN6FwiVC$Q-M~4`8EMhfUvJimSrSDb1_S!9|N6O zJ{~^McqEQ&4n>aK>LvQa=J)9AR|zvpx%+A8<+KD}dhaKEslslUzx#YtYzSVplN7}O zdHMchK1~L5oV}MgQl>ZFu~ve!bO+*n8hOXwkJ1IR67Qwd3DwEIpWJP3S~q5a)*YCA;d`^%yhUeto}GV{y~`FSiVo}9(+Lk^5=%= z4`y#_eB1m`NiM;x-=vD4q&aZ*BxUpO_k`a5hAsOgHCQ=xFrgZlHff%bkx{ETAub{A z_#XY)vn9P|nh(& zvvkClC<>K7(gIibxhutq>{3|&Iu@|R86hfI!5y3LIp;!eSiB1FQNo>90>`7D8)_F&##}u;6dy}-~&z3DqS!D=4E87U99Izz& zzxacOr?1x!H7*km-?Pg$Jpzbh+G~A)sZmHywZ8I#fs-`6H^;*__B;{3y_0nXu6JjQ zJ4-VWTfv^it7AG$^7R^u>bCs^&OXgjbGn~xRMHX?#rWEnYK@@UO}CT&nQ%tbs^`at zss$Fkk9CdD4Nz-b_s;`X^5lesBaho?t?qdd@8^s3kA+eg~n9O`r zK}id)>u^@qDb4FUq-&^Y+P@3|=bL^TMH*kDIo*oQPJX|?*Bm@kNP1~aYnZmiB)6;- zuODTW@S>D)jfOM{{&30gNh>;MRQIbbTz?3Pgwo1ylknp`*-dN*r&7vuJ_=HVrE<4A zBe7rSPP@C}LzE!H&`n7D?f~grFZxFvuG(Iep(>}t-_`1fEr%)}XPx#!?Kr~pr2@tldeb*y3FE1}Klge_3N5k6)MQmfMijoqB!n++Y_j|5Q$gsra<$=cN z_|BPGR%Oc?nC-$J}nPj5Qn#{j^?>5`j6R^gO zp&=7XR(KyV*fsP3vu1fyJl~8sb2pE(%0HjVWk~9JE~OIDb`;l?(Z^;74_{ zkIA=xyKC9dfrMhKC}RGUT;_33@wn>eoW~R%>TsH?w~seoSD*C$xvm!-f&f_LZ4#T^~t<)0yfgP?IxtH=&JT4@IG1f(LMDCFPeFTW}7;o zRadveedgY#yGaoXMompgEjcI%y05=~(7%&1=+w0x(4);j8zE|HN@-+dR238_(5T(A z;Qo3md?kE7kB<8+M^14@N!~Zv<1eqvd1MEc~PAY0@HT!;Zpy(|s zs-cw3hF1ei%QJ_DB=ht00quGa;*yg2KtAxpfPEX51Q{P6LE>o8pz$_%^JxSGbO(|h z2J_25#|poxR4xqTv$Y7zmt;~ON~|$Cw7X2_5~k|Fg+K@!j{9j`_rl3M^pmPbKn2T_ z86Ok$A3L)-Y<*$Ck*PS9pzZ7LtK}zB%@&TGJ*Ffh6Cv^le=Y?BXKx^!30rz;RaKEe zw>y)5Wl>X8L|E8YXFUqGKYc$%0 z`VNgVpNlN+vZU{PK#}`S*_0a|_7z)74QnyF^{c5nCI+jK=5JPdf4_Y{$hI~i(c`abv;42zT%97I>8Kpz})mD$GHb2{g>j$>T7CL1js9T^i-j8T8cuLp6d#b}$*>hDKwF~!H0 z87Gf59>o+JE z#bTSJ0+w<1)<<*4v&cuAxepKSya}GA_E-|zM>7So85{^4+<_s;WV{|k5aHqBg?`tl zF~kij+OAPo{n1I@_=DlIfTiz!;glbxq$#Ke!;8f*KT~HsM8RUMwK%YydA7LM<&@HD z`7P+h5c9h(pCBS3nGA$s9JNjP+^-m#eR%2p{>lRg}(q+oK8f72|t7&25aH zfz8gShJ0eH4IRE1lU(j?xu&(Hr6Cv+mo`0-hBNIyrrtu#;Nxe}zADHkbxy@8Z5F*> z_!$C&t2)%4xf%-0*(n^`q{L^wp{L85%TlvP7~gd?8M5I=>dR4QkBsn?S4@xoth5@+ zwaXGmeou=!4nmcs1ABn{f&v62w2~FOVUX+ioG#kd!*Y4Yg8}?IkkaEx1J4u@+HN0Aa9f6ZhAyl4 z$8dyfq&ZB&M=GY&Z#I=$L>qEjC>?s0~vfjWhB7E{pADx7zf?r-ApmnO#u5#5Bcuf*KR2VL7$TseOHJVIkj& z;M-~epImfw+JyPj{kg*a@oZ`NSdTxH88nERlao_iTwGDh1v!x`GsFq%@yPF#rwsBg zFKv@dNS%tBizw3;FFl=AH#cG60z>TaG9Req65JNaxir1#c>0x5YAp7;_s$yCCu8J? zh=rv?&cR%nFBl7!Q%66xh1{nWWm5?V5S7d>SG7Ig0^Q`EULGzH*Uk`Hvd(_oe$Buc z9gOTIV?G~7Cg7NB_EX0p;#Ho&RCvQ^epXs5A5XM`l&d%#iC^XMevlc8&UDaPz1)T) zW$}8OZZUF)ly}=obMC)@?#f9TJM?=LTSO$yk+wtcW$`E@lrd>l!AE)+coIn!j zcA*v4zUHTXOc2U^2#|KBJH(PT47MaqWE)w#69_gi{XGw@k&7*}5gh+oU;j{F9P*Hc z2N6Q$llv~{n$ugb1JNRU=WBh(9~L7Is^g<-D8#_Wma8mws=I@1E6ywXEGH)iLj2aS zEGsS!EtiA&23}uYpC=BSNSMq?>HDi2USa4 z%}9|xo{dr(AG4WaYLcp?qSqn_jE|~J5OujV(5l<<`XD+g zV{D8#?nqPTd@Qnday!J4W$~>#ZyN_p)84yJjmz@#;?qju39{^D8Bu#-OESSPWDiIt z-aN%axf=>qq_>BvviOQ>cgniiY+RXSXh<*2Y@L15Sc`%$JL$xl>s>Y(Uo7QZe;z#= z3qOY_7%ij!_=b8KI$`GjEIT$8f^&<~`Am}ZN7JA+mJt}P`x~8F0e|XkHkqaD&`G8< zN9!{)GdFb9a@5A}AHMk;?33o#mC}5%(%dHVm|&zLcn#R}EZTb4>AHIh*X%otluRAV zjqL&Od$WsJB+;xEdezHc6ei z!G10){YH#2gL?L~AYuchH=y$zA7|LV;D?6*Wk+H31sVXT8yFtOAS8@kEmHED5z*5_ zadB}0$5;MWSGz>QO1;Cmb60zb_a=3C&6sgWp*ds}6oDNb0)2gbrRC*2;4m5W;iaOc zYbP(1WG9+?1Kq+UF(N`GZ4wH=$IQXJr7jnR2S_L^3>EXWKbgbVtP}f*$^aEaq{=|P?Yqk_BKs(J$N6UvaeNi!ZCu$ zOee-oyP3aV!(`@Enl5B;hWsvL*b9yhmd&t8(%}7$^1VLLvUauvUuZCKzf7R#Em16; zld>fap|l1J1snJD&Gm7hb<13h0Tg_`q{QcGNR4z&L^L#uo0e6jRlF>@h`vQQSEu*a z`}?oi{BCC*2MRnH#oG(pS?pN^eFiR6Vb;w-sjAJJaD5-b$~wfgvul=A zR+eqw%;uTtn<>~XEuT$ISLRGEFCX`txu}Z5?`XWk9?})gsjVf%6Z~D#8XtZyBeAIY)%u(2CP2f!|-ZWW}euI_ku$_ozl!y_Xp zsHsE1UtfRfRPP8^La9YlXS~%K1&L{m1Msqj;0!YNeeAo&dU^a*jw9zIhG(b2fPVZK zNt1;jo}NF`sA+RUp&Z^Xii{o-PJ41IDNpilK&?O^qN0)*RzyP1z!23ZYQi|8=f?Ri z4vLo|`S7!`F$o+&IxXtCU2cbxM)bG&FIPVJ&K%q^ow?Lq=54d(eD^(MqFL>U3#!Smlqs8O4yC zwITm8GFfu3NrHMGe5P(rndIOO#g!qAX>~`(qofKa|K**r8qi+gX)r9z{IJ&BjB}nzDwGK_8S9fkD)%Q;q&EQOFg8 zRn|v%+#`e>mgoQgASgH(gP3^T+z&CYtfpqzlnrpX14D#@vUJ0zDv>v3b?BW8mC2Y+ zFzo(u0zv$QH7%SxfCZ~>rk2%HljrhsCMlJ-%!$+Zk6ap-*ik?TK2mZCeRxdz=k%iS z39w%nGl>7s?lh)?K<_wnxA!qJuhyuR;YeH_vf$&l z5?m>?zlV7hRWY44h)kB8!ijKNxH~-0_j_j7QX@jW;Cbh*UjBh# z2%&r>G5Eyu_Iio=v;zYJh7HSMF)^@F2F?iChik1);!?vG`|l)0Z=zV{AjpW(paVyf znkIJd3l><`G)qpBU47%9wA8AC3BS7A1D$5MU64N?|sTS62RLW@fh2$mH1n0Kmfb ziOxs9Ul02OQnxB^j}?AB?sh-QJBNPVSozgGxZOh9%-yip+U_PU&YMVGbn{II7L{lO z%x)hJxVw+}E$)DeXkem zM%?%v6F?`=gydO_sXV<;QTWo!oGBbnzcznF0c{Fe*2wOSwalXzD(q z;6YO|0-5)Gcig_txjt(jOpf;&vy!m+TpBahbkyf8>SqSc;zypS z3(mUpF*S$hiMfLF_uV(zUOPKG0dJqodjnv=D11GqqHwvFsBn2y5DQxw`aQBphCKkW zph%`O_t`4@l=Ee(*})55X3-Ryu14;csc9l&_ox2Egulzb8T|DOdI5K>i>oMAchdxh=I8ttJL4;kip3z{L7Rroh4INi1o8^*)^oP z5|(^6pMEwWku_E1$joGUY$TbSzIXUl8joUYl5 zqT`Wsxz0X6%ApasVf^^<Y$2(VDP*(sKJMg(u5?PSztObvkd@uezwyd=ypey zxdX&B9yRD`Sts~~o8i!&sj$;~2SltlAAR7=EVfFUL=5L*hwAS+{-ekl9pXtd9IN+5 z4Rl0%l%~jlBWq-qM!v%mtb@<$0=cjaXwiY!XkL|bc5V!tv2!@Nu^Q6BBYs==F>SSJz#nr@CFaI{{D$HRTpr2P>u&b_CO^81E$1lw?jLZa!+m3h(Loxyq!<>cQv!Zun zRiV7x_2|)2^iy(jvbcnV6IicOOkx51CF03MOzXlYZ_N1knV?XEpW(0>mK;xCp-}jz z1zz!)D`j^hUq6d+vghJ}`fXiz7Ic3Sa{DRPLfmEv`)zPXe^znmOCIS*d#CX8yf!GU z(Fs|#ed&{P;TC=ycsA7A)&J(3FFkK%9kF$g={H^w`=(Arr;Beq+K$&!rc{t80@mH2 z5F?nKj09+#OK{wQZ858$uA%mh<=BnT=Hr^Bgy>(Ay?QIdoHqE1Aaa)_Y{Aj9cUOqS4e zUKe#5D{ntkV)j{aMnrjrZ+Jt@N8~(!{D6lC5e`mH3=9miDcmQ44A^2EnaGrV-%yL3 zH+VID$Whj?b@Jwz>75xA)a;x1NvocFA8_GuUOAN+iVs&oW)v2b8zo zb237%HyVytrWm%bO*A#}FyiCEqvw12CLcMrLk%eFq#>(Cj$UWg9ZY186iqpv%+Y~U zvZXclrW0vA1O(-!6>g4s)I=;wdZ3?g#+Y=NryXwOsONfOoT}tu`$K!C#?S2zS;8`b zghQJgS%AbYF&7ukA_KLnnGJ{RmU4i}TyrffcVBjNCk+T~6QvBqp1l;G*_uF%_8pky4{UQ&}y!xL8p%T-~^g zrg*#hk&yanoo?mWdB?_DR4wxr=p&>XDsQ;GohE3(`Yx29)iR}`rY73yNR607+6}EVSEdOUja z;AK10Qmk}i;RHFhI(V?jg13J14g1#|-I^VDdATuLx zu9%)4BLINVqa=Gk29^Px-k~t9EFBbW-3*nnR24|eGd9H%*AW9l2K(N$8B#1`KpJ80 zOQL3GR3<}F@u=w4nv&7qj29}sn`~yhW4|c94#bzASo#7}!T3$tA4(Ix8${3CU>ZiQ zg5YhU73p{a*NfaH)C>L9TY{IyA&+Xps+>zQ98>?7{s(h;Q0Q>LnI9tG}Bkow~Jwm$CqnANhj{7^)el)S%$)* z&hh5%S0_M{!+r#ngpzl+Gdxj&%jP>6ZYRv0nv26aG%gm~G?lS1UE7Hpmfiojny6q> zPYWi1)f54S%EW!nO|$if8e_K1{gIPGw9e@;0$#^L=JCbfzk7m_aKVmZe;^$5<#F1N znt>q;*S9sO^vDwIlfuKodiEXhfjJ!5%@rgTi2%RKVrtG$cWPB&BZbVwPU2wJB+0nLGuH#a2^ZDt?6P4&;?f!eq*@QEJiq}<3V$P7)bqDx@O|BaFt7`UZ z^PgbDvb41PnV07ezC25wrmn6|TuKTP6H^QfRA4=ZnvBeU)vjHRq;M7G?UwtUO8&^? zWwl#yYAPEhOMn+jkDJwTFH_+Cr8~?dh+c;Qp)(esA{soKY;hFMs#Cyn;Ip~reLV?Y*E%USQS*l7 z>uc9Mni-e%MFoi0r&|iJ-~)Cv1`8w4o6qCok%K##IoG%n8@@Psl)BLZZx6ALvF{I@ zI5G^pyw`(d;1Zs^zf>r0SpNn9))}d&f>}+54B67Xff;S&?&6dP8tmKK@dEd2(HtBc z7$hW&s2E^1x9?XFw+SV@=&GriAgw&QCstz1m;bgj=)aMIU1Af|WV72MJ|2r*uKwDf z>6|ag@rn<4! z*mk&V#MjmpIymZ6%Q>1pVTPn5<6VHRlQ#Z3i`!r^ZTu84N>x#uKM`Q-`?e-2QiHbi z!ADmhm60x0M4a+oxto&NT;cMYUAGU_;FG8MT|H0+t$%G|Pd|1yK}|(^nQif0liB=i zyUNFUi>He>&rDcwm0=L%n8nPNVgd&z4kL2zFyp~OS z5vU>69JTd1Jt)u+^}b!kLqU3+qv3LGuTeT7 z_e0QkmV2-fm)+NAi~KjS zWN5M0lSX z$!o;+JwZob(?O}pJ%TyNN~L^|-WNxFF;-@K%sNA5(o}>n!)zh`vN!$y&b_*p_m%KAgMU*z(%APr`~jzy)jd<7Wy zpE=*MYex0!hJJe7^&?suOPP9L{G9~JwI&o(2U>B717yCOW^m@(f;V97BeflS6K;*b z2*a+d#9cyoSJX;Vcu4mLtbjq;I5zD;S+>a3!`eJUuZDHr@%EJ4n@V7rf=u`F2mVc+(`j z=u+*~_&arQC7U}Z_5Fy^4PR<@+N+81nRM0_da2F}Z2dgD6UE7J=|zRLW@p7)H0=rfM5a&;FEs&z zeL<@lSBdHVw+|b!#KWN8Y7%qXAAzCKm<}xF=J5@AKR`(i4~D2(?5oX1QR$}pM0*Yh zNhCR67Zip7wTA6=?*o8B=VBDl(;s@#wj&zwt{s;^=Vg%MbDkLus%)%WmwaWo5`%%Hy))O4dL#V5`WN^{!l z48`oazAxH7)(2-3pNy+((*;d}1_2f)DBIH@ThlL{>A!xa*DKb|rSBG2ymIjdZ;J%0 zB1lmSPrIG5Y{azCL?ZY-(dSz7$xiJw0e{5P$zJ$@=o>)OP;3%N+#*)tWc4p6*C0QJ z-!V)W<+@y#6MJuy_!UrtS*O-oy*9{d!y~32mj~DrQ!m1+pV>Ut)8dfAYIfv@Kuvd3 zm|$xat=%nfK~8nPCz@M$)Qq!gNzv%Z#?kR4gfbha9|FUI+;ZRAPEWHTEU}|pR;7ymzm9H ze@)cU@cctNmU+GY;>;}rBG$RHtO847WflsS&8B>B2u^-}C_H{(QD|mKHy@q_BV2Sp zoV~@`64L-cf%N-_y7Y-1L0|lesR89s;JIkGUaIVlKco<^@1uO&(~OHiyjD-APJ2Av z37vozk$npAmAQ>pJ0>+KhX7f57*u@xvKMLXN}4vgNqv95vUAC`Q!za4BM1<}3d+Hj zSxpy4YC2v`YoX+KnDlq+ks}!%h)umvb~|u+Wy7P=X$~U!>5W^3sm1nPy5Tnhk73|y zLKZJ>j#o?|7|-r1@#$!L@J2lIQF1=)(9j!6M-I-e9!_(!G3%94h!5q{`(95p*IE#E zAuEQic6I(hX`ZHX^4xj@4}1ZT$6=RIXZ2G<06Q&DR(gBkk?ja{TWM5%$=am&6(W8&eb?UUg@bsszs=*B+2m+o>KFdqVe(H`6BJrlMtv~<__ zB{df2SH>xav=ho)4$ou8cUU#1))4_aZrGQ%#i-_#3Ahd3`8yTwcUf6?HSpl`3sqIE zjy=s+kD?a9laXky>#bEuRGMghAx63mq)BdA+aBhi?&m zAB8s?@hv`RTOm!XV?CvE+YZ(lbbh!CD&;oKg^r%2@(s^7R!&Id$CCMG5t}%5N9eF# z5ZoaT8!LOZ*>Rcoe&939VYm7upkR7;NCHv+IPdSwv(Y(EIaUfIz}F-kE2|IN6BJs% zI>A5(-UBLo!h7?(!~Lc^;o1oeYSZh!)zKe+Tw6bYu1)>*pX<(XouBGl1h%yl-$wR! z;>?;FXLQs{`MB%}kh;5)y?kwLGA?EnwD^@j;9MMuAqcR0B-T}ByU393M(#}wRvilb z=G(~F^}H@Yw~X*eVT1Dh3bfpu0zZ zV5R45OaQ~pEjxcpyQoM?-NQ{rVc=`Z{R0X0%L6R$0Tag4CXUm2^>WAiwUwaq2DoZ4 zBKUhrgh_Bk2)N|kjirGS-p6Btap}vHW2Z*YpSwrI1}^tanCYdUhvGVQi_V+Owb_HK z>rv*9?gt7RZaEBDpWw;BHSo^SdxNLTv)r=jt@`J`2xX>pYYNQ6ok;|jz7QyX7R(Dm}Fu>&rG{HFpET5O>kKH&Fi+5pVI>Lc^&Am--g!f3!{ zkbtqVu>l0pn)sxoxr*C+;GzQG_Gb~c|DllbhKKlxb1h#Y(z`~ZMxRk16Ffz=w5dP` z7pt`4-`Y&k;R{l@*I}t`0vs9gq<^X~p%cTXFuwgWae(wuhi1Y*5qr?qS5a_1KRoq6 zC7*ee&f*N=hW}J)VtiZVBW`o~0Uh+W)OW<)y^8#wip{@q{(ou+$Q!N;LxL7*QKh7! z3I{(+3*W$>!(2b6oPTiwc&Ze;wqxqce+GgVMFQuaslWfbG;~GuKQ$BlH;m!`UOf7r zC;!jg2>+!$;s3*kf6T-;Tj49_Bj&BmX5>5FY-q>9X(E9!=g#SeJmw{5s=Leiz2>Q= zYi+CcPw;)%WGOFj!r;qYW~Qo>3(ie1v&1TC>rI%od-HG?^_nn!3or!a=6n1FM2 z){Z2tob8X>HEXqdfFq~xK4U$sJo_=fR#wKiJ{Q}tdB5l4eT&zS_E^W}<+SePNI|2iZO?ptv+lWT zfp<5b&t|TOe)>i^F%W03-p!t=jEj(6zXtNBLtWLpvr@ZR@;;a&lH*L)!e&b%*``|P z&rU3GG;^!g$aB(ZOm`+O= zE70;jy&vcCsWHHsRbjPrb2{HpWa}m;pR&$S&uRT!i0xBpbkRzT>p0tqu=p5X_xY68 zguEP@vBvjz+Ofu;zVJ8SzY~6wS*ZWy*1_DLD%_Pu@wOa{W6PlHKS!wmE^uvro!jQivMHZrxE*`+he1>fmYH}Chh&z+H6)}HOQU$q~qYe>A_ z+#MH#g!GZ0`8{+SwbbEuw83o+1jB#!?Td@z@KnEIJJH(00RKcco3Pb?9bX@t8crm$ zg;DTqN=*B6C*8$Rn-#OXr{N2>lBE&JRmpDR0|4~b6H9!3!f`%Lb!{Ac{SWCmqXPPc z58{sB+XEgg)cB4;j}&Pr(hd02YzIr9HoGFMDm0oYoW&M}t2&P}3X{}bj?Fw?+S+~X z*v&hH}$3I7i$um2f|De6nQQ3E>v@<~0jj8vn6`Ylu)dD#fHe1xsnxgRc4@@2190wJmTzmsqedCw*F76_{7m*F@JB-Q-EFISSsI~dC3 zn(rkHv3`6zv7fk3!37eIDs=~*+}M|P%3Ba;n?sG*5?D`-7EAm0>H$@yZOA>T zNHAdd9*+O*6}#W`^ULK{1v|#o1zDnsl3Tgwv8xeH2p}KXzsmZLRy$trR@XJReDIfA zN5-%%^;@(>ZyAgb0`F0N+ZzzMVywEIJjfPe?aL!ngjli{{8>d zUGQJp4gP;IqF&$;Kd#X)?KV&x2Y>}&t)~FuPXC0t&bIdF*NSq5VEVhXBTN7T zyl8HoRPlC)hJr_AWtH-QzZNaM`a3=M<{kcCGX8Vw{v`ZTvnsvOdVucT8Q5gaO(gZT zB0X{IEJHYtk|K>_;~x=IP-btl8RRF;mX4~8KpFSTcLso#-3%-^ylM?*nBbhTPq#5juy~a|^C=-egPi1h%oLkpFL1?zk zem2b$h%f_FQ|QBnVVH=XeZAVUfq(5BE633d5(UHzHd6 zbqjp-n{1f-??RfwO>QLU(0OR#R1kLu%2`&!+YW~RhNN)@>`^TvxzH-6|16i@%nyYXcI-DflewW3w(^U z(Tje6HP}54O$S!BL&PY`B8HQVp`v5sJN3-MhW7WK@F#6;B2W={l2NY!Rf-1PkZ_3* z&c;(%RlBMuh0r#9DY&9rbRjktMP9a|M-}U4&tPP5O|U;%ZMSy`H66y%xJ_2e-y6`! z|0Z`;FM<<>6`RLANjpmLdwBw6dVVX5 zo*NO16_lvsN&~T^#621Uw!_Y^0A59boCz8gcfcgmSB8V%4_FDZgT3Q-%TG)&&{kqP zo5%F5Gsk5)hFvxoVkXLX3U)_A_Uv3LU%|~KzQhA)U1{C|ye)n!1r>ECqxz-~7GZys zk?WSy-;ge>jDSmYXzLsDgQ`*|_VlP?zcduke34Ub(5j#KWJkJp-M>f3oj~yz_+pPF1h*3}PWSdrOQq3;irQ{n0tu5lNie1bm zHQ>giW&L+3+Lt_Og9ljgO^H{=swoDere)6s{q6?S;16U}ella5X>UeOl3e7H5h0Fz zKGCJFP#98>V&l-z_F9b)j{OOWzYhNd-$|SDhdsTy`A6T?Ck<&YC#{Bx+i)8t{dCr3 zV`gKC6*3BT$l7M8S(5(%PR6EKgvy$Z+8>?QZ2YdAi(33Xx17!G9ko3?y`i)3xnO zN9z{hVzY5TC`%jJnzr%TwrX~Y?P5!dMDA54G;^$$%AVA|D`3Q4U1cjy@a#E5ufw?# zz$zs6w2Jdp6&iAlUUg%X{fe*y5Z2JIsI(?I6lBiSBqP}5PjLXt{EpfgZHzelP~I*;G2u- z``P2q*R^H(JsA>A&~hBs!+M|LZS_3VDjzjfDRG-`&`zh75UE=yT6CH!7M1&Hl-@`i zHh$rXjpS<%Xgy}W@Gl^r@P}xptm?nRtZufe4{xS;Jl<^$8+rhy2Nd|hOGImB`oEjN>BGVI=;WZ#`~&#EasH>~zyH^0tU-?h=uPg8 z(Ibt(tQIXU*__XNbp@?ZO`T94A79~N{bkj9PLweOpXFO3cpPt>OYXY&Q*;Kbh)p-U zeEza-PvrEFzts4@GFFiRWdn)-jp7mig;(|~+S%JKv%{JD6ezkqHRHlPtuQ*=(*2V*czqypO_?@-p<`p@kI|B^2~K0oL%3gJ{+`4G!&eA9=}$EiOWh3il098T+6ey}m%JJiB}~W}?dTj#N_|>2G0lVo zUfayN)$?$scG{T6OorT6p9Airetk$UQgkI)&D?au9^^~6w~*_-e8lB(7W{PG2-wvj zayXJyFEbQIEecq#=^PqrMs>KkZuU;6+w^6um+ZRFxjSmhX5QG0?Z4!;@4O?hCw3T7 znhTw|r8r%I9d~}2lf>5K^Q-BTmEG0RG+*IA6VMe7=?kdcCsZ9aao%jvx5 zjc^YJ!TJoCcVPda;X2XkjsEN?DC+!s}00K!zw*{=qg-rJ?IAOyLs6>31S*RhQp25CY-=mD>rYQc)3wZHk5p6bcH6T-xWJv(8=X+_V3?f8GE179afJ8{X%6 z-t|83u?rr0X+y5{waos6|AhPZ%Z|T5g!S^NPS>06=`j~Kv(@Dr101XmhZ4M~1dU<< z_nR>KuiQa^`;-9uo&%`Jgv19d*mm_+DGFf~a&Ts7F%&OtUj zZ$=7B*y+b;xV5UYd(Kt{0EBSgYj%3zubp3v*5ecM%l*6?|4d$lamh{jZQiQR-U z*WZ7si8$k>Fe4F1Ux<|zMt(0ZFplr*?n~U}QhLCyyer#z#WeoL`tvRwIPbit-46jR z>R%8TG0-xX4}5T9#a6U|-trHiKTOMUK1wpmJEyHufXZVwoUQB2SHT=<_>p~}gU;n> z&;8=YK6=pIH}Tdc=zI{4^t1WHVjnN4e}6W_Jeyx(>mCWH5lCYFtoKEfD>7}3D9Y$} z9Q(BMZ%%d#?&aDpTU^5UMW0t5XA6iYbLFlO@`Sz91Ze3#_m6E*mUDcT-H)g*#-q^7 z(H*sshs@WtIqVuAf?8_YGh9RUkKLdvDCLg2_2&<2srzNEEQr>1!3cfl80wza6HlqU zQ2qB6utPz|s(I3<+7#De}&{6@;eC}#OQb7K8=rd zHlzMXb?g<*y#NEbA67$378Wy?m&A#S*gaKEp2CP;y1rEdJeHBlkFJCndKUm5u+O3$(4Jldf zJ*57`a@MFUo_lG6Ijv+No@4cKZDjt>dr8jmQ9z zoElqq;Q9^zlS-Tn_zZ`KxeHDOE%EGTf0ftOTp#im2(jbS5f1yDlFZF%bN6oZ*76fO zr{>sr266MK)+W;<9tD_B;@SYk<1z!j=n{Yxje)YxzD-`lm@8_?mcII-=B2-@bx#xf z10s!8;_cjW-CtF|r*>a}+W%)lb`8d!0*Bn3zpwTOV_)%<&iQ9s+kaO^>{NXm z4FBN~0E>%W`U(4NF@M{j&iDaf3!pI^*mAQg^_YIJ0yzG0pqD@R*%m| z<*wAm`khmEyLafGTI9Y>hf98J(BIp)gCV(nT4>iimhEkddp*DDeq1aEN?$eS66PWF zm|Ctxh}3a6w(g8#ZIwHKcoSSzTIkPT;Bv=y$$j{nQ%2VNEoLSq9-C$F$;mxDEhl$t zm)r&Se>?o^8Q(wu5OwhMACZp!tLZM)=wjhNGkH!{?$*N zJEnBABu(zG+e(9AW=oODhyZ!N8)>Mak3A7ZDOTFjh~Azuc=D^W@LFbfi4sf4G4R!R zu@V?b{#ZP?5qJ%&l64}t=Jkcf(GRpRMJQa%zR0!;*pzV80>Y?^;5vTey*E6vTYX<~ zp8$6%v^c@QYtJJ%^*Xq`MvU5!t~OEB^j^k;>QyR0o;izaCjh28du;kwuFGfC7~~jW1o^$oR4AD1c*p-oxBce^(N^%cbyMp7>g5LJ zH}E&kM)VhTv;+Z>!f1=q56FYpuz-E^B-0&Pkpn^&bKXckFp$2hCK`IMgVV?;Z=H@E zt?i01t)Q)TR_&z|JlpCtfjgDFFoZhqy6IjnXnAASADEpUc!HViie4&^bJEy1HzF|a ziB&qIrnWqqx0~W?ARX;`K!nB4yz=I}51eCQB>3A(SOLvHEK`yw8A|#>j_`FvGLQk5 z3m$>0j20c)0ez6X5)2yrn~2Ma56fs1FFboH!C;-)l}!mWLfDDw`4h7+3N6{Cz==Wy8ZqA8~gz&U(y%s?Pe z^1@pa{+5r%&(R+v@oiUnTR>tBa%h-#X+6Tpv8?`_sesY_?zX;uy|F2As!-_&lpIH! zESyu@P3bK`FTz_(H6okF!hb_Azv;T-5YqU&EY?3^|w|Ts*;(@1#O!(83JR3sy2W&6{825fCPyVghhGZ z6w72WWW?f$4%05GVhN@P7Iq$^c`o(W67Cks0$9x2tdkHxzpOXKW-1~Hvf}N$G)){N zi-(AO!i<t}>whNlqT-E3_i`NwB1DC*!ufUAKwJ1Fr|8tOF{IP40G zxI4XpEIpr(xO9sy633*xGEh``bF7a@BI!UE24A&ZtdJ*J+?HcYR=9$y~j(T!vhra`CBjI+9*i#OHmI-=v9@Uwya zyM;LR?VAE*fiN-@(;!#f0|H>S%GD3aO8ehK+BeBfKC9mz+rC z-y8n;@%iKOwpBOBj-$ueZ1OvKhTeX;TdcCMKO=iiPENsD4p|&≧P_;+Z_42E~+XDeXK0dtzp(=K>7B2= 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 literal 31524 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 z diff --git a/docs/doxygen-user/images/command_line_ingest_profile.png b/docs/doxygen-user/images/command_line_ingest_profile.png new file mode 100644 index 0000000000000000000000000000000000000000..8d417c837c7e26699628ac0f3f19e570052b74f0 GIT binary patch literal 31547 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 Date: Tue, 15 Sep 2020 18:30:26 -0400 Subject: [PATCH 073/130] Minor changes and fixed tests --- .../discovery/search/DiscoveryKeyUtils.java | 9 +++--- .../search/DomainSearchCacheLoaderTest.java | 30 +++++++++---------- .../search/DomainSearchTestUtils.java | 6 ++-- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java index 059f66a675..6a4c7eb1c3 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java @@ -1108,6 +1108,8 @@ public class DiscoveryKeyUtils { private final Long visits; @NbBundle.Messages({ + "# {0} - totalVisits", + "DiscoveryKeyUtils.NumberOfVisitsGroupKey.displayName={0} visits", "DiscoveryKeyUtils.NumberOfVisitsGroupKey.noVisits=No visits"}) NumberOfVisitsGroupKey(Result result) { if (result instanceof ResultDomain) { @@ -1115,8 +1117,8 @@ public class DiscoveryKeyUtils { if (totalVisits == null) { totalVisits = 0L; } - displayName = Long.toString(totalVisits); visits = totalVisits; + displayName = Bundle.DiscoveryKeyUtils_NumberOfVisitsGroupKey_displayName(Long.toString(visits)); } else { displayName = Bundle.DiscoveryKeyUtils_NumberOfVisitsGroupKey_noVisits(); visits = -1L; @@ -1124,11 +1126,8 @@ public class DiscoveryKeyUtils { } @Override - @NbBundle.Messages({ - "# {0} - totalVisits", - "DiscoveryKeyUtils.NumberOfVisitsGroupKey.displayName={0} visits"}) String getDisplayName() { - return Bundle.DiscoveryKeyUtils_NumberOfVisitsGroupKey_displayName(Long.toString(visits)); + return displayName; } @Override diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoaderTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoaderTest.java index 2a75ca2dc7..bad7df2423 100755 --- a/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoaderTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoaderTest.java @@ -36,12 +36,12 @@ public class DomainSearchCacheLoaderTest { public void load_GroupByDataSourceSortByGroupNameAndDomain() throws DiscoveryException, TskCoreException, SQLException { DomainSearchCacheLoader loader = mock(DomainSearchCacheLoader.class); List domains = Arrays.asList( - DomainSearchTestUtils.mockDomainResult("google.com", 10, 100, 5, 4, 110), - DomainSearchTestUtils.mockDomainResult("yahoo.com", 1, 5, 7, 20, 100), - DomainSearchTestUtils.mockDomainResult("google.com", 5, 20, 1, 4, 105), - DomainSearchTestUtils.mockDomainResult("facebook.com", 2, 2, 1, 3, 110), - DomainSearchTestUtils.mockDomainResult("abc.com", 1, 2, 3, 4, 100), - DomainSearchTestUtils.mockDomainResult("xyz.com", 1, 2, 3, 4, 20) + DomainSearchTestUtils.mockDomainResult("google.com", 10, 100, 3, 5, 4, 110), + DomainSearchTestUtils.mockDomainResult("yahoo.com", 1, 5, 3, 7, 20, 100), + DomainSearchTestUtils.mockDomainResult("google.com", 5, 20, 3, 1, 4, 105), + DomainSearchTestUtils.mockDomainResult("facebook.com", 2, 2, 3, 1, 3, 110), + DomainSearchTestUtils.mockDomainResult("abc.com", 1, 2, 3, 3, 4, 100), + DomainSearchTestUtils.mockDomainResult("xyz.com", 1, 2, 3, 3, 4, 20) ); SearchKey key = new SearchKey(null, new ArrayList<>(), @@ -69,11 +69,11 @@ public class DomainSearchCacheLoaderTest { public void load_GroupByNothingByGroupNameAndDomain() throws DiscoveryException, TskCoreException, SQLException { DomainSearchCacheLoader loader = mock(DomainSearchCacheLoader.class); List domains = Arrays.asList( - DomainSearchTestUtils.mockDomainResult("google.com", 10, 100, 5, 4, 110), - DomainSearchTestUtils.mockDomainResult("yahoo.com", 1, 5, 7, 20, 100), - DomainSearchTestUtils.mockDomainResult("facebook.com", 2, 2, 1, 3, 110), - DomainSearchTestUtils.mockDomainResult("abc.com", 1, 2, 3, 4, 100), - DomainSearchTestUtils.mockDomainResult("xyz.com", 1, 2, 3, 4, 20) + DomainSearchTestUtils.mockDomainResult("google.com", 10, 100, 1, 5, 4, 110), + DomainSearchTestUtils.mockDomainResult("yahoo.com", 1, 5, 1, 7, 20, 100), + DomainSearchTestUtils.mockDomainResult("facebook.com", 2, 2, 1, 1, 3, 110), + DomainSearchTestUtils.mockDomainResult("abc.com", 1, 2, 1, 3, 4, 100), + DomainSearchTestUtils.mockDomainResult("xyz.com", 1, 2, 1, 3, 4, 20) ); SearchKey key = new SearchKey(null, new ArrayList<>(), @@ -101,8 +101,8 @@ public class DomainSearchCacheLoaderTest { public void load_GroupByNothingSortByNameAndDataSource() throws DiscoveryException, TskCoreException, SQLException { DomainSearchCacheLoader loader = mock(DomainSearchCacheLoader.class); List domains = Arrays.asList( - DomainSearchTestUtils.mockDomainResult("google.com", 10, 100, 5, 4, 110), - DomainSearchTestUtils.mockDomainResult("yahoo.com", 1, 5, 7, 20, 100) + DomainSearchTestUtils.mockDomainResult("google.com", 10, 100, 7, 5, 4, 110), + DomainSearchTestUtils.mockDomainResult("yahoo.com", 1, 5, 7, 7, 20, 100) ); SearchKey key = new SearchKey(null, new ArrayList<>(), @@ -130,8 +130,8 @@ public class DomainSearchCacheLoaderTest { public void load_GroupByDataSourceBySizeAndName() throws DiscoveryException, TskCoreException, SQLException { DomainSearchCacheLoader loader = mock(DomainSearchCacheLoader.class); List domains = Arrays.asList( - DomainSearchTestUtils.mockDomainResult("google.com", 10, 100, 5, 4, 110), - DomainSearchTestUtils.mockDomainResult("yahoo.com", 1, 5, 7, 20, 100) + DomainSearchTestUtils.mockDomainResult("google.com", 10, 100, 7, 5, 4, 110), + DomainSearchTestUtils.mockDomainResult("yahoo.com", 1, 5, 7, 7, 20, 100) ); SearchKey key = new SearchKey(null, new ArrayList<>(), diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTestUtils.java b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTestUtils.java index a0f19c17a4..8a884a2fac 100755 --- a/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTestUtils.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTestUtils.java @@ -32,14 +32,14 @@ public class DomainSearchTestUtils { } public static ResultDomain mockDomainResult(String domain, long start, long end, - long visits, long filesDownloaded, long dataSourceId) { + long totalVisits, long visits, long filesDownloaded, long dataSourceId) { Content dataSource = mockDataSource(dataSourceId); - return new ResultDomain(domain, start, end, + return new ResultDomain(domain, start, end, totalVisits, visits, filesDownloaded, dataSource); } public static ResultDomain mockDomainResult(String domain) { - return DomainSearchTestUtils.mockDomainResult(domain, 0, 0, 0, 0, 0); + return DomainSearchTestUtils.mockDomainResult(domain, 0, 0, 0, 0, 0, 0); } public static Content mockDataSource(long dataSourceId) { From e6d53a03c64c5febd710f0dcb25a26312d4e8d2e Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 15 Sep 2020 22:14:54 -0400 Subject: [PATCH 074/130] initial work --- .../datamodel/PastCasesSummary.java | 163 +++--------------- .../datasourcesummary/ui/AnalysisPanel.java | 20 ++- .../ui/BaseDataSourceSummaryPanel.java | 79 +++++++++ .../datasourcesummary/ui/ContainerPanel.java | 31 +--- .../datasourcesummary/ui/PastCasesPanel.java | 27 ++- .../ui/RecentFilesPanel.java | 24 ++- .../datasourcesummary/ui/TypesPanel.java | 34 +++- .../ui/UserActivityPanel.java | 37 ++-- 8 files changed, 210 insertions(+), 205 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java index 4b1154878c..f6bfe5346b 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java @@ -28,7 +28,6 @@ import java.util.Set; import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.sleuthkit.autopsy.centralrepository.ingestmodule.CentralRepoIngestModuleFactory; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; @@ -38,7 +37,6 @@ import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.DataSource; -import org.sleuthkit.datamodel.IngestJobInfo; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; @@ -66,46 +64,6 @@ import org.sleuthkit.datamodel.TskCoreException; */ public class PastCasesSummary implements DefaultArtifactUpdateGovernor { - /** - * Exception that is thrown in the event that a data source has not been - * ingested with a particular ingest module. - */ - public static class NotIngestedWithModuleException extends Exception { - private static final long serialVersionUID = 1L; - - private final String moduleDisplayName; - - /** - * Constructor. - * - * @param moduleName The module name. - * @param message The message for the exception. - */ - public NotIngestedWithModuleException(String moduleName, String message) { - super(message); - this.moduleDisplayName = moduleName; - } - - /** - * Constructor. - * - * @param moduleName The module name. - * @param message The message for the exception. - * @param thrwbl Inner exception if applicable. - */ - public NotIngestedWithModuleException(String moduleName, String message, Throwable thrwbl) { - super(message, thrwbl); - this.moduleDisplayName = moduleName; - } - - /** - * @return The module display name. - */ - public String getModuleDisplayName() { - return moduleDisplayName; - } - } - /** * Return type for results items in the past cases tab. */ @@ -139,12 +97,11 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor { return taggedNotable; } } - - private static final Set ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList( - ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(), - ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() - )); + private static final Set ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList( + ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(), + ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() + )); private static final String CENTRAL_REPO_INGEST_NAME = CentralRepoIngestModuleFactory.getModuleName().toUpperCase().trim(); private static final BlackboardAttribute.Type TYPE_COMMENT = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_COMMENT); @@ -179,8 +136,8 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor { * is designed with unit testing in mind since mocked dependencies can be * utilized. * - * @param provider The object providing the current SleuthkitCase. - * @param logger The logger to use. + * @param provider The object providing the current SleuthkitCase. + * @param logger The logger to use. */ public PastCasesSummary( SleuthkitCaseProvider provider, @@ -189,8 +146,7 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor { this.caseProvider = provider; this.logger = logger; } - - + @Override public Set getArtifactTypeIdsForRefresh() { return ARTIFACT_UPDATE_TYPE_IDS; @@ -265,7 +221,8 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor { * * @param cases A stream of cases. * - * @return The list of unique cases and their occurrences sorted from max to min. + * @return The list of unique cases and their occurrences sorted from max to + * min. */ private List> getCaseCounts(Stream cases) { Collection> groupedCases = cases @@ -285,11 +242,15 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor { } /** - * Given an artifact with a TYPE_ASSOCIATED_ARTIFACT attribute, retrieves the related artifact. - * @param skCase The sleuthkit case. + * Given an artifact with a TYPE_ASSOCIATED_ARTIFACT attribute, retrieves + * the related artifact. + * + * @param skCase The sleuthkit case. * @param artifact The artifact with the TYPE_ASSOCIATED_ARTIFACT attribute. + * * @return The artifact if found or null if not. - * @throws SleuthkitCaseProviderException + * + * @throws SleuthkitCaseProviderException */ private BlackboardArtifact getParentArtifact(BlackboardArtifact artifact) throws SleuthkitCaseProviderException { Long parentId = DataSourceInfoUtilities.getLongOrNull(artifact, TYPE_ASSOCIATED_ARTIFACT); @@ -307,35 +268,37 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor { return null; } } - + /** * Returns true if the artifact has an associated artifact of a device type. + * * @param artifact The artifact. + * * @return True if there is a device associated artifact. - * @throws SleuthkitCaseProviderException + * + * @throws SleuthkitCaseProviderException */ private boolean hasDeviceAssociatedArtifact(BlackboardArtifact artifact) throws SleuthkitCaseProviderException { BlackboardArtifact parent = getParentArtifact(artifact); if (parent == null) { return false; } - + return CR_DEVICE_TYPE_IDS.contains(parent.getArtifactTypeID()); } - - + /** * Returns the past cases data to be shown in the past cases tab. + * * @param dataSource The data source. + * * @return The retrieved data. + * * @throws SleuthkitCaseProviderException * @throws TskCoreException - * @throws NotIngestedWithModuleException */ public PastCasesResult getPastCasesData(DataSource dataSource) - throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, NotIngestedWithModuleException { - - throwOnNotCentralRepoIngested(dataSource); + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException { SleuthkitCase skCase = caseProvider.get(); @@ -363,76 +326,4 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor { getCaseCounts(Stream.concat(filesCases, nonDeviceArtifactCases.stream())) ); } - - - /** - * Returns true if the ingest job info contains an ingest module that - * matches the Central Repo Module ingest display name. - * - * @param info The info. - * - * @return True if there is a central repo ingest match. - */ - private boolean hasCentralRepoIngest(IngestJobInfo info) { - if (info == null || info.getIngestModuleInfo() == null) { - return false; - } - - return info.getIngestModuleInfo().stream() - .anyMatch((moduleInfo) -> { - return StringUtils.isNotBlank(moduleInfo.getDisplayName()) - && moduleInfo.getDisplayName().trim().equalsIgnoreCase(CENTRAL_REPO_INGEST_NAME); - }); - } - - /** - * Returns true if the central repository ingest module has been run on the - * datasource. - * - * @param dataSource The data source. - * - * @return True if there is an ingest job pertaining to the data source - * where an ingest module matches the central repo ingest module - * display name. - * - * @throws SleuthkitCaseProviderException - * @throws TskCoreException - */ - public boolean isCentralRepoIngested(DataSource dataSource) - throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException { - if (dataSource == null) { - return false; - } - - long dataSourceId = dataSource.getId(); - - return this.caseProvider.get().getIngestJobs().stream() - .anyMatch((ingestJob) -> { - return ingestJob != null - && ingestJob.getObjectId() == dataSourceId - && hasCentralRepoIngest(ingestJob); - }); - - } - - /** - * Throws an exception if the current data source has not been ingested with - * the Central Repository Ingest Module. - * - * @param dataSource The data source to check if it has been ingested with - * the Central Repository Ingest Module. - * - * @throws SleuthkitCaseProviderException - * @throws TskCoreException - * @throws NotIngestedWithModuleException - */ - private void throwOnNotCentralRepoIngested(DataSource dataSource) - throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, NotIngestedWithModuleException { - - if (!isCentralRepoIngested(dataSource)) { - String objectId = (dataSource == null) ? "" : String.valueOf(dataSource.getId()); - String message = String.format("Data source: %s has not been ingested with the Central Repository Ingest Module.", objectId); - throw new NotIngestedWithModuleException(CENTRAL_REPO_INGEST_NAME, message); - } - } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java index 3cb5a9b10d..a5406c6c0a 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java @@ -28,6 +28,8 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRendere import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel.ColumnModel; +import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupModuleFactory; +import org.sleuthkit.autopsy.modules.interestingitems.InterestingItemsIngestModuleFactory; import org.sleuthkit.datamodel.DataSource; /** @@ -36,12 +38,22 @@ import org.sleuthkit.datamodel.DataSource; */ @Messages({ "AnalysisPanel_keyColumn_title=Name", - "AnalysisPanel_countColumn_title=Count" + "AnalysisPanel_countColumn_title=Count", + "AnalysisPanel_keywordSearchModuleName=Keyword Search" }) public class AnalysisPanel extends BaseDataSourceSummaryPanel { private static final long serialVersionUID = 1L; + private static final String KEYWORD_SEARCH_MODULE_NAME = Bundle.AnalysisPanel_keywordSearchModuleName(); + private static final String KEYWORD_SEARCH_FACTORY = "org.sleuthkit.autopsy.keywordsearch.KeywordSearchModuleFactory"; + + private static final String INTERESTING_ITEM_MODULE_NAME = new InterestingItemsIngestModuleFactory().getModuleDisplayName(); + private static final String INTERESTING_ITEM_FACTORY = InterestingItemsIngestModuleFactory.class.getCanonicalName(); + + private static final String HASHSET_MODULE_NAME = HashLookupModuleFactory.getModuleName(); + private static final String HASHSET_FACTORY = HashLookupModuleFactory.class.getCanonicalName(); + /** * Default Column definitions for each table */ @@ -99,15 +111,15 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { // hashset hits loading components new DataFetchWorker.DataFetchComponents<>( (dataSource) -> analysisData.getHashsetCounts(dataSource), - (result) -> hashsetHitsTable.showDataFetchResult(result)), + (result) -> showResultWithModuleCheck(hashsetHitsTable, result, HASHSET_FACTORY, HASHSET_MODULE_NAME)), // keyword hits loading components new DataFetchWorker.DataFetchComponents<>( (dataSource) -> analysisData.getKeywordCounts(dataSource), - (result) -> keywordHitsTable.showDataFetchResult(result)), + (result) -> showResultWithModuleCheck(keywordHitsTable, result, KEYWORD_SEARCH_FACTORY, KEYWORD_SEARCH_MODULE_NAME)), // interesting item hits loading components new DataFetchWorker.DataFetchComponents<>( (dataSource) -> analysisData.getInterestingItemCounts(dataSource), - (result) -> interestingItemsTable.showDataFetchResult(result)) + (result) -> showResultWithModuleCheck(interestingItemsTable, result, INTERESTING_ITEM_FACTORY, INTERESTING_ITEM_MODULE_NAME)) ); initComponents(); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java index 30d9e949b7..6e5310cc8d 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java @@ -23,13 +23,18 @@ 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.stream.Collectors; import javax.swing.JPanel; import javax.swing.SwingWorker; +import org.openide.util.NbBundle.Messages; 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.DataFetchResult; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; import org.sleuthkit.autopsy.datasourcesummary.uiutils.EventUpdateHandler; @@ -53,6 +58,7 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { private static final Logger logger = Logger.getLogger(BaseDataSourceSummaryPanel.class.getName()); private final SwingWorkerSequentialExecutor executor = new SwingWorkerSequentialExecutor(); + private final IngestModuleCheckUtil ingestModuleCheck = new IngestModuleCheckUtil(); private final EventUpdateHandler updateHandler; private final List governors; @@ -280,4 +286,77 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { fetchInformation(dataSource); } } + + /** + * Get default message when there is a NotIngestedWithModuleException. + * + * @param exception The moduleName. + * + * @return Message specifying that the ingest module was not run. + */ + @Messages({ + "# {0} - module name", + "BaseDataSourceSummaryPanel_defaultNotIngestMessage=The {0} Ingest Module has not been run on this datasource." + }) + protected String getDefaultNoIngestMessage(String moduleName) { + return Bundle.BaseDataSourceSummaryPanel_defaultNotIngestMessage(moduleName); + } + + /** + * Utility method to return the IngestModuleCheckUtil. + * @return The IngestModuleCheckUtil. + */ + protected IngestModuleCheckUtil getIngestModuleCheckUtil() { + return this.ingestModuleCheck; + } + + /** + * Utility method that in the event of a) there are no results and b) a + * relevant ingest module has not been run on this datasource, then a + * 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 factoryClass The fully qualified class name of the relevant + * 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(); + showResultWithModuleCheck(component, result, hasResults, factoryClass, moduleName); + } + + /** + * Utility method that in the event of a) there are no results and b) a + * relevant ingest module has not been run on this datasource, then a + * 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 factoryClass The fully qualified class name of the relevant + * 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) { + + if (result != null && result.getResultType() == ResultType.SUCCESS && !hasResults.test(result.getData())) { + try { + if (ingestModuleCheck.isModuleIngested(getDataSource(), factoryClass)) { + component.showMessage(getDefaultNoIngestMessage(moduleName)); + return; + } + } catch (TskCoreException | SleuthkitCaseProviderException ex) { + logger.log(Level.WARNING, "There was an error while checking for ingest modules for datasource.", ex); + } + } + + component.showDataFetchResult(result); + } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java index d350ee0fa7..7a8d482e4c 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java @@ -26,9 +26,11 @@ import java.util.Set; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.table.DefaultTableModel; +import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor; @@ -49,23 +51,16 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { private final DataSource dataSource; private final Long unallocatedFilesSize; - private final String operatingSystem; - private final String dataSourceType; /** * Main constructor. * * @param dataSource The original datasource. * @param unallocatedFilesSize The unallocated file size. - * @param operatingSystem The string representing the operating - * system. - * @param dataSourceType The datasource type as a string. */ - ContainerPanelData(DataSource dataSource, Long unallocatedFilesSize, String operatingSystem, String dataSourceType) { + ContainerPanelData(DataSource dataSource, Long unallocatedFilesSize) { this.dataSource = dataSource; this.unallocatedFilesSize = unallocatedFilesSize; - this.operatingSystem = operatingSystem; - this.dataSourceType = dataSourceType; } /** @@ -81,21 +76,6 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { Long getUnallocatedFilesSize() { return unallocatedFilesSize; } - - /** - * @return The string representing the operating system. - */ - String getOperatingSystem() { - return operatingSystem; - } - - /** - * @return The datasource type as a string. - */ - String getDataSourceType() { - return dataSourceType; - } - } // set of case events for which to call update (if the name changes, that will impact data shown) @@ -144,9 +124,7 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { (dataSource) -> { return new ContainerPanelData( dataSource, - containerSummary.getSizeOfUnallocatedFiles(dataSource), - containerSummary.getOperatingSystems(dataSource), - containerSummary.getDataSourceType(dataSource) + containerSummary.getSizeOfUnallocatedFiles(dataSource) ); }, (result) -> { @@ -168,6 +146,7 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { setDataSource(null); } + @Override protected void onNewDataSource(DataSource dataSource) { fetchInformation(dataSource); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java index a530757276..422517e96c 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java @@ -21,12 +21,10 @@ package org.sleuthkit.autopsy.datasourcesummary.ui; import java.util.Arrays; import java.util.List; import java.util.function.Function; -import java.util.stream.Collectors; import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.centralrepository.ingestmodule.CentralRepoIngestModuleFactory; import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary.NotIngestedWithModuleException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary.PastCasesResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.DefaultCellModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; @@ -45,11 +43,12 @@ import org.sleuthkit.datamodel.DataSource; "PastCasesPanel_caseColumn_title=Case", "PastCasesPanel_countColumn_title=Count", "PastCasesPanel_onNoCrIngest_message=No results will be shown because the Central Repository module was not run." - }) public class PastCasesPanel extends BaseDataSourceSummaryPanel { private static final long serialVersionUID = 1L; + private static final String CR_FACTORY = CentralRepoIngestModuleFactory.class.getName(); + private static final String CR_NAME = CentralRepoIngestModuleFactory.getModuleName(); private static final ColumnModel> CASE_COL = new ColumnModel<>( Bundle.PastCasesPanel_caseColumn_title(), @@ -95,21 +94,14 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { } /** - * handles displaying the result for the table. If a - * NotCentralRepoIngestedException is thrown, then an appropriate message is - * shown. Otherwise, this method uses the tables default showDataFetchResult - * method. + * Handles displaying the result for each table by breaking apart subdata + * items into seperate results for each table. * * @param result The result. */ private void handleResult(DataFetchResult result) { - if (result.getResultType() == ResultType.ERROR && result.getException() instanceof NotIngestedWithModuleException) { - notableFileTable.showMessage(Bundle.PastCasesPanel_onNoCrIngest_message()); - sameIdTable.showMessage(Bundle.PastCasesPanel_onNoCrIngest_message()); - } else { - notableFileTable.showDataFetchResult(getSubResult(result, (res) -> (res == null) ? null : res.getTaggedNotable())); - sameIdTable.showDataFetchResult(getSubResult(result, (res) -> (res == null) ? null : res.getSameIdsResults())); - } + showResultWithModuleCheck(notableFileTable, getSubResult(result, (res) -> res.getTaggedNotable()), CR_FACTORY, CR_NAME); + showResultWithModuleCheck(sameIdTable, getSubResult(result, (res) -> res.getSameIdsResults()), CR_FACTORY, CR_NAME); } /** @@ -124,9 +116,10 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { * @return The new result with the error of the original or the processed * data. */ - private DataFetchResult getSubResult(DataFetchResult inputResult, Function getSubResult) { + private DataFetchResult getSubResult(DataFetchResult inputResult, Function getSubResult) { if (inputResult.getResultType() == ResultType.SUCCESS) { - return DataFetchResult.getSuccessResult(getSubResult.apply(inputResult.getData())); + O innerData = (inputResult == null) ? null : getSubResult.apply(inputResult.getData()); + return DataFetchResult.getSuccessResult(innerData); } else { return DataFetchResult.getErrorResult(inputResult.getException()); } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java index 11e083c9ae..6bf27f595a 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.IngestModuleCheckUtil; import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentAttachmentDetails; import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentDownloadDetails; @@ -39,6 +40,8 @@ import org.sleuthkit.datamodel.DataSource; public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { private static final long serialVersionUID = 1L; + private static final String EMAIL_PARSER_FACTORY = "org.sleuthkit.autopsy.thunderbirdparser.EmailParserModuleFactory"; + private static final String EMAIL_PARSER_MODULE_NAME = Bundle.RecentFilePanel_emailParserModuleName(); private final List> tablePanelList = new ArrayList<>(); private final List> dataFetchComponents = new ArrayList<>(); @@ -49,7 +52,8 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { "RecentFilesPanel_col_head_date=Date", "RecentFilePanel_col_header_domain=Domain", "RecentFilePanel_col_header_path=Path", - "RecentFilePanel_col_header_sender=Sender" + "RecentFilePanel_col_header_sender=Sender", + "RecentFilePanel_emailParserModuleName=Email Parser" }) /** @@ -118,8 +122,11 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { DataFetchWorker.DataFetchComponents> worker = new DataFetchWorker.DataFetchComponents<>( (dataSource) -> dataHandler.getRecentlyOpenedDocuments(dataSource, 10), - (result) -> pane.showDataFetchResult(result, JTablePanel.getDefaultErrorMessage(), - Bundle.RecentFilePanel_no_open_documents())); + (result) -> { + showResultWithModuleCheck(pane, result, + IngestModuleCheckUtil.RECENT_ACTIVITY_FACTORY, + IngestModuleCheckUtil.RECENT_ACTIVITY_MODULE_NAME); + }); dataFetchComponents.add(worker); } @@ -154,8 +161,11 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { DataFetchWorker.DataFetchComponents> worker = new DataFetchWorker.DataFetchComponents<>( (dataSource) -> dataHandler.getRecentDownloads(dataSource, 10), - (result) -> pane.showDataFetchResult(result, JTablePanel.getDefaultErrorMessage(), - Bundle.RecentFilePanel_no_open_documents())); + (result) -> { + showResultWithModuleCheck(pane, result, + IngestModuleCheckUtil.RECENT_ACTIVITY_FACTORY, + IngestModuleCheckUtil.RECENT_ACTIVITY_MODULE_NAME); + }); dataFetchComponents.add(worker); } @@ -190,8 +200,8 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { DataFetchWorker.DataFetchComponents> worker = new DataFetchWorker.DataFetchComponents<>( (dataSource) -> dataHandler.getRecentAttachments(dataSource, 10), - (result) -> pane.showDataFetchResult(result, JTablePanel.getDefaultErrorMessage(), - Bundle.RecentFilePanel_no_open_documents())); + (result) -> showResultWithModuleCheck(pane, result, EMAIL_PARSER_FACTORY, EMAIL_PARSER_MODULE_NAME) + ); dataFetchComponents.add(worker); } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java index e082543dee..a355131fcd 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java @@ -23,6 +23,7 @@ import java.sql.SQLException; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -34,6 +35,7 @@ import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.IngestModuleCheckUtil; import org.sleuthkit.autopsy.datasourcesummary.datamodel.MimeTypeSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.uiutils.AbstractLoadableComponent; @@ -42,6 +44,7 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetch import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent; import org.sleuthkit.autopsy.datasourcesummary.uiutils.PieChartPanel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.PieChartPanel.PieChartItem; +import org.sleuthkit.autopsy.modules.filetypeid.FileTypeIdModuleFactory; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; @@ -114,7 +117,9 @@ class TypesPanel extends BaseDataSourceSummaryPanel { private static final long serialVersionUID = 1L; private static final DecimalFormat INTEGER_SIZE_FORMAT = new DecimalFormat("#"); private static final DecimalFormat COMMA_FORMATTER = new DecimalFormat("#,###"); - + private static final String FILE_TYPE_FACTORY = FileTypeIdModuleFactory.class.getCanonicalName(); + private static final String FILE_TYPE_MODULE_NAME = FileTypeIdModuleFactory.getModuleName(); + // All file type categories. private static final List>> FILE_MIME_TYPE_CATEGORIES = Arrays.asList( Pair.of(Bundle.TypesPanel_fileMimeTypesChart_images_title(), FileTypeCategory.IMAGE.getMediaTypes()), @@ -176,11 +181,25 @@ class TypesPanel extends BaseDataSourceSummaryPanel { // usage label worker new DataFetchWorker.DataFetchComponents<>( containerData::getDataSourceType, - usageLabel::showDataFetchResult), + (result) -> { + showResultWithModuleCheck( + usageLabel, + result, + StringUtils::isBlank, + IngestModuleCheckUtil.RECENT_ACTIVITY_FACTORY, + IngestModuleCheckUtil.RECENT_ACTIVITY_MODULE_NAME); + }), // os label worker new DataFetchWorker.DataFetchComponents<>( containerData::getOperatingSystems, - osLabel::showDataFetchResult), + (result) -> { + showResultWithModuleCheck( + osLabel, + result, + StringUtils::isBlank, + IngestModuleCheckUtil.RECENT_ACTIVITY_FACTORY, + IngestModuleCheckUtil.RECENT_ACTIVITY_MODULE_NAME); + }), // size label worker new DataFetchWorker.DataFetchComponents<>( (dataSource) -> { @@ -191,7 +210,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel { // file types worker new DataFetchWorker.DataFetchComponents<>( (dataSource) -> getMimeTypeCategoriesModel(mimeTypeData, dataSource), - fileMimeTypesChart::showDataFetchResult), + (result) -> showResultWithModuleCheck(fileMimeTypesChart, result, FILE_TYPE_FACTORY, FILE_TYPE_MODULE_NAME)), // allocated files worker new DataFetchWorker.DataFetchComponents<>( (dataSource) -> getStringOrZero(typeData.getCountOfAllocatedFiles(dataSource)), @@ -234,7 +253,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel { throws SQLException, SleuthkitCaseProviderException, TskCoreException { if (dataSource == null) { - return null; + return Collections.emptyList(); } // for each category of file types, get the counts of files @@ -259,6 +278,11 @@ class TypesPanel extends BaseDataSourceSummaryPanel { fileCategoryItems.add(Pair.of(Bundle.TypesPanel_fileMimeTypesChart_other_title(), allRegularFiles - (categoryTotalCount + noMimeTypeCount))); + // check at this point to see if these are all 0, if so we don't have results; return empty list + if (!fileCategoryItems.stream().anyMatch((pair) -> pair.getValue() != null && pair.getValue() > 0)) { + return Collections.emptyList(); + } + // create entry for not analyzed mime types category fileCategoryItems.add(Pair.of(Bundle.TypesPanel_fileMimeTypesChart_notAnalyzed_title(), noMimeTypeCount)); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java index 6437812296..22a3d5847c 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java @@ -70,6 +70,8 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { private static final int TOP_SEARCHES_COUNT = 10; private static final int TOP_ACCOUNTS_COUNT = 5; private static final int TOP_DEVICES_COUNT = 10; + private static final String ANDROID_FACTORY = "org.python.proxies.module$AndroidModuleFactory"; + private static final String ANDROID_MODULE_NAME = "Android Analyzer"; /** * Gets a string formatted date or returns empty string if the date is null. @@ -250,28 +252,43 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { // top programs query new DataFetchComponents>( (dataSource) -> topProgramsData.getTopPrograms(dataSource, TOP_PROGS_COUNT), - (result) -> topProgramsTable.showDataFetchResult(result, JTablePanel.getDefaultErrorMessage(), - Bundle.UserActivityPanel_noDataExists())), + (result) -> { + showResultWithModuleCheck(topProgramsTable, result, + IngestModuleCheckUtil.RECENT_ACTIVITY_FACTORY, + IngestModuleCheckUtil.RECENT_ACTIVITY_MODULE_NAME); + }), // top domains query new DataFetchComponents>( (dataSource) -> userActivityData.getRecentDomains(dataSource, TOP_DOMAINS_COUNT), - (result) -> recentDomainsTable.showDataFetchResult(result, JTablePanel.getDefaultErrorMessage(), - Bundle.UserActivityPanel_noDataExists())), + (result) -> { + showResultWithModuleCheck(recentDomainsTable, result, + IngestModuleCheckUtil.RECENT_ACTIVITY_FACTORY, + IngestModuleCheckUtil.RECENT_ACTIVITY_MODULE_NAME); + }), // top web searches query new DataFetchComponents>( (dataSource) -> userActivityData.getMostRecentWebSearches(dataSource, TOP_SEARCHES_COUNT), - (result) -> topWebSearchesTable.showDataFetchResult(result, JTablePanel.getDefaultErrorMessage(), - Bundle.UserActivityPanel_noDataExists())), + (result) -> { + showResultWithModuleCheck(topWebSearchesTable, result, + IngestModuleCheckUtil.RECENT_ACTIVITY_FACTORY, + IngestModuleCheckUtil.RECENT_ACTIVITY_MODULE_NAME); + }), // top devices query new DataFetchComponents>( (dataSource) -> userActivityData.getRecentDevices(dataSource, TOP_DEVICES_COUNT), - (result) -> topDevicesAttachedTable.showDataFetchResult(result, JTablePanel.getDefaultErrorMessage(), - Bundle.UserActivityPanel_noDataExists())), + (result) -> { + showResultWithModuleCheck(topDevicesAttachedTable, result, + IngestModuleCheckUtil.RECENT_ACTIVITY_FACTORY, + IngestModuleCheckUtil.RECENT_ACTIVITY_MODULE_NAME); + }), // top accounts query new DataFetchComponents>( (dataSource) -> userActivityData.getRecentAccounts(dataSource, TOP_ACCOUNTS_COUNT), - (result) -> topAccountsTable.showDataFetchResult(result, JTablePanel.getDefaultErrorMessage(), - Bundle.UserActivityPanel_noDataExists())) + (result) -> { + showResultWithModuleCheck(topAccountsTable, result, + ANDROID_FACTORY, + ANDROID_MODULE_NAME); + }) ); initComponents(); From c2333b7b593d9f6be9d1c42c7ea97355df46295f Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 15 Sep 2020 22:15:31 -0400 Subject: [PATCH 075/130] initial work --- .../datamodel/IngestModuleCheckUtil.java | 146 ++++++++++++++++ .../uiutils/IngestRunningLabel.java | 162 ++++++++++++++++++ 2 files changed, 308 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/IngestModuleCheckUtil.java create mode 100644 Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/IngestModuleCheckUtil.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/IngestModuleCheckUtil.java new file mode 100644 index 0000000000..86c731e78b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/IngestModuleCheckUtil.java @@ -0,0 +1,146 @@ +/* + * 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 java.util.Map; +import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.IngestJobInfo; +import org.sleuthkit.datamodel.IngestModuleInfo; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Utilities for checking if an ingest module has been run on a datasource. + */ +@Messages({ + "IngestModuleCheckUtil_recentActivityModuleName=Recent Activity", + +}) +public class IngestModuleCheckUtil { + public static final String RECENT_ACTIVITY_FACTORY = "org.sleuthkit.autopsy.recentactivity.RecentActivityExtracterModuleFactory"; + public static final String RECENT_ACTIVITY_MODULE_NAME = Bundle.IngestModuleCheckUtil_recentActivityModuleName(); + + // IngestModuleInfo separator for unique_name + private static final String UNIQUE_NAME_SEPARATOR = "-"; + + private final SleuthkitCaseProvider caseProvider; + + /** + * Main constructor. + */ + public IngestModuleCheckUtil() { + this(SleuthkitCaseProvider.DEFAULT); + + } + + /** + * Main constructor with external dependencies specified. This constructor + * is designed with unit testing in mind since mocked dependencies can be + * utilized. + * + * @param provider The object providing the current SleuthkitCase. + * @param logger The logger to use. + */ + public IngestModuleCheckUtil(SleuthkitCaseProvider provider) { + + this.caseProvider = provider; + } + + + /** + * Gets the fully qualified factory from the IngestModuleInfo. + * @param info The IngestJobInfo. + * @return The fully qualified factory. + */ + private static String getFullyQualifiedFactory(IngestModuleInfo info) { + if (info == null) { + return null; + } + + String qualifiedName = info.getUniqueName(); + if (StringUtils.isBlank(qualifiedName)) { + return null; + } + + return qualifiedName.split(UNIQUE_NAME_SEPARATOR)[0]; + } + + + /** + * Whether or not the ingest job info contains the ingest modulename. + * @param info The IngestJobInfo. + * @param fullyQualifiedFactory The fully qualified classname of the relevant factory. + * @return True if the ingest module name is contained in the data. + */ + private static boolean hasIngestModule(IngestJobInfo info, String fullyQualifiedFactory) { + if (info == null || info.getIngestModuleInfo() == null || StringUtils.isBlank(fullyQualifiedFactory)) { + return false; + } + + return info.getIngestModuleInfo().stream() + .anyMatch((moduleInfo) -> { + String thisQualifiedFactory = getFullyQualifiedFactory(moduleInfo); + return fullyQualifiedFactory.equalsIgnoreCase(thisQualifiedFactory); + }); + } + + /** + * Whether or not a data source has been ingested with a particular ingest module. + * @param dataSource The datasource. + * @param fullyQualifiedFactory The fully qualified classname of the relevant factory. + * @return Whether or not a data source has been ingested with a particular ingest module. + * @throws TskCoreException + * @throws SleuthkitCaseProviderException + */ + public boolean isModuleIngested(DataSource dataSource, String fullyQualifiedFactory) + throws TskCoreException, SleuthkitCaseProviderException { + if (dataSource == null) { + return false; + } + + long dataSourceId = dataSource.getId(); + + return caseProvider.get().getIngestJobs().stream() + .anyMatch((ingestJob) -> { + return ingestJob != null + && ingestJob.getObjectId() == dataSourceId + && hasIngestModule(ingestJob, fullyQualifiedFactory); + }); + + } + + /** + * Get a mapping of fully qualified factory name to display name. + * @param skCase The SleuthkitCase. + * @return The mapping of fully qualified factory name to display name. + * @throws TskCoreException + */ + public static Map getFactoryDisplayNames(SleuthkitCase skCase) throws TskCoreException { + return skCase.getIngestJobs().stream() + .flatMap(ingestJob -> ingestJob.getIngestModuleInfo().stream()) + .collect(Collectors.toMap( + (moduleInfo) -> getFullyQualifiedFactory(moduleInfo), + (moduleInfo) -> moduleInfo.getDisplayName(), + (a,b) -> a)); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java new file mode 100644 index 0000000000..044c9c0346 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java @@ -0,0 +1,162 @@ +/* + * 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 java.awt.BorderLayout; +import java.beans.PropertyChangeListener; +import java.net.URL; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.Set; +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.JPanel; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.ingest.IngestManager; + +/** + * JLabel that shows ingest is running. + */ +@Messages({ + "IngestRunningLabel_defaultMessage=Ingest is currently running." +}) +public class IngestRunningLabel extends JPanel { + + public static final String DEFAULT_MESSAGE = Bundle.IngestRunningLabel_defaultMessage(); + private static final URL DEFAULT_ICON = IngestRunningLabel.class.getResource("/org/sleuthkit/autopsy/modules/filetypeid/warning16.png"); + + private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of( + IngestManager.IngestJobEvent.STARTED, + IngestManager.IngestJobEvent.CANCELLED, + IngestManager.IngestJobEvent.COMPLETED + ); + + private static Set activeLabels = new HashSet<>(); + private static PropertyChangeListener classListener = null; + private static Object lockObject = new Object(); + + /** + * Setup ingest event listener for the current label. + * + * @param label The label. + */ + private static void setupListener(IngestRunningLabel label) { + synchronized (lockObject) { + + // if listener is not initialized, initialize it. + if (classListener == null) { + classListener = (evt) -> { + + if (evt.getPropertyName().equals(IngestManager.IngestJobEvent.STARTED.toString())) { + // ingest started + notifyListeners(true); + + } else if (evt.getPropertyName().equals(IngestManager.IngestJobEvent.CANCELLED.toString()) + || evt.getPropertyName().equals(IngestManager.IngestJobEvent.COMPLETED.toString())) { + // ingest cancelled or finished + notifyListeners(false); + + } + }; + IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, classListener); + } + + // add the item to the set + activeLabels.add(label); + } + } + + /** + * Notifies all listening instances of an update in ingest state. + * + * @param ingestIsRunning Whether or not ingest is running currently. + */ + private static void notifyListeners(boolean ingestIsRunning) { + synchronized (lockObject) { + for (IngestRunningLabel label : activeLabels) { + label.refreshState(ingestIsRunning); + } + } + } + + /** + * Removes a label from listening events. + * + * @param label The label to remove from listening events. + */ + private static void removeListener(IngestRunningLabel label) { + synchronized (lockObject) { + activeLabels.remove(label); + if (activeLabels.isEmpty() && classListener != null) { + IngestManager.getInstance().removeIngestJobEventListener(classListener); + classListener = null; + } + } + } + + /** + * Main constructor with default message and showing icon. + */ + public IngestRunningLabel() { + this(DEFAULT_MESSAGE, true); + } + + /** + * Constructor. + * + * @param message The message to be shown. + * @param showWarningIcon Whether or not to show warning icon. + */ + public IngestRunningLabel(String message, boolean showWarningIcon) { + JLabel jlabel = new JLabel(); + jlabel.setText(message); + if (showWarningIcon) { + jlabel.setIcon(new ImageIcon(DEFAULT_ICON)); + } + + setLayout(new BorderLayout()); + add(jlabel, BorderLayout.CENTER); + + setupListener(this); + refreshState(); + } + + /** + * Refresh state of this label based on ingest status. + */ + protected final void refreshState() { + refreshState(IngestManager.getInstance().isIngestRunning()); + } + + /** + * Refresh state of this label based on ingest status. + * + * @param ingestIsRunning True if ingest is running. + */ + protected final void refreshState(boolean ingestIsRunning) { + setVisible(ingestIsRunning); + } + + /** + * Unregister this instance from listening for ingest status changes. + */ + public void unregister() { + removeListener(this); + } +} From 0059e24778757288edba4941261b32eddbae9574 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 15 Sep 2020 22:41:59 -0400 Subject: [PATCH 076/130] added ingest label --- .../datasourcesummary/ui/AnalysisPanel.form | 21 ++++++++++ .../datasourcesummary/ui/AnalysisPanel.java | 19 ++++++++++ .../datasourcesummary/ui/PastCasesPanel.form | 21 ++++++++++ .../datasourcesummary/ui/PastCasesPanel.java | 16 ++++++++ .../ui/RecentFilesPanel.form | 38 ++++++++++++++++--- .../ui/RecentFilesPanel.java | 33 +++++++++++++--- .../datasourcesummary/ui/TypesPanel.form | 21 ++++++++++ .../datasourcesummary/ui/TypesPanel.java | 20 +++++++++- .../ui/UserActivityPanel.form | 21 ++++++++++ .../ui/UserActivityPanel.java | 16 ++++++++ 10 files changed, 212 insertions(+), 14 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form index 4016b539a7..07ed2771e1 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form @@ -57,6 +57,27 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java index a5406c6c0a..0cfca04286 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java @@ -26,6 +26,7 @@ import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.datasourcesummary.datamodel.AnalysisSummary; import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.DefaultCellModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; +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.modules.hashdatabase.HashLookupModuleFactory; @@ -89,6 +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 @@ -125,6 +129,14 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { initComponents(); } + + @Override + public void close() { + ingestRunningLabel.unregister(); + super.close(); + } + + @Override protected void fetchInformation(DataSource dataSource) { fetchInformation(dataFetchComponents, dataSource); @@ -146,6 +158,7 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { javax.swing.JScrollPane mainScrollPane = new javax.swing.JScrollPane(); javax.swing.JPanel mainContentPanel = new javax.swing.JPanel(); + javax.swing.JPanel ingestRunningPanel = ingestRunningLabel; 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; @@ -164,6 +177,12 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { mainContentPanel.setMinimumSize(new java.awt.Dimension(200, 452)); mainContentPanel.setLayout(new javax.swing.BoxLayout(mainContentPanel, javax.swing.BoxLayout.PAGE_AXIS)); + ingestRunningPanel.setAlignmentX(0.0F); + ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 20)); + ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 20)); + ingestRunningPanel.setPreferredSize(new java.awt.Dimension(32767, 20)); + mainContentPanel.add(ingestRunningPanel); + org.openide.awt.Mnemonics.setLocalizedText(hashsetHitsLabel, org.openide.util.NbBundle.getMessage(AnalysisPanel.class, "AnalysisPanel.hashsetHitsLabel.text")); // NOI18N mainContentPanel.add(hashsetHitsLabel); mainContentPanel.add(filler1); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form index 13ddb081bd..fd8a67cd36 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form @@ -51,6 +51,27 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java index 422517e96c..5a520e471f 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java @@ -31,6 +31,7 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; 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.datamodel.DataSource; @@ -75,6 +76,8 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { private final List> dataFetchComponents; + private final IngestRunningLabel ingestRunningLabel = new IngestRunningLabel(); + public PastCasesPanel() { this(new PastCasesSummary()); } @@ -135,6 +138,12 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { onNewDataSource(dataFetchComponents, tables, dataSource); } + @Override + public void close() { + ingestRunningLabel.unregister(); + super.close(); + } + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -146,6 +155,7 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { javax.swing.JScrollPane mainScrollPane = new javax.swing.JScrollPane(); javax.swing.JPanel mainContentPanel = new javax.swing.JPanel(); + javax.swing.JPanel ingestRunningPanel = ingestRunningLabel; javax.swing.JLabel notableFileLabel = 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 notableFilePanel = notableFileTable; @@ -158,6 +168,12 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { mainContentPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10)); mainContentPanel.setLayout(new javax.swing.BoxLayout(mainContentPanel, javax.swing.BoxLayout.PAGE_AXIS)); + ingestRunningPanel.setAlignmentX(0.0F); + ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 20)); + ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 20)); + ingestRunningPanel.setPreferredSize(new java.awt.Dimension(32767, 20)); + mainContentPanel.add(ingestRunningPanel); + org.openide.awt.Mnemonics.setLocalizedText(notableFileLabel, org.openide.util.NbBundle.getMessage(PastCasesPanel.class, "PastCasesPanel.notableFileLabel.text")); // NOI18N mainContentPanel.add(notableFileLabel); notableFileLabel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(PastCasesPanel.class, "PastCasesPanel.notableFileLabel.text")); // NOI18N diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.form index 4d1cdccecd..b67ec8a6a3 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.form @@ -45,13 +45,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -63,7 +89,7 @@ - + @@ -75,7 +101,7 @@ - + @@ -93,7 +119,7 @@ - + @@ -109,7 +135,7 @@ - + @@ -125,7 +151,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java index 6bf27f595a..b599e60bd6 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java @@ -29,6 +29,7 @@ import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.Rece import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentFileDetails; import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.DefaultCellModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; +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.ListTableModel; @@ -46,6 +47,8 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { private final List> tablePanelList = new ArrayList<>(); private final List> dataFetchComponents = new ArrayList<>(); + private final IngestRunningLabel ingestRunningLabel = new IngestRunningLabel(); + private final RecentFilesSummary dataHandler; @Messages({ @@ -84,6 +87,12 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { onNewDataSource(dataFetchComponents, tablePanelList, dataSource); } + @Override + public void close() { + ingestRunningLabel.unregister(); + super.close(); + } + /** * Setup the data model and columns for the panel tables. */ @@ -218,6 +227,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { javax.swing.JScrollPane scrollPane = new javax.swing.JScrollPane(); javax.swing.JPanel tablePanel = new javax.swing.JPanel(); + javax.swing.JPanel ingestRunningPanel = ingestRunningLabel; openedDocPane = new JTablePanel(); downloadsPane = new JTablePanel(); attachmentsPane = new JTablePanel(); @@ -230,9 +240,20 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { tablePanel.setMinimumSize(new java.awt.Dimension(400, 400)); tablePanel.setPreferredSize(new java.awt.Dimension(600, 400)); tablePanel.setLayout(new java.awt.GridBagLayout()); + + ingestRunningPanel.setAlignmentX(0.0F); + ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 20)); + ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 20)); + ingestRunningPanel.setPreferredSize(new java.awt.Dimension(32767, 20)); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 1; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + tablePanel.add(ingestRunningPanel, gridBagConstraints); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; gridBagConstraints.weightx = 1.0; @@ -241,7 +262,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { tablePanel.add(openedDocPane, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 3; + gridBagConstraints.gridy = 4; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; gridBagConstraints.weightx = 1.0; @@ -250,7 +271,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { tablePanel.add(downloadsPane, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 5; + gridBagConstraints.gridy = 6; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; gridBagConstraints.weightx = 1.0; @@ -261,7 +282,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { org.openide.awt.Mnemonics.setLocalizedText(openDocsLabel, org.openide.util.NbBundle.getMessage(RecentFilesPanel.class, "RecentFilesPanel.openDocsLabel.text")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 0; + gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; gridBagConstraints.insets = new java.awt.Insets(10, 5, 0, 5); @@ -270,7 +291,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 = 2; + gridBagConstraints.gridy = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.insets = new java.awt.Insets(15, 5, 0, 5); tablePanel.add(downloadLabel, gridBagConstraints); @@ -278,7 +299,7 @@ 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 = 4; + gridBagConstraints.gridy = 5; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; gridBagConstraints.insets = new java.awt.Insets(15, 5, 0, 5); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.form index 2efe151eb5..36a8ee3493 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.form @@ -52,6 +52,27 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java index a355131fcd..17a07dc399 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java @@ -41,6 +41,7 @@ import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.S import org.sleuthkit.autopsy.datasourcesummary.uiutils.AbstractLoadableComponent; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent; import org.sleuthkit.autopsy.datasourcesummary.uiutils.PieChartPanel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.PieChartPanel.PieChartItem; @@ -119,7 +120,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel { private static final DecimalFormat COMMA_FORMATTER = new DecimalFormat("#,###"); private static final String FILE_TYPE_FACTORY = FileTypeIdModuleFactory.class.getCanonicalName(); private static final String FILE_TYPE_MODULE_NAME = FileTypeIdModuleFactory.getModuleName(); - + // All file type categories. private static final List>> FILE_MIME_TYPE_CATEGORIES = Arrays.asList( Pair.of(Bundle.TypesPanel_fileMimeTypesChart_images_title(), FileTypeCategory.IMAGE.getMediaTypes()), @@ -153,6 +154,8 @@ class TypesPanel extends BaseDataSourceSummaryPanel { directoriesLabel ); + private final IngestRunningLabel ingestRunningLabel = new IngestRunningLabel(); + // all of the means for obtaining data for the gui components. private final List> dataFetchComponents; @@ -163,6 +166,12 @@ class TypesPanel extends BaseDataSourceSummaryPanel { this(new MimeTypeSummary(), new TypesSummary(), new ContainerSummary()); } + @Override + public void close() { + ingestRunningLabel.unregister(); + super.close(); + } + /** * Creates a new TypesPanel. * @@ -282,7 +291,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel { if (!fileCategoryItems.stream().anyMatch((pair) -> pair.getValue() != null && pair.getValue() > 0)) { return Collections.emptyList(); } - + // create entry for not analyzed mime types category fileCategoryItems.add(Pair.of(Bundle.TypesPanel_fileMimeTypesChart_notAnalyzed_title(), noMimeTypeCount)); @@ -328,6 +337,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel { javax.swing.JScrollPane scrollParent = new javax.swing.JScrollPane(); javax.swing.JPanel contentParent = new javax.swing.JPanel(); + javax.swing.JPanel ingestRunningPanel = ingestRunningLabel; javax.swing.JPanel usagePanel = usageLabel; javax.swing.JPanel osPanel = osLabel; javax.swing.JPanel sizePanel = sizeLabel; @@ -346,6 +356,12 @@ class TypesPanel extends BaseDataSourceSummaryPanel { contentParent.setMinimumSize(new java.awt.Dimension(400, 490)); contentParent.setLayout(new javax.swing.BoxLayout(contentParent, javax.swing.BoxLayout.PAGE_AXIS)); + ingestRunningPanel.setAlignmentX(0.0F); + ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 20)); + ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 20)); + ingestRunningPanel.setPreferredSize(new java.awt.Dimension(32767, 20)); + contentParent.add(ingestRunningPanel); + usagePanel.setAlignmentX(0.0F); usagePanel.setMaximumSize(new java.awt.Dimension(32767, 20)); usagePanel.setMinimumSize(new java.awt.Dimension(10, 20)); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.form index a7a3d6e0b2..f4daefb048 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.form @@ -60,6 +60,27 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java index 22a3d5847c..1e83a71cb8 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java @@ -36,6 +36,7 @@ import org.sleuthkit.autopsy.datasourcesummary.datamodel.TopProgramsSummary.TopP import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDomainsResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.DefaultCellModel; 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.datamodel.DataSource; @@ -222,6 +223,8 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { topAccountsTable ); + private final IngestRunningLabel ingestRunningLabel = new IngestRunningLabel(); + private final List> dataFetchComponents; private final TopProgramsSummary topProgramsData; @@ -316,6 +319,12 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { onNewDataSource(dataFetchComponents, tables, dataSource); } + @Override + public void close() { + ingestRunningLabel.unregister(); + super.close(); + } + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -327,6 +336,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { javax.swing.JScrollPane contentScrollPane = new javax.swing.JScrollPane(); javax.swing.JPanel contentPanel = new javax.swing.JPanel(); + javax.swing.JPanel ingestRunningPanel = ingestRunningLabel; 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; @@ -357,6 +367,12 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { contentPanel.setMinimumSize(new java.awt.Dimension(10, 450)); contentPanel.setLayout(new javax.swing.BoxLayout(contentPanel, javax.swing.BoxLayout.PAGE_AXIS)); + ingestRunningPanel.setAlignmentX(0.0F); + ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 20)); + ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 20)); + ingestRunningPanel.setPreferredSize(new java.awt.Dimension(32767, 20)); + contentPanel.add(ingestRunningPanel); + programsRunLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); org.openide.awt.Mnemonics.setLocalizedText(programsRunLabel, org.openide.util.NbBundle.getMessage(UserActivityPanel.class, "UserActivityPanel.programsRunLabel.text")); // NOI18N programsRunLabel.setAlignmentX(Component.LEFT_ALIGNMENT); From 45ca1cc20221d08be09e8dd6f48512acf96758ce Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 16 Sep 2020 08:51:57 -0400 Subject: [PATCH 077/130] 6714 address comments and codacy --- .../discovery/search/DiscoveryAttributes.java | 54 +++++++++---------- .../discovery/search/DiscoveryKeyUtils.java | 12 ++++- .../discovery/search/DomainSearchCache.java | 10 ++-- .../discovery/ui/ArtifactTypeFilterPanel.java | 4 +- .../autopsy/discovery/ui/DateFilterPanel.java | 7 +-- 5 files changed, 49 insertions(+), 38 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java index 90cb880cc2..e827c8583b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java @@ -222,7 +222,7 @@ public class DiscoveryAttributes { static class FrequencyAttribute extends AttributeType { static final int BATCH_SIZE = 50; // Number of hashes to look up at one time - + static final int DOMAIN_BATCH_SIZE = 500; // Number of domains to look up at one time @Override @@ -255,13 +255,13 @@ public class DiscoveryAttributes { private void processResultFilesForCR(List results, CentralRepository centralRepoDb) throws DiscoveryException { List currentFiles = new ArrayList<>(); - Set hashesToLookUp = new HashSet<>(); + Set hashesToLookUp = new HashSet<>(); List domainsToQuery = new ArrayList<>(); for (Result result : results) { if (result.getKnown() == TskData.FileKnown.KNOWN) { result.setFrequency(SearchData.Frequency.KNOWN); } - + if (result.getType() != SearchData.Type.DOMAIN) { ResultFile file = (ResultFile) result; if (file.getFrequency() == SearchData.Frequency.UNKNOWN @@ -270,12 +270,12 @@ public class DiscoveryAttributes { hashesToLookUp.add(file.getFirstInstance().getMd5Hash()); currentFiles.add(file); } - - if (hashesToLookUp.size() >= BATCH_SIZE) { - computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); - hashesToLookUp.clear(); - currentFiles.clear(); + if (hashesToLookUp.size() >= BATCH_SIZE) { + computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); + + hashesToLookUp.clear(); + currentFiles.clear(); } } else { ResultDomain domain = (ResultDomain) result; @@ -295,31 +295,31 @@ public class DiscoveryAttributes { computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); ResultDomain domainInstance = (ResultDomain) result; domainsToQuery.add(domainInstance); - + if (domainsToQuery.size() == DOMAIN_BATCH_SIZE) { queryDomainFrequency(domainsToQuery, centralRepoDb); - + domainsToQuery.clear(); } } } - + queryDomainFrequency(domainsToQuery, centralRepoDb); computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); } } - + private static void queryDomainFrequency(List domainsToQuery, CentralRepository centralRepository) throws DiscoveryException { if (domainsToQuery.isEmpty()) { return; } - + try { final Map> resultDomainTable = new HashMap<>(); final StringJoiner joiner = new StringJoiner(", "); final CorrelationAttributeInstance.Type attributeType = centralRepository.getCorrelationTypeById(CorrelationAttributeInstance.DOMAIN_TYPE_ID); - for(ResultDomain domainInstance : domainsToQuery) { + for (ResultDomain domainInstance : domainsToQuery) { try { final String domainValue = domainInstance.getDomain(); final String normalizedDomain = CorrelationAttributeNormalizer.normalize(attributeType, domainValue); @@ -333,10 +333,10 @@ public class DiscoveryAttributes { } final String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(attributeType); - final String domainFrequencyQuery = " value AS domain_name, COUNT(*) AS frequency " + - "FROM " + tableName + " " + - "WHERE value IN (" + joiner + ") " + - "GROUP BY value"; + final String domainFrequencyQuery = " value AS domain_name, COUNT(*) AS frequency " + + "FROM " + tableName + " " + + "WHERE value IN (" + joiner + ") " + + "GROUP BY value"; final DomainFrequencyCallback frequencyCallback = new DomainFrequencyCallback(resultDomainTable); centralRepository.processSelectClause(domainFrequencyQuery, frequencyCallback); @@ -348,15 +348,15 @@ public class DiscoveryAttributes { throw new DiscoveryException("Fatal exception encountered querying the CR.", ex); } } - + private static class DomainFrequencyCallback implements InstanceTableCallback { - + private final Map> domainLookup; private SQLException sqlCause; - + private DomainFrequencyCallback(Map> domainLookup) { this.domainLookup = domainLookup; - } + } @Override public void process(ResultSet resultSet) { @@ -364,9 +364,9 @@ public class DiscoveryAttributes { while (resultSet.next()) { String domain = resultSet.getString("domain_name"); Long frequency = resultSet.getLong("frequency"); - + List domainInstances = domainLookup.get(domain); - for(ResultDomain domainInstance : domainInstances) { + for (ResultDomain domainInstance : domainInstances) { domainInstance.setFrequency(SearchData.Frequency.fromCount(frequency)); } } @@ -374,7 +374,7 @@ public class DiscoveryAttributes { this.sqlCause = ex; } } - + SQLException getCause() { return this.sqlCause; } @@ -733,7 +733,7 @@ public class DiscoveryAttributes { FILE_TAG(new FileTagAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_tag_displayName()), OBJECT_DETECTED(new ObjectDetectedAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_object_displayName()), MOST_RECENT_DATE(new MostRecentActivityDateAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_mostRecentDate_displayName()), - FIRST_DATE(new MostRecentActivityDateAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_firstDate_displayName()), + FIRST_DATE(new FirstActivityDateAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_firstDate_displayName()), NO_GROUPING(new NoGroupingAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_none_displayName()); private final AttributeType attributeType; @@ -771,7 +771,7 @@ public class DiscoveryAttributes { return Arrays.asList(FREQUENCY, MOST_RECENT_DATE, FIRST_DATE); } } - + /** * Computes the CR frequency of all the given hashes and updates the list of * files. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java index b00fee63e8..7d4bed0011 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java @@ -22,6 +22,7 @@ import java.text.SimpleDateFormat; import java.util.Collections; import java.util.Date; import java.util.List; +import java.util.Locale; import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.logging.Level; @@ -166,7 +167,8 @@ public class DiscoveryKeyUtils { /** * Get the fileSorting - * @return + * + * @return */ ResultsSorter.SortingMethod getFileSortingMethod() { return fileSortingMethod; @@ -938,6 +940,9 @@ public class DiscoveryKeyUtils { } } + /** + * Key representing a date of most recent activity. + */ static class MostRecentActivityDateGroupKey extends GroupKey { private final Long epochDate; @@ -1020,6 +1025,9 @@ public class DiscoveryKeyUtils { } } + /** + * Key representing a date of first activity. + */ static class FirstActivityDateGroupKey extends GroupKey { private final Long epochDate; @@ -1030,7 +1038,7 @@ public class DiscoveryKeyUtils { FirstActivityDateGroupKey(Result result) { if (result instanceof ResultDomain) { epochDate = ((ResultDomain) result).getActivityStart(); - dateNameString = new SimpleDateFormat("yyyy/MM/dd").format(new Date(TimeUnit.SECONDS.toMillis(epochDate))); + dateNameString = new SimpleDateFormat("yyyy/MM/dd", Locale.getDefault()).format(new Date(TimeUnit.SECONDS.toMillis(epochDate))); } else { epochDate = Long.MAX_VALUE; dateNameString = Bundle.DiscoveryKeyUtils_FirstActivityDateGroupKey_noDate(); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java index 481fabefb3..e7f46821a9 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java @@ -36,10 +36,10 @@ import org.sleuthkit.datamodel.SleuthkitCase; class DomainSearchCache { private static final int MAXIMUM_CACHE_SIZE = 10; - private static final LoadingCache>> cache = - CacheBuilder.newBuilder() - .maximumSize(MAXIMUM_CACHE_SIZE) - .build(new DomainSearchCacheLoader()); + private static final LoadingCache>> cache + = CacheBuilder.newBuilder() + .maximumSize(MAXIMUM_CACHE_SIZE) + .build(new DomainSearchCacheLoader()); /** * Get domain search results matching the given parameters. If no results @@ -57,7 +57,7 @@ class DomainSearchCache { groupSortingType, domainSortingMethod, caseDb, centralRepoDb); return cache.get(searchKey); - } catch (Throwable ex) { + } catch (ExecutionException ex) { throw new DiscoveryException("Error fetching results from cache", ex.getCause()); } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java index 00f3eff06d..089c18bf13 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactTypeFilterPanel.java @@ -25,6 +25,7 @@ import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.discovery.search.SearchData; import org.sleuthkit.autopsy.discovery.search.SearchFiltering.ArtifactTypeFilter; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -133,10 +134,11 @@ class ArtifactTypeFilterPanel extends AbstractDiscoveryFilterPanel { return null; } + @NbBundle.Messages({"ArtifactTypeFilterPanel.selectionNeeded.text=At least one Result type must be selected."}) @Override String checkForError() { if (artifactTypeCheckbox.isSelected() && artifactList.getSelectedValuesList().isEmpty()) { - return "At least one Result type must be selected."; + return Bundle.ArtifactTypeFilterPanel_selectionNeeded_text(); } return ""; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java index 803c637411..70bf5c6bb3 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java @@ -278,13 +278,15 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { } } + @NbBundle.Messages({"DateFilterPanel.invalidRange.text=Range or Only Last must be selected", + "DateFilterPanel.startOrEndNeeded.text=A start or end date must be specified to use the range filter"}) @Override String checkForError() { if (dateFilterCheckBox.isSelected()) { if (!(rangeRadioButton.isSelected() || mostRecentRadioButton.isSelected())) { - return "Range or Only Last must be selected"; + return Bundle.DateFilterPanel_invalidRange_text(); } else if (rangeRadioButton.isSelected() && !(startCheckBox.isSelected() || endCheckBox.isSelected())) { - return "A start or end date must be specified to use the range filter"; + return Bundle.DateFilterPanel_startOrEndNeeded_text(); } } return ""; @@ -292,7 +294,6 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { @Override AbstractFilter getFilter() { - if (dateFilterCheckBox.isSelected()) { LocalDate startDate = LocalDate.MIN; LocalDate endDate = LocalDate.MAX; From 1e2fc4755ef649476417fe316fb29c2cb739f748 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 16 Sep 2020 08:56:00 -0400 Subject: [PATCH 078/130] 6714 remove accidently duplicated code --- .../discovery/search/DiscoveryAttributes.java | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java index e827c8583b..59e620828a 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java @@ -278,21 +278,6 @@ public class DiscoveryAttributes { currentFiles.clear(); } } else { - ResultDomain domain = (ResultDomain) result; - try { - CorrelationAttributeInstance.Type domainAttributeType - = centralRepoDb.getCorrelationTypeById(CorrelationAttributeInstance.DOMAIN_TYPE_ID); - Long count = centralRepoDb.getCountArtifactInstancesByTypeValue(domainAttributeType, domain.getDomain()); - domain.setFrequency(SearchData.Frequency.fromCount(count)); - } catch (CentralRepoException ex) { - throw new DiscoveryException("Error encountered querying the central repository.", ex); - } catch (CorrelationAttributeNormalizationException ex) { - logger.log(Level.INFO, "Domain [%s] could not be normalized for central repository querying, skipping...", domain.getDomain()); - } - } - - if (hashesToLookUp.size() >= BATCH_SIZE) { - computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); ResultDomain domainInstance = (ResultDomain) result; domainsToQuery.add(domainInstance); From dda7ec04d88fe91a0d2188d43cbd6fc6a2406b0c Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 16 Sep 2020 09:08:30 -0400 Subject: [PATCH 079/130] bug fixes --- .../datamodel/Bundle.properties-MERGED | 1 + .../datasourcesummary/ui/AnalysisPanel.form | 5 +++++ .../datasourcesummary/ui/AnalysisPanel.java | 1 + .../ui/BaseDataSourceSummaryPanel.java | 4 ++-- .../ui/Bundle.properties-MERGED | 4 ++++ .../datasourcesummary/ui/PastCasesPanel.form | 17 +++++++++++++---- .../datasourcesummary/ui/PastCasesPanel.java | 16 ++++++++++++---- .../ui/RecentFilesPanel.form | 19 ++++++++++++------- .../ui/RecentFilesPanel.java | 14 ++++++++------ .../datasourcesummary/ui/TypesPanel.form | 5 +++++ .../datasourcesummary/ui/TypesPanel.java | 5 +++-- .../ui/UserActivityPanel.form | 5 +++++ .../ui/UserActivityPanel.java | 2 ++ .../uiutils/Bundle.properties-MERGED | 1 + .../uiutils/IngestRunningLabel.java | 4 ++++ 15 files changed, 78 insertions(+), 25 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/Bundle.properties-MERGED index 2e019a0248..8d62e88381 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/Bundle.properties-MERGED @@ -1,2 +1,3 @@ DataSourceUserActivitySummary_getRecentAccounts_calllogMessage=Call Log DataSourceUserActivitySummary_getRecentAccounts_emailMessage=Email Message +IngestModuleCheckUtil_recentActivityModuleName=Recent Activity diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form index 07ed2771e1..0a0b094ff8 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form @@ -59,6 +59,11 @@ + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java index 0cfca04286..b4f9138117 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java @@ -177,6 +177,7 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { mainContentPanel.setMinimumSize(new java.awt.Dimension(200, 452)); mainContentPanel.setLayout(new javax.swing.BoxLayout(mainContentPanel, javax.swing.BoxLayout.PAGE_AXIS)); + ingestRunningPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 5, 1)); ingestRunningPanel.setAlignmentX(0.0F); ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 20)); ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 20)); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java index 6e5310cc8d..12bd75ffcb 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java @@ -324,7 +324,7 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { * Search'). */ protected void showResultWithModuleCheck(LoadableComponent> component, DataFetchResult> result, String factoryClass, String moduleName) { - Predicate> hasResults = (lst) -> lst == null || lst.isEmpty(); + Predicate> hasResults = (lst) -> lst != null && !lst.isEmpty(); showResultWithModuleCheck(component, result, hasResults, factoryClass, moduleName); } @@ -348,7 +348,7 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { if (result != null && result.getResultType() == ResultType.SUCCESS && !hasResults.test(result.getData())) { try { - if (ingestModuleCheck.isModuleIngested(getDataSource(), factoryClass)) { + if (!ingestModuleCheck.isModuleIngested(getDataSource(), factoryClass)) { component.showMessage(getDefaultNoIngestMessage(moduleName)); return; } 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 c994603559..1bf1de03b3 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -1,5 +1,8 @@ AnalysisPanel_countColumn_title=Count AnalysisPanel_keyColumn_title=Name +AnalysisPanel_keywordSearchModuleName=Keyword Search +# {0} - module name +BaseDataSourceSummaryPanel_defaultNotIngestMessage=The {0} Ingest Module has not been run on this datasource. ContainerPanel.getDataSources.error.text=Failed to get the list of datasources for the current case. ContainerPanel.getDataSources.error.title=Load Failure CTL_DataSourceSummaryAction=Data Source Summary @@ -54,6 +57,7 @@ PastCasesPanel_onNoCrIngest_message=No results will be shown because the Central RecentFilePanel_col_header_domain=Domain RecentFilePanel_col_header_path=Path RecentFilePanel_col_header_sender=Sender +RecentFilePanel_emailParserModuleName=Email Parser RecentFilePanel_no_open_documents=No recently open documents found. RecentFilesPanel_col_head_date=Date SizeRepresentationUtil_units_bytes=\ bytes diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form index fd8a67cd36..f5b217fd85 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form @@ -53,6 +53,11 @@ + + + + + @@ -61,7 +66,7 @@ - + @@ -91,7 +96,7 @@ - + @@ -99,6 +104,7 @@ + @@ -130,7 +136,7 @@ - + @@ -138,6 +144,7 @@ + @@ -159,7 +166,7 @@ - + @@ -167,6 +174,7 @@ + @@ -200,6 +208,7 @@ + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java index 5a520e471f..4499a5eea5 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java @@ -157,27 +157,29 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { javax.swing.JPanel mainContentPanel = new javax.swing.JPanel(); javax.swing.JPanel ingestRunningPanel = ingestRunningLabel; javax.swing.JLabel notableFileLabel = 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.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 notableFilePanel = notableFileTable; - 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.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.JLabel sameIdLabel = new javax.swing.JLabel(); - javax.swing.Box.Filler filler3 = 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.Box.Filler filler3 = 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 sameIdPanel = sameIdTable; 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)); mainContentPanel.setLayout(new javax.swing.BoxLayout(mainContentPanel, javax.swing.BoxLayout.PAGE_AXIS)); + ingestRunningPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 5, 1)); ingestRunningPanel.setAlignmentX(0.0F); ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 20)); ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 20)); - ingestRunningPanel.setPreferredSize(new java.awt.Dimension(32767, 20)); + ingestRunningPanel.setPreferredSize(new java.awt.Dimension(10, 20)); mainContentPanel.add(ingestRunningPanel); org.openide.awt.Mnemonics.setLocalizedText(notableFileLabel, org.openide.util.NbBundle.getMessage(PastCasesPanel.class, "PastCasesPanel.notableFileLabel.text")); // NOI18N mainContentPanel.add(notableFileLabel); notableFileLabel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(PastCasesPanel.class, "PastCasesPanel.notableFileLabel.text")); // NOI18N + filler1.setAlignmentX(0.0F); mainContentPanel.add(filler1); notableFilePanel.setAlignmentX(0.0F); @@ -185,10 +187,14 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { notableFilePanel.setMinimumSize(new java.awt.Dimension(100, 106)); notableFilePanel.setPreferredSize(new java.awt.Dimension(100, 106)); mainContentPanel.add(notableFilePanel); + + filler2.setAlignmentX(0.0F); mainContentPanel.add(filler2); org.openide.awt.Mnemonics.setLocalizedText(sameIdLabel, org.openide.util.NbBundle.getMessage(PastCasesPanel.class, "PastCasesPanel.sameIdLabel.text")); // NOI18N mainContentPanel.add(sameIdLabel); + + filler3.setAlignmentX(0.0F); mainContentPanel.add(filler3); sameIdPanel.setAlignmentX(0.0F); @@ -196,6 +202,8 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { sameIdPanel.setMinimumSize(new java.awt.Dimension(100, 106)); sameIdPanel.setPreferredSize(new java.awt.Dimension(100, 106)); mainContentPanel.add(sameIdPanel); + + filler5.setAlignmentX(0.0F); mainContentPanel.add(filler5); mainScrollPane.setViewportView(mainContentPanel); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.form index b67ec8a6a3..7f94219af6 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.form @@ -31,6 +31,11 @@ + + + + + @@ -65,7 +70,7 @@ - + @@ -77,7 +82,7 @@ - + @@ -89,7 +94,7 @@ - + @@ -101,7 +106,7 @@ - + @@ -119,7 +124,7 @@ - + @@ -135,7 +140,7 @@ - + @@ -151,7 +156,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java index b599e60bd6..c61633981e 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java @@ -237,6 +237,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { setLayout(new java.awt.BorderLayout()); + tablePanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10)); tablePanel.setMinimumSize(new java.awt.Dimension(400, 400)); tablePanel.setPreferredSize(new java.awt.Dimension(600, 400)); tablePanel.setLayout(new java.awt.GridBagLayout()); @@ -250,6 +251,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { gridBagConstraints.gridy = 0; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 0); tablePanel.add(ingestRunningPanel, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; @@ -258,7 +260,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; - gridBagConstraints.insets = new java.awt.Insets(5, 5, 0, 5); + gridBagConstraints.insets = new java.awt.Insets(2, 0, 0, 0); tablePanel.add(openedDocPane, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; @@ -267,7 +269,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; - gridBagConstraints.insets = new java.awt.Insets(5, 5, 0, 5); + gridBagConstraints.insets = new java.awt.Insets(2, 0, 0, 0); tablePanel.add(downloadsPane, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; @@ -276,7 +278,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; - gridBagConstraints.insets = new java.awt.Insets(5, 5, 10, 5); + gridBagConstraints.insets = new java.awt.Insets(2, 0, 0, 0); tablePanel.add(attachmentsPane, gridBagConstraints); org.openide.awt.Mnemonics.setLocalizedText(openDocsLabel, org.openide.util.NbBundle.getMessage(RecentFilesPanel.class, "RecentFilesPanel.openDocsLabel.text")); // NOI18N @@ -285,7 +287,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; - gridBagConstraints.insets = new java.awt.Insets(10, 5, 0, 5); + gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0); tablePanel.add(openDocsLabel, gridBagConstraints); org.openide.awt.Mnemonics.setLocalizedText(downloadLabel, org.openide.util.NbBundle.getMessage(RecentFilesPanel.class, "RecentFilesPanel.downloadLabel.text")); // NOI18N @@ -293,7 +295,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.insets = new java.awt.Insets(15, 5, 0, 5); + gridBagConstraints.insets = new java.awt.Insets(20, 0, 0, 0); tablePanel.add(downloadLabel, gridBagConstraints); org.openide.awt.Mnemonics.setLocalizedText(attachmentLabel, org.openide.util.NbBundle.getMessage(RecentFilesPanel.class, "RecentFilesPanel.attachmentLabel.text")); // NOI18N @@ -302,7 +304,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { gridBagConstraints.gridy = 5; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; - gridBagConstraints.insets = new java.awt.Insets(15, 5, 0, 5); + gridBagConstraints.insets = new java.awt.Insets(20, 0, 0, 0); tablePanel.add(attachmentLabel, gridBagConstraints); scrollPane.setViewportView(tablePanel); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.form index 36a8ee3493..3619bb574f 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.form @@ -54,6 +54,11 @@ + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java index 17a07dc399..483b0543d4 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java @@ -194,7 +194,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel { showResultWithModuleCheck( usageLabel, result, - StringUtils::isBlank, + StringUtils::isNotBlank, IngestModuleCheckUtil.RECENT_ACTIVITY_FACTORY, IngestModuleCheckUtil.RECENT_ACTIVITY_MODULE_NAME); }), @@ -205,7 +205,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel { showResultWithModuleCheck( osLabel, result, - StringUtils::isBlank, + StringUtils::isNotBlank, IngestModuleCheckUtil.RECENT_ACTIVITY_FACTORY, IngestModuleCheckUtil.RECENT_ACTIVITY_MODULE_NAME); }), @@ -356,6 +356,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel { contentParent.setMinimumSize(new java.awt.Dimension(400, 490)); contentParent.setLayout(new javax.swing.BoxLayout(contentParent, javax.swing.BoxLayout.PAGE_AXIS)); + ingestRunningPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 5, 1)); ingestRunningPanel.setAlignmentX(0.0F); ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 20)); ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 20)); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.form index f4daefb048..52c456fa4f 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.form @@ -62,6 +62,11 @@ + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java index 1e83a71cb8..3cb71a177b 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.Locale; 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.TopProgramsSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopAccountResult; @@ -367,6 +368,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { contentPanel.setMinimumSize(new java.awt.Dimension(10, 450)); contentPanel.setLayout(new javax.swing.BoxLayout(contentPanel, javax.swing.BoxLayout.PAGE_AXIS)); + ingestRunningPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 5, 1)); ingestRunningPanel.setAlignmentX(0.0F); ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 20)); ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 20)); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/Bundle.properties-MERGED index 491c3bfa56..b7e31eace5 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/Bundle.properties-MERGED @@ -1,3 +1,4 @@ AbstractLoadableComponent_errorMessage_defaultText=There was an error loading results. AbstractLoadableComponent_loadingMessage_defaultText=Loading results... AbstractLoadableComponent_noDataExists_defaultText=No data exists. +IngestRunningLabel_defaultMessage=Ingest is currently running. diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java index 044c9c0346..e38695bddd 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java @@ -126,6 +126,10 @@ public class IngestRunningLabel extends JPanel { public IngestRunningLabel(String message, boolean showWarningIcon) { JLabel jlabel = new JLabel(); jlabel.setText(message); + jlabel.setVerticalAlignment(JLabel.TOP); + jlabel.setVerticalTextPosition(JLabel.TOP); + jlabel.setHorizontalAlignment(JLabel.LEFT); + jlabel.setHorizontalTextPosition(JLabel.LEFT); if (showWarningIcon) { jlabel.setIcon(new ImageIcon(DEFAULT_ICON)); } From 82a1126a3fa29d060809183a13ef88ed58dfe899 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 16 Sep 2020 09:39:16 -0400 Subject: [PATCH 080/130] 6715 address review comments --- .../autopsy/discovery/ui/DomainSummaryViewer.form | 1 + .../autopsy/discovery/ui/DomainSummaryViewer.java | 3 +-- .../autopsy/discovery/ui/DomainWrapper.java | 12 ++++++------ .../sleuthkit/autopsy/discovery/ui/ResultsPanel.java | 10 +++++----- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.form index 7489c56609..9f1e3516b9 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.form @@ -11,6 +11,7 @@ + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.java index 849c9a9afd..50f6c4df53 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.java @@ -21,8 +21,7 @@ package org.sleuthkit.autopsy.discovery.ui; import javax.swing.DefaultListModel; /** - * - * @author wschaefer + * A JPanel to display domain summaries. */ public class DomainSummaryViewer extends javax.swing.JPanel { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainWrapper.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainWrapper.java index 47ae242360..b3ee3999ac 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainWrapper.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainWrapper.java @@ -22,12 +22,12 @@ import java.awt.Image; import org.sleuthkit.autopsy.discovery.search.ResultDomain; /** - * - * @author wschaefer + * Class to wrap all the information necessary for a domain summary to be + * displayed. */ public class DomainWrapper { - private ResultDomain domain; + private final ResultDomain domain; private Image thumbnail = null; /** @@ -43,10 +43,10 @@ public class DomainWrapper { /** * Set the thumbnail which exists. * - * @param thumbnail The Image object which will be used to represent this + * @param thumbnail The image object which will be used to represent this * domain object. */ - void setThumnail(Image thumbnail) { + void setThumbnail(Image thumbnail) { this.thumbnail = thumbnail; } @@ -64,7 +64,7 @@ public class DomainWrapper { /** * Get the image to be used for the domain. * - * @return The Image which represents the domain. + * @return The image which represents the domain. */ Image getThumbnail() { return thumbnail; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java index 54de9aa693..662dbdd78c 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java @@ -120,7 +120,7 @@ final class ResultsPanel extends javax.swing.JPanel { } } }); - //JIRA-TODO + //JIRA-TODO 6307 Add listener for domainSummaryViewer when 6782, 6773, and the other details area related stories are done } /** @@ -812,7 +812,7 @@ final class ResultsPanel extends javax.swing.JPanel { @Override protected Void doInBackground() throws Exception { - domainWrapper.setThumnail(null); + domainWrapper.setThumbnail(null); return null; } @@ -821,13 +821,13 @@ final class ResultsPanel extends javax.swing.JPanel { try { get(); } catch (InterruptedException | ExecutionException ex) { - domainWrapper.setThumnail(null); + domainWrapper.setThumbnail(null); logger.log(Level.WARNING, "Document Worker Exception", ex); } catch (CancellationException ignored) { - domainWrapper.setThumnail(null); + domainWrapper.setThumbnail(null); //we want to do nothing in response to this since we allow it to be cancelled } - documentPreviewViewer.repaint(); + domainSummaryViewer.repaint(); } } From f4a24501c59a08097d43e31e3bbd65c5166eb49c Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 16 Sep 2020 09:54:31 -0400 Subject: [PATCH 081/130] 6715 fix codacy issues update merged properties file --- .../sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java | 2 +- .../sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED | 3 +++ .../sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.java | 4 ++-- .../sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.form | 2 ++ .../sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.java | 3 +-- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java index 7d4bed0011..6d7b763c7d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java @@ -953,7 +953,7 @@ public class DiscoveryKeyUtils { MostRecentActivityDateGroupKey(Result result) { if (result instanceof ResultDomain) { epochDate = ((ResultDomain) result).getActivityEnd(); - dateNameString = new SimpleDateFormat("yyyy/MM/dd").format(new Date(TimeUnit.SECONDS.toMillis(epochDate))); + dateNameString = new SimpleDateFormat("yyyy/MM/dd", Locale.getDefault()).format(new Date(TimeUnit.SECONDS.toMillis(epochDate))); } else { epochDate = Long.MAX_VALUE; dateNameString = Bundle.DiscoveryKeyUtils_MostRecentActivityDateGroupKey_noDate(); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED index 48f0a1aab7..fb85b8a049 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED @@ -1,3 +1,4 @@ +ArtifactTypeFilterPanel.selectionNeeded.text=At least one Result type must be selected. CTL_OpenDiscoveryAction=Discovery # {0} - dataSourceName DataSourceModuleWrapper.exifModule.text=Exif Parser module was not run on data source: {0}\n @@ -7,6 +8,8 @@ DataSourceModuleWrapper.fileTypeModule.text=File Type Identification module was DataSourceModuleWrapper.hashModule.text=Hash Lookup module was not run on data source: {0}\n # {0} - timeZone DateFilterPanel.dateRange.text=Date Range ({0}): +DateFilterPanel.invalidRange.text=Range or Only Last must be selected +DateFilterPanel.startOrEndNeeded.text=A start or end date must be specified to use the range filter DiscoveryDialog.name.text=Discovery DiscoveryTopComponent.cancelButton.text=Cancel Search DiscoveryTopComponent.name=\ Discovery diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.java index cb29bff5cc..5aa269eeb4 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryPanel.java @@ -24,6 +24,7 @@ import java.awt.Point; import java.awt.event.MouseEvent; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.Locale; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JList; @@ -38,8 +39,7 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer< private static final long serialVersionUID = 1L; private static final Color SELECTION_COLOR = new Color(0, 120, 215); - private static final int MAX_NAME_STRING = 90; - private static final SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd yyyy"); + private static final SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd yyyy", Locale.getDefault()); /** * Creates new form DomainPanel. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.form index 9f1e3516b9..22296c0178 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.form @@ -39,6 +39,8 @@ + + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.java index 50f6c4df53..593ae49949 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainSummaryViewer.java @@ -56,7 +56,7 @@ public class DomainSummaryViewer extends javax.swing.JPanel { private void initComponents() { domainScrollPane = new javax.swing.JScrollPane(); - domainList = new javax.swing.JList<>(); + javax.swing.JList domainList = new javax.swing.JList<>(); setLayout(new java.awt.BorderLayout()); @@ -69,7 +69,6 @@ public class DomainSummaryViewer extends javax.swing.JPanel { // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JList domainList; private javax.swing.JScrollPane domainScrollPane; // End of variables declaration//GEN-END:variables From 06c42b1ce4b5c1552125ddaf645b68f9696f0add Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 16 Sep 2020 10:21:03 -0400 Subject: [PATCH 082/130] bug fixes and formatting --- .../autopsy/datasourcesummary/ui/AnalysisPanel.form | 11 +++-------- .../autopsy/datasourcesummary/ui/AnalysisPanel.java | 7 +++---- .../datasourcesummary/ui/PastCasesPanel.form | 11 +++-------- .../datasourcesummary/ui/PastCasesPanel.java | 13 +++++++------ .../datasourcesummary/ui/RecentFilesPanel.form | 10 +++++----- .../datasourcesummary/ui/RecentFilesPanel.java | 8 +++----- .../autopsy/datasourcesummary/ui/TypesPanel.form | 11 +++-------- .../autopsy/datasourcesummary/ui/TypesPanel.java | 7 +++---- .../datasourcesummary/ui/UserActivityPanel.form | 11 +++-------- .../datasourcesummary/ui/UserActivityPanel.java | 7 +++---- .../uiutils/IngestRunningLabel.java | 7 ++----- 11 files changed, 38 insertions(+), 65 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form index 0a0b094ff8..402b709b38 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form @@ -59,20 +59,15 @@ - - - - - - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java index b4f9138117..34dfa97a13 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java @@ -177,11 +177,10 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { mainContentPanel.setMinimumSize(new java.awt.Dimension(200, 452)); mainContentPanel.setLayout(new javax.swing.BoxLayout(mainContentPanel, javax.swing.BoxLayout.PAGE_AXIS)); - ingestRunningPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 5, 1)); ingestRunningPanel.setAlignmentX(0.0F); - ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 20)); - ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 20)); - ingestRunningPanel.setPreferredSize(new java.awt.Dimension(32767, 20)); + ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 25)); + ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 25)); + ingestRunningPanel.setPreferredSize(new java.awt.Dimension(10, 25)); mainContentPanel.add(ingestRunningPanel); org.openide.awt.Mnemonics.setLocalizedText(hashsetHitsLabel, org.openide.util.NbBundle.getMessage(AnalysisPanel.class, "AnalysisPanel.hashsetHitsLabel.text")); // NOI18N diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form index f5b217fd85..7c84d44660 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form @@ -53,20 +53,15 @@ - - - - - - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java index 4499a5eea5..76d36f4785 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java @@ -120,8 +120,10 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { * data. */ private DataFetchResult getSubResult(DataFetchResult inputResult, Function getSubResult) { - if (inputResult.getResultType() == ResultType.SUCCESS) { - O innerData = (inputResult == null) ? null : getSubResult.apply(inputResult.getData()); + if (inputResult == null) { + return null; + } else if (inputResult.getResultType() == ResultType.SUCCESS) { + O innerData = (inputResult.getData() == null) ? null : getSubResult.apply(inputResult.getData()); return DataFetchResult.getSuccessResult(innerData); } else { return DataFetchResult.getErrorResult(inputResult.getException()); @@ -168,11 +170,10 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { mainContentPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10)); mainContentPanel.setLayout(new javax.swing.BoxLayout(mainContentPanel, javax.swing.BoxLayout.PAGE_AXIS)); - ingestRunningPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 5, 1)); ingestRunningPanel.setAlignmentX(0.0F); - ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 20)); - ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 20)); - ingestRunningPanel.setPreferredSize(new java.awt.Dimension(10, 20)); + ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 25)); + ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 25)); + ingestRunningPanel.setPreferredSize(new java.awt.Dimension(10, 25)); mainContentPanel.add(ingestRunningPanel); org.openide.awt.Mnemonics.setLocalizedText(notableFileLabel, org.openide.util.NbBundle.getMessage(PastCasesPanel.class, "PastCasesPanel.notableFileLabel.text")); // NOI18N diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.form index 7f94219af6..150abf2ed0 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.form @@ -54,13 +54,13 @@ - + - + - + @@ -70,7 +70,7 @@ - + @@ -124,7 +124,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java index c61633981e..1b675032d0 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java @@ -243,15 +243,14 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { tablePanel.setLayout(new java.awt.GridBagLayout()); ingestRunningPanel.setAlignmentX(0.0F); - ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 20)); - ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 20)); - ingestRunningPanel.setPreferredSize(new java.awt.Dimension(32767, 20)); + ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 25)); + ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 25)); + ingestRunningPanel.setPreferredSize(new java.awt.Dimension(10, 25)); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 0); tablePanel.add(ingestRunningPanel, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; @@ -287,7 +286,6 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; - gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0); tablePanel.add(openDocsLabel, gridBagConstraints); org.openide.awt.Mnemonics.setLocalizedText(downloadLabel, org.openide.util.NbBundle.getMessage(RecentFilesPanel.class, "RecentFilesPanel.downloadLabel.text")); // NOI18N diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.form index 3619bb574f..efb1ca2aae 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.form @@ -54,20 +54,15 @@ - - - - - - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java index 483b0543d4..c9cc439b16 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java @@ -356,11 +356,10 @@ class TypesPanel extends BaseDataSourceSummaryPanel { contentParent.setMinimumSize(new java.awt.Dimension(400, 490)); contentParent.setLayout(new javax.swing.BoxLayout(contentParent, javax.swing.BoxLayout.PAGE_AXIS)); - ingestRunningPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 5, 1)); ingestRunningPanel.setAlignmentX(0.0F); - ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 20)); - ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 20)); - ingestRunningPanel.setPreferredSize(new java.awt.Dimension(32767, 20)); + ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 25)); + ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 25)); + ingestRunningPanel.setPreferredSize(new java.awt.Dimension(10, 25)); contentParent.add(ingestRunningPanel); usagePanel.setAlignmentX(0.0F); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.form index 52c456fa4f..28560a3ec7 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.form @@ -62,20 +62,15 @@ - - - - - - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java index 3cb71a177b..476d8c5e6f 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java @@ -368,11 +368,10 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { contentPanel.setMinimumSize(new java.awt.Dimension(10, 450)); contentPanel.setLayout(new javax.swing.BoxLayout(contentPanel, javax.swing.BoxLayout.PAGE_AXIS)); - ingestRunningPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 5, 1)); ingestRunningPanel.setAlignmentX(0.0F); - ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 20)); - ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 20)); - ingestRunningPanel.setPreferredSize(new java.awt.Dimension(32767, 20)); + ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 25)); + ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 25)); + ingestRunningPanel.setPreferredSize(new java.awt.Dimension(10, 25)); contentPanel.add(ingestRunningPanel); programsRunLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java index e38695bddd..0f6c694ee9 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java @@ -126,16 +126,13 @@ public class IngestRunningLabel extends JPanel { public IngestRunningLabel(String message, boolean showWarningIcon) { JLabel jlabel = new JLabel(); jlabel.setText(message); - jlabel.setVerticalAlignment(JLabel.TOP); - jlabel.setVerticalTextPosition(JLabel.TOP); - jlabel.setHorizontalAlignment(JLabel.LEFT); - jlabel.setHorizontalTextPosition(JLabel.LEFT); + if (showWarningIcon) { jlabel.setIcon(new ImageIcon(DEFAULT_ICON)); } setLayout(new BorderLayout()); - add(jlabel, BorderLayout.CENTER); + add(jlabel, BorderLayout.NORTH); setupListener(this); refreshState(); From 182b1d3f713a8f5a0005a829af0750dea2600e83 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 16 Sep 2020 12:27:48 -0400 Subject: [PATCH 083/130] working on updates --- .../datasourcesummary/ui/BaseDataSourceSummaryPanel.java | 2 +- .../sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java | 2 +- .../autopsy/datasourcesummary/uiutils/PieChartPanel.java | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java index 12bd75ffcb..cf11c45330 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java @@ -296,7 +296,7 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { */ @Messages({ "# {0} - module name", - "BaseDataSourceSummaryPanel_defaultNotIngestMessage=The {0} Ingest Module has not been run on this datasource." + "BaseDataSourceSummaryPanel_defaultNotIngestMessage=The {0} ingest module has not been run on this datasource." }) protected String getDefaultNoIngestMessage(String moduleName) { return Bundle.BaseDataSourceSummaryPanel_defaultNotIngestMessage(moduleName); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java index c9cc439b16..f01784ca4a 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java @@ -101,7 +101,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel { String formattedKey = StringUtils.isBlank(key) ? "" : key; String formattedValue = StringUtils.isBlank(value) ? "" : value; String htmlFormattedValue = (italicize) ? String.format("%s", formattedValue) : formattedValue; - label.setText(String.format("

%s: %s
", formattedKey, htmlFormattedValue)); + label.setText(String.format("%s: %s", formattedKey, htmlFormattedValue)); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/PieChartPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/PieChartPanel.java index 8d6eab4a9b..6cde2f074b 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/PieChartPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/PieChartPanel.java @@ -198,4 +198,8 @@ public class PieChartPanel extends AbstractLoadableComponent data) { + + } } From 6fbe72065575d567501f423532ab031fd8b2cec7 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 16 Sep 2020 12:34:06 -0400 Subject: [PATCH 084/130] 6714 update getFilter panel with fixes from Danny --- .../org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java index 70bf5c6bb3..0d09bc13e4 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java @@ -299,7 +299,7 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { LocalDate endDate = LocalDate.MAX; ZoneId zone = Utils.getUserPreferredZoneId(); if (rangeRadioButton.isSelected() && (startCheckBox.isSelected() || endCheckBox.isSelected())) { - if (startCheckBox.isSelected() && startDatePicker.getDate().equals(startDate)) { + if (startCheckBox.isSelected() && startDatePicker.getDate() != null) { startDate = startDatePicker.getDate(); } if (endCheckBox.isSelected() && endDatePicker.getDate() != null) { @@ -307,7 +307,7 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { } } else if (dateFilterCheckBox.isSelected() && mostRecentRadioButton.isSelected()) { endDate = LocalDate.now(); - startDate = LocalDate.now().minus(Duration.ofDays((long) daysSpinner.getValue())); + startDate = LocalDate.now().minus(Period.ofDays((Integer) daysSpinner.getValue())); } return new SearchFiltering.ArtifactDateRangeFilter(startDate.atStartOfDay(zone).toEpochSecond(), endDate.atStartOfDay(zone).toEpochSecond() + SECS_PER_DAY);//to insure end date is inclusive } From db32e290f29fd82c289e1e506c85206c224eb602 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 16 Sep 2020 12:41:33 -0400 Subject: [PATCH 085/130] 6714 fix import --- .../src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java index 0d09bc13e4..668e441f95 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java @@ -19,8 +19,8 @@ package org.sleuthkit.autopsy.discovery.ui; import java.awt.event.ActionListener; -import java.time.Duration; import java.time.LocalDate; +import java.time.Period; import java.time.ZoneId; import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import javax.swing.JCheckBox; From 8b57ce3da5bb873551476c68973674c4ea7650d0 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Wed, 16 Sep 2020 13:16:29 -0400 Subject: [PATCH 086/130] Updated the code to generate thumbnails and disabled the details view as best as I could --- .../search/DomainSearchThumbnailLoader.java | 5 ++- .../discovery/ui/Bundle.properties-MERGED | 1 + .../discovery/ui/DiscoveryTopComponent.java | 6 +-- .../discovery/ui/DomainSummaryPanel.java | 12 +++--- .../autopsy/discovery/ui/ResultsPanel.java | 43 ++++++++++++++++--- .../discovery/ui/ResultsSplitPaneDivider.java | 28 +++++++++++- 6 files changed, 78 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 0a6a34bf8c..a96225534e 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.ArrayList; import java.util.Collections; import org.sleuthkit.autopsy.coreutils.ImageUtils; +import org.openide.util.ImageUtilities; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.AbstractFile; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE; @@ -47,6 +48,8 @@ public class DomainSearchThumbnailLoader extends CacheLoader list, DomainWrapper value, int index, boolean isSelected, boolean cellHasFocus) { domainNameLabel.setText(value.getResultDomain().getDomain()); @@ -153,8 +152,11 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer< pagesLabel.setText(Bundle.DomainSummaryPanel_pages_text() + value.getResultDomain().getVisitsInLast60()); filesDownloadedLabel.setText(Bundle.DomainSummaryPanel_downloads_text() + value.getResultDomain().getFilesDownloaded()); if (value.getThumbnail() == null) { - numberOfImagesLabel.setText(Bundle.DocumentPanel_numberOfImages_noImages()); - sampleImageLabel.setIcon(new ImageIcon(ImageUtils.getDefaultThumbnail())); + numberOfImagesLabel.setText(Bundle.DomainSummaryPanel_loadingImages_text()); + sampleImageLabel.setIcon(null); + } else { + numberOfImagesLabel.setText(null); + sampleImageLabel.setIcon(new ImageIcon(value.getThumbnail())); } setBackground(isSelected ? SELECTION_COLOR : list.getBackground()); return this; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java index 54de9aa693..cfbfe26ae6 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java @@ -33,6 +33,8 @@ import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; @@ -41,6 +43,8 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; +import org.sleuthkit.autopsy.discovery.search.DomainSearch; +import org.sleuthkit.autopsy.discovery.search.DomainSearchThumbnailRequest; import org.sleuthkit.autopsy.discovery.search.Group; import org.sleuthkit.autopsy.discovery.search.FileSearch; import org.sleuthkit.autopsy.discovery.search.SearchData; @@ -50,6 +54,7 @@ import org.sleuthkit.autopsy.discovery.search.ResultDomain; import org.sleuthkit.autopsy.discovery.search.ResultFile; import static org.sleuthkit.autopsy.discovery.search.SearchData.Type.DOMAIN; import org.sleuthkit.autopsy.textsummarizer.TextSummary; +import org.sleuthkit.datamodel.SleuthkitCase; /** * Panel for displaying of Discovery results and handling the paging of those @@ -122,6 +127,10 @@ final class ResultsPanel extends javax.swing.JPanel { }); //JIRA-TODO } + + SearchData.Type getActiveType() { + return resultType; + } /** * Get the list of all instances for the the currently selected item in the @@ -278,8 +287,17 @@ final class ResultsPanel extends javax.swing.JPanel { * viewer with. */ synchronized void populateDomainViewer(List results) { + SleuthkitCase currentCase; + try { + currentCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + } catch (NoCurrentCaseException ex) { + // Do nothing, case has been closed. + return; + } + for (Result result : results) { - DomainThumbnailWorker domainWorker = new DomainThumbnailWorker((ResultDomain) result); + DomainThumbnailWorker domainWorker = new DomainThumbnailWorker( + currentCase, (ResultDomain) result); domainWorker.execute(); //keep track of thumb worker for possible cancelation resultContentWorkers.add(domainWorker); @@ -301,6 +319,7 @@ final class ResultsPanel extends javax.swing.JPanel { selectedGroupKey = groupSelectedEvent.getGroupKey(); resultType = groupSelectedEvent.getResultType(); groupSize = groupSelectedEvent.getGroupSize(); + resetResultViewer(); setPage(0); }); } @@ -798,6 +817,7 @@ final class ResultsPanel extends javax.swing.JPanel { private class DomainThumbnailWorker extends SwingWorker { private final DomainWrapper domainWrapper; + private final SleuthkitCase caseDb; /** * Construct a new DomainThumbnailWorker. @@ -805,14 +825,23 @@ final class ResultsPanel extends javax.swing.JPanel { * @param file The ResultFile which represents the domain attribute the * preview is being retrieved for. */ - DomainThumbnailWorker(ResultDomain domain) { + DomainThumbnailWorker(SleuthkitCase caseDb, ResultDomain domain) { + this.caseDb = caseDb; domainWrapper = new DomainWrapper(domain); domainSummaryViewer.addDomain(domainWrapper); } @Override protected Void doInBackground() throws Exception { - domainWrapper.setThumnail(null); + DomainSearch domainSearch = new DomainSearch(); + DomainSearchThumbnailRequest request = new DomainSearchThumbnailRequest( + caseDb, + domainWrapper.getResultDomain().getDomain(), + ImageUtils.ICON_SIZE_LARGE + ); + + Image thumbnail = domainSearch.getThumbnail(request); + domainWrapper.setThumnail(thumbnail); return null; } @@ -820,14 +849,14 @@ final class ResultsPanel extends javax.swing.JPanel { protected void done() { try { get(); - } catch (InterruptedException | ExecutionException ex) { + } catch (ExecutionException ex) { domainWrapper.setThumnail(null); - logger.log(Level.WARNING, "Document Worker Exception", ex); - } catch (CancellationException ignored) { + logger.log(Level.WARNING, "Fatal error getting thumbnail for domain.", ex); + } catch (InterruptedException | CancellationException ignored) { domainWrapper.setThumnail(null); //we want to do nothing in response to this since we allow it to be cancelled } - documentPreviewViewer.repaint(); + domainSummaryViewer.repaint(); } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.java index 6a08f681e4..4306e592be 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.java @@ -19,7 +19,10 @@ package org.sleuthkit.autopsy.discovery.ui; import java.awt.Cursor; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionListener; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; +import org.sleuthkit.autopsy.discovery.search.SearchData; /** * Panel for separating the results list from the details area. @@ -27,12 +30,29 @@ import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; final class ResultsSplitPaneDivider extends javax.swing.JPanel { private static final long serialVersionUID = 1L; + private final ResultsPanel resultsPanel; /** * Creates new form LabeledSplitPaneDivider. */ - ResultsSplitPaneDivider() { + ResultsSplitPaneDivider(ResultsPanel resultsPanel) { initComponents(); + this.resultsPanel = resultsPanel; + this.addMouseMotionListener(new MouseMotionListener() { + @Override + public void mouseDragged(MouseEvent e) { + if (resultsPanel.getActiveType() == SearchData.Type.DOMAIN) { + e.consume(); + } + } + + @Override + public void mouseMoved(MouseEvent e) { + if (resultsPanel.getActiveType() == SearchData.Type.DOMAIN) { + e.consume(); + } + } + }); } /** @@ -109,10 +129,16 @@ final class ResultsSplitPaneDivider extends javax.swing.JPanel { }// //GEN-END:initComponents private void showButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showButtonActionPerformed + if (resultsPanel.getActiveType() == SearchData.Type.DOMAIN) { + return; + } DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.DetailsVisibleEvent(true)); }//GEN-LAST:event_showButtonActionPerformed private void hideButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_hideButtonActionPerformed + if (resultsPanel.getActiveType() == SearchData.Type.DOMAIN) { + return; + } DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.DetailsVisibleEvent(false)); }//GEN-LAST:event_hideButtonActionPerformed From df409f52b8b99fed91d59a1c946d611cb6d8a519 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Wed, 16 Sep 2020 13:23:10 -0400 Subject: [PATCH 087/130] Changed the default icon from null to the question mark. Also, guava cache does not allow a return of null --- .../discovery/search/DomainSearchThumbnailLoader.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java index 0a6a34bf8c..3a4856338c 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java @@ -35,6 +35,8 @@ import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; +import org.openide.util.ImageUtilities; + /** * Loads a thumbnail for the given request. Thumbnail candidates are JPEG files * that are either TSK_WEB_DOWNLOAD or TSK_WEB_CACHE artifacts. JPEG files are @@ -43,6 +45,8 @@ import org.sleuthkit.datamodel.TskCoreException; * loaded from the DomainSearchArtifactsCache and then further analyzed. */ 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"; @@ -95,7 +99,7 @@ public class DomainSearchThumbnailLoader extends CacheLoader Date: Wed, 16 Sep 2020 13:25:09 -0400 Subject: [PATCH 088/130] Merged in the thumbnail branch --- .../autopsy/discovery/search/DomainSearchThumbnailLoader.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java index 2c39097da4..a02213213f 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java @@ -53,8 +53,6 @@ public class DomainSearchThumbnailLoader extends CacheLoader Date: Wed, 16 Sep 2020 13:29:19 -0400 Subject: [PATCH 089/130] revisions to pie chart --- .../datasourcesummary/ui/TypesPanel.java | 110 ++++++++++++++++-- .../uiutils/PieChartPanel.java | 23 +++- 2 files changed, 120 insertions(+), 13 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java index f01784ca4a..2d51bb6f61 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java @@ -23,22 +23,25 @@ import java.sql.SQLException; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.logging.Level; import java.util.stream.Collectors; import javax.swing.JLabel; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.IngestModuleCheckUtil; import org.sleuthkit.autopsy.datasourcesummary.datamodel.MimeTypeSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.uiutils.AbstractLoadableComponent; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; @@ -115,11 +118,47 @@ class TypesPanel extends BaseDataSourceSummaryPanel { } } + /** + * Data for types pie chart. + */ + private static class TypesPieChartData { + + private final List pieSlices; + private final boolean usefulContent; + + /** + * Main constructor. + * + * @param pieSlices The pie slices. + * @param usefulContent True if this is useful content; false if there + * is 0 mime type information. + */ + public TypesPieChartData(List pieSlices, boolean usefulContent) { + this.pieSlices = pieSlices; + this.usefulContent = usefulContent; + } + + /** + * @return The pie chart data. + */ + public List getPieSlices() { + return pieSlices; + } + + /** + * @return Whether or not the data is usefulContent. + */ + public boolean isUsefulContent() { + return usefulContent; + } + } + private static final long serialVersionUID = 1L; private static final DecimalFormat INTEGER_SIZE_FORMAT = new DecimalFormat("#"); private static final DecimalFormat COMMA_FORMATTER = new DecimalFormat("#,###"); private static final String FILE_TYPE_FACTORY = FileTypeIdModuleFactory.class.getCanonicalName(); private static final String FILE_TYPE_MODULE_NAME = FileTypeIdModuleFactory.getModuleName(); + private static final Logger logger = Logger.getLogger(TypesPanel.class.getName()); // All file type categories. private static final List>> FILE_MIME_TYPE_CATEGORIES = Arrays.asList( @@ -219,7 +258,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel { // file types worker new DataFetchWorker.DataFetchComponents<>( (dataSource) -> getMimeTypeCategoriesModel(mimeTypeData, dataSource), - (result) -> showResultWithModuleCheck(fileMimeTypesChart, result, FILE_TYPE_FACTORY, FILE_TYPE_MODULE_NAME)), + this::showMimeTypeCategories), // allocated files worker new DataFetchWorker.DataFetchComponents<>( (dataSource) -> getStringOrZero(typeData.getCountOfAllocatedFiles(dataSource)), @@ -258,11 +297,11 @@ class TypesPanel extends BaseDataSourceSummaryPanel { * * @return The pie chart items. */ - private List getMimeTypeCategoriesModel(MimeTypeSummary mimeTypeData, DataSource dataSource) + private TypesPieChartData getMimeTypeCategoriesModel(MimeTypeSummary mimeTypeData, DataSource dataSource) throws SQLException, SleuthkitCaseProviderException, TskCoreException { if (dataSource == null) { - return Collections.emptyList(); + return null; } // for each category of file types, get the counts of files @@ -287,20 +326,73 @@ class TypesPanel extends BaseDataSourceSummaryPanel { fileCategoryItems.add(Pair.of(Bundle.TypesPanel_fileMimeTypesChart_other_title(), allRegularFiles - (categoryTotalCount + noMimeTypeCount))); - // check at this point to see if these are all 0, if so we don't have results; return empty list - if (!fileCategoryItems.stream().anyMatch((pair) -> pair.getValue() != null && pair.getValue() > 0)) { - return Collections.emptyList(); - } + // check at this point to see if these are all 0; if so, we don't have useful content. + boolean usefulContent = fileCategoryItems.stream().anyMatch((pair) -> pair.getValue() != null && pair.getValue() > 0); // create entry for not analyzed mime types category fileCategoryItems.add(Pair.of(Bundle.TypesPanel_fileMimeTypesChart_notAnalyzed_title(), noMimeTypeCount)); // create pie chart items to provide to pie chart - return fileCategoryItems.stream() + List items = fileCategoryItems.stream() .filter(keyCount -> keyCount.getRight() != null && keyCount.getRight() > 0) .map(keyCount -> new PieChartItem(keyCount.getLeft(), keyCount.getRight())) .collect(Collectors.toList()); + + return new TypesPieChartData(items, usefulContent); + } + + /** + * Handles properly showing data for the mime type categories pie chart + * accounting for whether there are any files with mime types specified and + * whether or not the current data source has been ingested with the file + * type ingest module. + * + * @param result The result to be shown. + */ + private void showMimeTypeCategories(DataFetchResult result) { + // if result is null check for ingest module and show empty results. + if (result == null) { + showPieResultWithModuleCheck(null); + return; + } + + // if error, show error + if (result.getResultType() == ResultType.ERROR) { + this.fileMimeTypesChart.showDataFetchResult(DataFetchResult.getErrorResult(result.getException())); + return; + } + + // if no useful data, do an ingest module check and show data. + TypesPieChartData data = result.getData(); + if (data == null || !data.isUsefulContent()) { + showPieResultWithModuleCheck(data.getPieSlices()); + return; + } + + this.fileMimeTypesChart.showDataFetchResult(DataFetchResult.getSuccessResult(data.getPieSlices())); + } + + /** + * Shows a message in the fileMimeTypesChart about the data source not being + * ingested with the file type ingest module if the data source has not been + * ingested with that module. Also shows data if present. + * + * @param items The list of items to show. + */ + private void showPieResultWithModuleCheck(List items) { + boolean hasBeenIngested = false; + try { + hasBeenIngested = this.getIngestModuleCheckUtil().isModuleIngested(getDataSource(), FILE_TYPE_FACTORY); + } catch (TskCoreException | SleuthkitCaseProviderException ex) { + logger.log(Level.WARNING, "There was an error fetching whether or not the current data source has been ingested with the file type ingest module.", ex); + } + + if (hasBeenIngested) { + this.fileMimeTypesChart.showDataFetchResult(DataFetchResult.getSuccessResult(items)); + } else { + this.fileMimeTypesChart.showDataWithMessage(items, getDefaultNoIngestMessage(FILE_TYPE_MODULE_NAME)); + } } /** diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/PieChartPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/PieChartPanel.java index 6cde2f074b..4178c2ee63 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/PieChartPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/PieChartPanel.java @@ -33,10 +33,14 @@ import org.jfree.chart.panel.AbstractOverlay; import org.jfree.chart.panel.Overlay; import org.jfree.chart.plot.PiePlot; import org.jfree.data.general.DefaultPieDataset; +import org.openide.util.NbBundle.Messages; /** * A pie chart panel. */ +@Messages({ + "PieChartPanel_noDataLabel=No Data" +}) public class PieChartPanel extends AbstractLoadableComponent> { /** @@ -192,14 +196,25 @@ public class PieChartPanel extends AbstractLoadableComponent data) { this.dataset.clear(); - if (data != null) { + if (data != null && !data.isEmpty()) { for (PieChartPanel.PieChartItem slice : data) { this.dataset.setValue(slice.getLabel(), slice.getValue()); } + } else { + // show a no data label if no data. + this.dataset.setValue(Bundle.PieChartPanel_noDataLabel(), 0); } } - - public void showMessageWithData(String message, List data) { - + + /** + * Shows a message on top of data. + * + * @param data The data. + * @param message The message. + */ + public synchronized void showDataWithMessage(List data, String message) { + setResults(data); + setMessage(true, message); + repaint(); } } From dd6eabc41a398441a7cb4d4a0ac61bfd6481880f Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 16 Sep 2020 13:34:58 -0400 Subject: [PATCH 090/130] bundle updates --- .../autopsy/datasourcesummary/ui/Bundle.properties-MERGED | 2 +- .../org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java | 3 +-- .../autopsy/datasourcesummary/uiutils/Bundle.properties-MERGED | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) 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 1bf1de03b3..ed28d6695b 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -2,7 +2,7 @@ AnalysisPanel_countColumn_title=Count AnalysisPanel_keyColumn_title=Name AnalysisPanel_keywordSearchModuleName=Keyword Search # {0} - module name -BaseDataSourceSummaryPanel_defaultNotIngestMessage=The {0} Ingest Module has not been run on this datasource. +BaseDataSourceSummaryPanel_defaultNotIngestMessage=The {0} ingest module has not been run on this datasource. ContainerPanel.getDataSources.error.text=Failed to get the list of datasources for the current case. ContainerPanel.getDataSources.error.title=Load Failure CTL_DataSourceSummaryAction=Data Source Summary diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java index 2d51bb6f61..e63c1cf068 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java @@ -103,8 +103,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel { private void setValue(String value, boolean italicize) { String formattedKey = StringUtils.isBlank(key) ? "" : key; String formattedValue = StringUtils.isBlank(value) ? "" : value; - String htmlFormattedValue = (italicize) ? String.format("%s", formattedValue) : formattedValue; - label.setText(String.format("%s: %s", formattedKey, htmlFormattedValue)); + label.setText(String.format("%s: %s", formattedKey, formattedValue)); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/Bundle.properties-MERGED index b7e31eace5..c06bc6850a 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/Bundle.properties-MERGED @@ -2,3 +2,4 @@ AbstractLoadableComponent_errorMessage_defaultText=There was an error loading re AbstractLoadableComponent_loadingMessage_defaultText=Loading results... AbstractLoadableComponent_noDataExists_defaultText=No data exists. IngestRunningLabel_defaultMessage=Ingest is currently running. +PieChartPanel_noDataLabel=No Data From dde338fb367503a6a66329728e3838138cf266c8 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 16 Sep 2020 13:35:44 -0400 Subject: [PATCH 091/130] bug fixes --- .../sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java index e63c1cf068..dced9b2491 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java @@ -100,7 +100,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel { this.showResults(null); } - private void setValue(String value, boolean italicize) { + private void setValue(String value) { String formattedKey = StringUtils.isBlank(key) ? "" : key; String formattedValue = StringUtils.isBlank(value) ? "" : value; label.setText(String.format("%s: %s", formattedKey, formattedValue)); @@ -108,12 +108,12 @@ class TypesPanel extends BaseDataSourceSummaryPanel { @Override protected void setMessage(boolean visible, String message) { - setValue(message, true); + setValue(message); } @Override protected void setResults(String data) { - setValue(data, false); + setValue(data); } } From b4945afbb9d347d3b7b3ed87954d3f4741d0282b Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Wed, 16 Sep 2020 14:05:10 -0400 Subject: [PATCH 092/130] Codacy --- .../autopsy/discovery/search/DomainSearchArtifactsCache.java | 2 +- .../autopsy/discovery/search/DomainSearchArtifactsLoader.java | 2 +- .../autopsy/discovery/search/DomainSearchThumbnailCache.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsCache.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsCache.java index 7efc42e219..95bf4aec23 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsCache.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsCache.java @@ -49,7 +49,7 @@ public class DomainSearchArtifactsCache { try { return cache.get(request); } catch (ExecutionException ex) { - throw new DiscoveryException("Error fetching artifacts from cache", ex.getCause()); + throw new DiscoveryException("Error fetching artifacts from cache", ex); } } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsLoader.java index 20772f2c12..ea177efcc9 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsLoader.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsLoader.java @@ -49,7 +49,7 @@ public class DomainSearchArtifactsLoader extends CacheLoader Date: Wed, 16 Sep 2020 14:06:47 -0400 Subject: [PATCH 093/130] bug fix --- .../datasourcesummary/uiutils/PieChartPanel.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/PieChartPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/PieChartPanel.java index 4178c2ee63..466c578b60 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/PieChartPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/PieChartPanel.java @@ -115,6 +115,13 @@ public class PieChartPanel extends AbstractLoadableComponent Date: Wed, 16 Sep 2020 14:13:46 -0400 Subject: [PATCH 094/130] Beef up the artifacts cache size a bit --- .../autopsy/discovery/search/DomainSearchArtifactsCache.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsCache.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsCache.java index 95bf4aec23..d3bb153176 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsCache.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsCache.java @@ -29,7 +29,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact; */ public class DomainSearchArtifactsCache { - private static final int MAXIMUM_CACHE_SIZE = 5; + private static final int MAXIMUM_CACHE_SIZE = 500; private static final LoadingCache> cache = CacheBuilder.newBuilder() .maximumSize(MAXIMUM_CACHE_SIZE) From 54460a041fb7b2553e02bfb5c7a540a60d83af48 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Wed, 16 Sep 2020 15:03:43 -0400 Subject: [PATCH 095/130] Codacy --- .../autopsy/discovery/search/DiscoveryAttributes.java | 3 +++ .../sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java index a7a5e0be07..68b5df4314 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java @@ -582,6 +582,9 @@ public class DiscoveryAttributes { } + /** + * Attribute for grouping/sorting by number of visits. + */ static class NumberOfVisitsAttribute extends AttributeType { @Override diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java index 63ca735702..03427268fa 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java @@ -1110,6 +1110,9 @@ public class DiscoveryKeyUtils { } } + /** + * Key representing the number of visits. + */ static class NumberOfVisitsGroupKey extends GroupKey { private final String displayName; From 743f3d1ad220c32dd281a55d69092bdd87a25aee Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 16 Sep 2020 16:34:08 -0400 Subject: [PATCH 096/130] addressing codacy remarks --- .../sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java | 2 -- .../autopsy/datasourcesummary/uiutils/IngestRunningLabel.java | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java index 7a8d482e4c..540b36fb14 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java @@ -26,11 +26,9 @@ import java.util.Set; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.table.DefaultTableModel; -import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java index 0f6c694ee9..301ad2747d 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java @@ -38,6 +38,7 @@ import org.sleuthkit.autopsy.ingest.IngestManager; }) public class IngestRunningLabel extends JPanel { + private static final long serialVersionUID = 1L; public static final String DEFAULT_MESSAGE = Bundle.IngestRunningLabel_defaultMessage(); private static final URL DEFAULT_ICON = IngestRunningLabel.class.getResource("/org/sleuthkit/autopsy/modules/filetypeid/warning16.png"); @@ -130,7 +131,7 @@ public class IngestRunningLabel extends JPanel { if (showWarningIcon) { jlabel.setIcon(new ImageIcon(DEFAULT_ICON)); } - + setLayout(new BorderLayout()); add(jlabel, BorderLayout.NORTH); From 16ec444a3ae332cc3981e22c0f69e00c03f6ff63 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Wed, 16 Sep 2020 17:01:57 -0400 Subject: [PATCH 097/130] Fixed typo --- .../org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java index 07cf1666a1..52325da82a 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java @@ -841,7 +841,7 @@ final class ResultsPanel extends javax.swing.JPanel { ); Image thumbnail = domainSearch.getThumbnail(request); - domainWrapper.setThumnail(thumbnail); + domainWrapper.setThumbnail(thumbnail); return null; } @@ -850,10 +850,10 @@ final class ResultsPanel extends javax.swing.JPanel { try { get(); } catch (ExecutionException ex) { - domainWrapper.setThumnail(null); + domainWrapper.setThumbnail(null); logger.log(Level.WARNING, "Fatal error getting thumbnail for domain.", ex); } catch (InterruptedException | CancellationException ignored) { - domainWrapper.setThumnail(null); + domainWrapper.setThumbnail(null); //we want to do nothing in response to this since we allow it to be cancelled } domainSummaryViewer.repaint(); From 8f810e4a2f1610bc1eff6eb437371af04f27d613 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Wed, 16 Sep 2020 17:15:18 -0400 Subject: [PATCH 098/130] Unused import --- .../autopsy/discovery/search/DomainSearchThumbnailLoader.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java index a02213213f..2923c35b4e 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java @@ -24,7 +24,6 @@ import java.util.List; import java.util.ArrayList; import java.util.Collections; import org.sleuthkit.autopsy.coreutils.ImageUtils; -import org.openide.util.ImageUtilities; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.AbstractFile; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE; From 59bb61126ba49b76423a959e89a109c91f1ba754 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 16 Sep 2020 17:48:24 -0400 Subject: [PATCH 099/130] Added Thread Dump menu to help menu --- .../autopsy/actions/Bundle.properties-MERGED | 1 + .../autopsy/actions/ThreadDumpAction.java | 156 ++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100755 Core/src/org/sleuthkit/autopsy/actions/ThreadDumpAction.java diff --git a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties-MERGED index a3a13c0cff..507e079cad 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties-MERGED @@ -14,6 +14,7 @@ AddContentTagAction.taggingErr=Tagging Error AddContentTagAction.unableToTag.msg=Unable to tag {0}, not a regular file. # {0} - fileName AddContentTagAction.unableToTag.msg2=Unable to tag {0}. +CTL_DumpThreadAction=Thread Dump CTL_ShowIngestProgressSnapshotAction=Ingest Status Details DeleteBlackboardArtifactTagAction.deleteTag=Remove Selected Tag(s) DeleteBlackboardArtifactTagAction.tagDelErr=Tag Deletion Error diff --git a/Core/src/org/sleuthkit/autopsy/actions/ThreadDumpAction.java b/Core/src/org/sleuthkit/autopsy/actions/ThreadDumpAction.java new file mode 100755 index 0000000000..6e534b45cb --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/actions/ThreadDumpAction.java @@ -0,0 +1,156 @@ +/* + * 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.actions; + +import java.awt.Desktop; +import java.awt.event.ActionListener; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import java.util.stream.Collectors; +import javax.swing.SwingWorker; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.awt.ActionRegistration; +import org.openide.util.HelpCtx; +import org.openide.util.NbBundle.Messages; +import org.openide.util.actions.CallableSystemAction; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; + +/** + * Action class for the Thread Dump help menu item. If there is no case open the + * dump file will be created in PlatformUtil.getLogDirectory() otherwise the + * file will be created in Case.getCurrentCase().getLogDirectoryPath() + */ +@ActionID(category = "Help", id = "org.sleuthkit.autopsy.actions.ThreadDumpAction") +@ActionRegistration(displayName = "#CTL_DumpThreadAction", lazy = false) +@ActionReference(path = "Menu/Help", position = 2000) +@Messages({ + "CTL_DumpThreadAction=Thread Dump" +}) +public final class ThreadDumpAction extends CallableSystemAction implements ActionListener { + + private static final long serialVersionUID = 1L; + private static final Logger logger = Logger.getLogger(ThreadDumpAction.class.getName()); + + private static final DateFormat DATE_FORMAT = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss-SSSS"); + + @Override + public void performAction() { + (new ThreadDumper()).run(); + } + + @Override + public String getName() { + return Bundle.CTL_DumpThreadAction(); + } + + @Override + public HelpCtx getHelpCtx() { + return HelpCtx.DEFAULT_HELP; + } + + /** + * SwingWorker to that will create the thread dump file. Once the file is + * created it will be opened in an external viewer. + */ + private final class ThreadDumper extends SwingWorker { + + @Override + protected File doInBackground() throws Exception { + return createThreadDump(); + } + + @Override + protected void done() { + File dumpFile = null; + try { + dumpFile = get(); + Desktop.getDesktop().open(dumpFile); + } catch (ExecutionException | InterruptedException ex) { + logger.log(Level.SEVERE, "Failure occurred while creating thread dump file", ex); + } catch (IOException ex) { + if (dumpFile != null) { + logger.log(Level.WARNING, "Failed to open thread dump file in external viewer: " + dumpFile.getAbsolutePath(), ex); + } else { + logger.log(Level.SEVERE, "Failed to create thread dump file.", ex); + } + } + } + + /** + * Create the thread dump file. + * + * @throws IOException + */ + private File createThreadDump() throws IOException { + File dumpFile = createFilePath().toFile(); + try (BufferedWriter writer = new BufferedWriter(new FileWriter(dumpFile, true))) { + ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); + ThreadInfo[] threadInfos = threadMXBean.getThreadInfo(threadMXBean.getAllThreadIds(), 100); + for (ThreadInfo threadInfo : threadInfos) { + writer.write(threadInfo.toString()); + writer.write("\n"); + } + + long[] deadlockThreadIds = threadMXBean.findDeadlockedThreads(); + if (deadlockThreadIds != null) { + writer.write("-------------------List of Deadlocked Thread IDs ---------------------"); + String idsList = (Arrays + .stream(deadlockThreadIds) + .boxed() + .collect(Collectors.toList())) + .stream().map(n -> String.valueOf(n)) + .collect(Collectors.joining("-", "{", "}")); + writer.write(idsList); + } + } + + return dumpFile; + } + + /** + * Create the dump file path. + * + * @return Path for dump file. + */ + private Path createFilePath() { + String fileName = "ThreadDump_" + DATE_FORMAT.format(new Date()) + ".txt"; + if (Case.isCaseOpen()) { + return Paths.get(Case.getCurrentCase().getLogDirectoryPath(), fileName); + } + return Paths.get(PlatformUtil.getLogDirectory(), fileName); + } + } + +} From 9ebd871fa8d631dcc02d726271e9d6b4478920e4 Mon Sep 17 00:00:00 2001 From: apriestman Date: Wed, 16 Sep 2020 18:00:23 -0400 Subject: [PATCH 100/130] Updates from feedback --- docs/doxygen-user/command_line_ingest.dox | 2 +- .../images/command_line_ingest_dialog.png | Bin 4550 -> 15326 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/doxygen-user/command_line_ingest.dox b/docs/doxygen-user/command_line_ingest.dox index 431f96865b..137005cdde 100644 --- a/docs/doxygen-user/command_line_ingest.dox +++ b/docs/doxygen-user/command_line_ingest.dox @@ -178,7 +178,7 @@ If you've entered everything correctly, Autopsy will load and you'll see this di \image html command_line_ingest_dialog.png -If you instead see the normal case open dialog, it most likely means that your command line is malformed. Verify that there are no typos and that you have the appropriate parameters for the operation(s) you're attempting. +If you entered something incorrectly you will likely see an error in the output. You may also see the normal case open dialog if your combination of commands and parameters was invalid. In either case you'll want to compare what you ran with the descriptions and examples above to try to find the error. If everything works correctly, you'll see a log of the processing being done and Autopsy will close when finished. diff --git a/docs/doxygen-user/images/command_line_ingest_dialog.png b/docs/doxygen-user/images/command_line_ingest_dialog.png index 51caccb30816e79f3b892b8f85c7bd076846fee7..5b4a050140d1d2184305d871a87ce371a74191ff 100644 GIT binary patch literal 15326 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 V5V6uQSd$DFXmXP=UZEfi{TJRLEsX#G literal 4550 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 A=>Px# From 843a9ebf3bb3b54ac109730e47fd898eb312744c Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 16 Sep 2020 19:49:37 -0400 Subject: [PATCH 101/130] spelling issue fix --- .../datasourcesummary/ui/BaseDataSourceSummaryPanel.java | 2 +- .../autopsy/datasourcesummary/ui/Bundle.properties-MERGED | 4 +--- .../autopsy/datasourcesummary/ui/ContainerPanel.java | 3 --- 3 files changed, 2 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 e395638019..a97682391d 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java @@ -345,7 +345,7 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { */ @Messages({ "# {0} - module name", - "BaseDataSourceSummaryPanel_defaultNotIngestMessage=The {0} ingest module has not been run on this datasource." + "BaseDataSourceSummaryPanel_defaultNotIngestMessage=The {0} ingest module has not been run on this data source." }) protected String getDefaultNoIngestMessage(String moduleName) { return Bundle.BaseDataSourceSummaryPanel_defaultNotIngestMessage(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 ed28d6695b..9a48089e5d 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -2,9 +2,7 @@ AnalysisPanel_countColumn_title=Count AnalysisPanel_keyColumn_title=Name AnalysisPanel_keywordSearchModuleName=Keyword Search # {0} - module name -BaseDataSourceSummaryPanel_defaultNotIngestMessage=The {0} ingest module has not been run on this datasource. -ContainerPanel.getDataSources.error.text=Failed to get the list of datasources for the current case. -ContainerPanel.getDataSources.error.title=Load Failure +BaseDataSourceSummaryPanel_defaultNotIngestMessage=The {0} ingest module has not been run on this data source. CTL_DataSourceSummaryAction=Data Source Summary DataSourceSummaryDialog.closeButton.text=Close ContainerPanel.displayNameLabel.text=Display Name: diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java index 540b36fb14..d638524471 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java @@ -26,7 +26,6 @@ import java.util.Set; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.table.DefaultTableModel; -import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType; @@ -112,8 +111,6 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { /** * Creates new form ContainerPanel. */ - @Messages({"ContainerPanel.getDataSources.error.text=Failed to get the list of datasources for the current case.", - "ContainerPanel.getDataSources.error.title=Load Failure"}) ContainerPanel(ContainerSummary containerSummary) { super(containerSummary, CONTAINER_UPDATES); From 4b4072a87167ae6b18054bd50c1bbb3a627af604 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 16 Sep 2020 20:38:36 -0400 Subject: [PATCH 102/130] NPE fixed --- .../autopsy/datasourcesummary/ui/TypesPanel.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java index dced9b2491..4d9271d712 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java @@ -362,14 +362,17 @@ class TypesPanel extends BaseDataSourceSummaryPanel { return; } - // if no useful data, do an ingest module check and show data. TypesPieChartData data = result.getData(); - if (data == null || !data.isUsefulContent()) { + if (data == null) { + // if no data, do an ingest module check with empty results + showPieResultWithModuleCheck(null); + } else if (!data.isUsefulContent()) { + // if no useful data, do an ingest module check and show data showPieResultWithModuleCheck(data.getPieSlices()); - return; + } else { + // otherwise, show the data + this.fileMimeTypesChart.showDataFetchResult(DataFetchResult.getSuccessResult(data.getPieSlices())); } - - this.fileMimeTypesChart.showDataFetchResult(DataFetchResult.getSuccessResult(data.getPieSlices())); } /** From d3ca618f2f8bfffa903a05a4b2d45ba6e20d8657 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Thu, 17 Sep 2020 09:56:43 -0400 Subject: [PATCH 103/130] Switched menu items around per Richards request --- Core/src/org/sleuthkit/autopsy/actions/OpenLogFolderAction.java | 2 +- Core/src/org/sleuthkit/autopsy/actions/ThreadDumpAction.java | 2 +- .../org/sleuthkit/autopsy/corecomponents/AboutWindowAction.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/actions/OpenLogFolderAction.java b/Core/src/org/sleuthkit/autopsy/actions/OpenLogFolderAction.java index fb178c797d..92b04140c3 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/OpenLogFolderAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/OpenLogFolderAction.java @@ -44,7 +44,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; * This action should only be invoked in the event dispatch thread (EDT). */ @ActionRegistration(displayName = "#CTL_OpenLogFolder", iconInMenu = true) -@ActionReference(path = "Menu/Help", position = 1750) +@ActionReference(path = "Menu/Help", position = 2000) @ActionID(id = "org.sleuthkit.autopsy.actions.OpenLogFolderAction", category = "Help") public final class OpenLogFolderAction implements ActionListener { diff --git a/Core/src/org/sleuthkit/autopsy/actions/ThreadDumpAction.java b/Core/src/org/sleuthkit/autopsy/actions/ThreadDumpAction.java index 6e534b45cb..d74511996c 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/ThreadDumpAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/ThreadDumpAction.java @@ -54,7 +54,7 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil; */ @ActionID(category = "Help", id = "org.sleuthkit.autopsy.actions.ThreadDumpAction") @ActionRegistration(displayName = "#CTL_DumpThreadAction", lazy = false) -@ActionReference(path = "Menu/Help", position = 2000) +@ActionReference(path = "Menu/Help", position = 1750) @Messages({ "CTL_DumpThreadAction=Thread Dump" }) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AboutWindowAction.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AboutWindowAction.java index db0710ee2d..00f0e7217a 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AboutWindowAction.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AboutWindowAction.java @@ -33,7 +33,7 @@ import org.openide.util.NbBundle; */ @ActionID(id = "org.sleuthkit.autopsy.corecomponents.AboutWindowAction", category = "Help") @ActionRegistration(displayName = "#CTL_CustomAboutAction", iconInMenu = true, lazy = false) -@ActionReference(path = "Menu/Help", position = 3000) +@ActionReference(path = "Menu/Help", position = 3000, separatorBefore = 2999) public class AboutWindowAction extends AboutAction { @Override From 176e9df7601eac56f0e0132ed4cfd93239e0e30d Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 17 Sep 2020 11:09:59 -0400 Subject: [PATCH 104/130] Added an aggregate function to group column access --- .../autopsy/discovery/search/DomainSearchCacheLoader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java index 99101cf053..a98d2e06a9 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java @@ -144,7 +144,7 @@ class DomainSearchCacheLoader extends CacheLoader Date: Thu, 17 Sep 2020 12:27:06 -0400 Subject: [PATCH 105/130] Clean up naming, formatting, and comments for Discovery package --- .../discovery/search/AbstractFilter.java | 3 +- .../discovery/search/DiscoveryAttributes.java | 106 ++++++-- .../discovery/search/DiscoveryEventUtils.java | 76 +++--- .../discovery/search/DiscoveryException.java | 2 +- .../discovery/search/DiscoveryKeyUtils.java | 239 +++++++++++++----- .../discovery/search/DomainSearch.java | 62 +++-- .../search/DomainSearchArtifactsCache.java | 5 +- .../search/DomainSearchArtifactsRequest.java | 24 +- .../discovery/search/DomainSearchCache.java | 17 +- .../search/DomainSearchCacheLoader.java | 196 +++++++------- .../search/DomainSearchThumbnailCache.java | 15 +- .../search/DomainSearchThumbnailLoader.java | 46 ++-- .../search/DomainSearchThumbnailRequest.java | 35 ++- .../autopsy/discovery/search/Group.java | 36 +-- .../discovery/search/ResultDomain.java | 48 +++- .../discovery/search/ResultsSorter.java | 84 +++--- .../autopsy/discovery/search/SearchData.java | 90 +++++-- .../discovery/search/SearchFiltering.java | 170 ++++++++----- .../discovery/search/SearchResults.java | 4 +- .../discovery/search/SummaryHelpers.java | 7 + .../ui/AbstractDiscoveryFilterPanel.java | 7 +- .../discovery/ui/AbstractFiltersPanel.java | 29 ++- .../autopsy/discovery/ui/DiscoveryDialog.form | 3 - .../autopsy/discovery/ui/DiscoveryDialog.java | 1 - .../discovery/ui/DiscoveryTopComponent.java | 4 +- .../discovery/ui/DomainFilterPanel.java | 1 - .../autopsy/discovery/ui/GroupListPanel.java | 2 +- .../discovery/ui/OpenDiscoveryAction.java | 5 +- .../autopsy/discovery/ui/ResultsPanel.java | 8 +- 29 files changed, 881 insertions(+), 444 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java b/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java index cb44c29415..bb2e258f2e 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java @@ -29,8 +29,7 @@ import org.sleuthkit.datamodel.SleuthkitCase; public abstract class AbstractFilter { /** - * Returns part of a query on the table that can be AND-ed with - * other pieces + * Returns part of a query on the table that can be AND-ed with other pieces * * @return the SQL query or an empty string if there is no SQL query for * this filter. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java index 68b5df4314..4acb503485 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java @@ -61,20 +61,20 @@ public class DiscoveryAttributes { public abstract static class AttributeType { /** - * For a given file, return the key for the group it belongs to for this - * attribute type. + * For a given Result, return the key for the group it belongs to for + * this attribute type. * - * @param file the result file to be grouped + * @param result The result to be grouped. * - * @return the key for the group this file goes in + * @return The key for the group this result goes in. */ - public abstract DiscoveryKeyUtils.GroupKey getGroupKey(Result file); + public abstract DiscoveryKeyUtils.GroupKey getGroupKey(Result result); /** * Add any extra data to the ResultFile object from this attribute. * - * @param files The list of results to enhance - * @param caseDb The case database + * @param files The list of results to enhance. + * @param caseDb The case database. * @param centralRepoDb The central repository database. Can be null if * not needed. * @@ -86,7 +86,7 @@ public class DiscoveryAttributes { } /** - * Attribute for grouping/sorting by file size + * Attribute for grouping/sorting by file size. */ public static class FileSizeAttribute extends AttributeType { @@ -97,7 +97,7 @@ public class DiscoveryAttributes { } /** - * Attribute for grouping/sorting by parent path + * Attribute for grouping/sorting by parent path. */ public static class ParentPathAttribute extends AttributeType { @@ -108,7 +108,7 @@ public class DiscoveryAttributes { } /** - * Default attribute used to make one group + * Default attribute used to make one group. */ static class NoGroupingAttribute extends AttributeType { @@ -119,7 +119,7 @@ public class DiscoveryAttributes { } /** - * Attribute for grouping/sorting by data source + * Attribute for grouping/sorting by data source. */ static class DataSourceAttribute extends AttributeType { @@ -130,7 +130,7 @@ public class DiscoveryAttributes { } /** - * Attribute for grouping/sorting by file type + * Attribute for grouping/sorting by file type. */ static class FileTypeAttribute extends AttributeType { @@ -141,7 +141,7 @@ public class DiscoveryAttributes { } /** - * Attribute for grouping/sorting by keyword lists + * Attribute for grouping/sorting by keyword lists. */ static class KeywordListAttribute extends AttributeType { @@ -179,7 +179,7 @@ public class DiscoveryAttributes { /** * Create the callback. * - * @param resultFiles List of files to add keyword list names to + * @param resultFiles List of files to add keyword list names to. */ SetKeywordListNamesCallback(List resultFiles) { this.resultFiles = resultFiles; @@ -217,7 +217,7 @@ public class DiscoveryAttributes { } /** - * Attribute for grouping/sorting by frequency in the central repository + * Attribute for grouping/sorting by frequency in the central repository. */ static class FrequencyAttribute extends AttributeType { @@ -294,11 +294,18 @@ public class DiscoveryAttributes { } } + /** + * Query to get the frequency of a domain. + * + * @param domainsToQuery List of domains to check the frequency of. + * @param centralRepository The central repository to query. + * + * @throws DiscoveryException + */ private static void queryDomainFrequency(List domainsToQuery, CentralRepository centralRepository) throws DiscoveryException { if (domainsToQuery.isEmpty()) { return; } - try { final Map> resultDomainTable = new HashMap<>(); final StringJoiner joiner = new StringJoiner(", "); @@ -334,11 +341,19 @@ public class DiscoveryAttributes { } } + /** + * Callback to get the frequency of domain. + */ private static class DomainFrequencyCallback implements InstanceTableCallback { private final Map> domainLookup; private SQLException sqlCause; + /** + * Construct a new DomainFrequencyCallback. + * + * @param domainLookup The map to get domain from. + */ private DomainFrequencyCallback(Map> domainLookup) { this.domainLookup = domainLookup; } @@ -360,6 +375,11 @@ public class DiscoveryAttributes { } } + /** + * Get the SQL exception if one occurred during this callback. + * + * @return + */ SQLException getCause() { return this.sqlCause; } @@ -373,6 +393,11 @@ public class DiscoveryAttributes { private final List files; + /** + * Construct a new FrequencyCallback. + * + * @param resultFiles List of files to add hash set names to. + */ private FrequencyCallback(List files) { this.files = new ArrayList<>(files); } @@ -404,7 +429,7 @@ public class DiscoveryAttributes { } /** - * Attribute for grouping/sorting by hash set lists + * Attribute for grouping/sorting by hash set lists. */ static class HashHitsAttribute extends AttributeType { @@ -444,7 +469,7 @@ public class DiscoveryAttributes { /** * Create the callback. * - * @param resultFiles List of files to add hash set names to + * @param resultFiles List of files to add hash set names to. */ HashSetNamesCallback(List results) { this.results = results; @@ -482,7 +507,7 @@ public class DiscoveryAttributes { } /** - * Attribute for grouping/sorting by interesting item set lists + * Attribute for grouping/sorting by interesting item set lists. */ static class InterestingItemAttribute extends AttributeType { @@ -521,7 +546,7 @@ public class DiscoveryAttributes { * Create the callback. * * @param resultFiles List of files to add interesting file set - * names to + * names to. */ InterestingFileSetNamesCallback(List results) { this.results = results; @@ -581,12 +606,12 @@ public class DiscoveryAttributes { } } - + /** * Attribute for grouping/sorting by number of visits. */ static class NumberOfVisitsAttribute extends AttributeType { - + @Override public DiscoveryKeyUtils.GroupKey getGroupKey(Result result) { return new DiscoveryKeyUtils.NumberOfVisitsGroupKey(result); @@ -594,7 +619,7 @@ public class DiscoveryAttributes { } /** - * Attribute for grouping/sorting by objects detected + * Attribute for grouping/sorting by objects detected. */ static class ObjectDetectedAttribute extends AttributeType { @@ -632,7 +657,7 @@ public class DiscoveryAttributes { /** * Create the callback. * - * @param resultFiles List of files to add object detected names to + * @param resultFiles List of files to add object detected names to. */ ObjectDetectedNamesCallback(List results) { this.results = results; @@ -670,7 +695,7 @@ public class DiscoveryAttributes { } /** - * Attribute for grouping/sorting by tag name + * Attribute for grouping/sorting by tag name. */ static class FileTagAttribute extends AttributeType { @@ -737,6 +762,14 @@ public class DiscoveryAttributes { private final AttributeType attributeType; private final String displayName; + /** + * Construct a new GroupingAttributeType enum value. + * + * @param attributeType The type of attribute this enum value was + * constructed for. + * @param displayName The display name for this grouping attribute + * type. + */ GroupingAttributeType(AttributeType attributeType, String displayName) { this.attributeType = attributeType; this.displayName = displayName; @@ -747,6 +780,11 @@ public class DiscoveryAttributes { return displayName; } + /** + * Get the type of attribute this enum value was constructed for. + * + * @return The type of attribute this enum value was constructed for. + */ public AttributeType getAttributeType() { return attributeType; } @@ -774,8 +812,9 @@ public class DiscoveryAttributes { * Computes the CR frequency of all the given hashes and updates the list of * files. * - * @param hashesToLookUp Hashes to find the frequency of - * @param currentFiles List of files to update with frequencies + * @param hashesToLookUp Hashes to find the frequency of. + * @param currentFiles List of files to update with frequencies. + * @param centralRepoDb The central repository being used. */ private static void computeFrequency(Set hashesToLookUp, List currentFiles, CentralRepository centralRepoDb) { @@ -804,6 +843,19 @@ public class DiscoveryAttributes { } + /** + * Private helper method to create a set name clause to be used in queries. + * + * @param results The list of results to create the set name clause + * for. + * @param artifactTypeID The Blackboard Artifact type ID for the artifact + * type. + * @param setNameAttrID The set name attribute id. + * + * @return The String to use as a set name clause in queries. + * + * @throws DiscoveryException + */ private static String createSetNameClause(List results, int artifactTypeID, int setNameAttrID) throws DiscoveryException { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java index 88ff2efc38..67c69904fa 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java @@ -57,19 +57,18 @@ public final class DiscoveryEventUtils { private final Type type; /** - * Construct a new SearchStartedEvent + * Construct a new SearchStartedEvent. * - * @param type The type of file the search event is for. + * @param type The type of result the search event is for. */ public SearchStartedEvent(Type type) { this.type = type; } - /** - * Get the type of file the search is being performed for. + * Get the type of result the search is being performed for. * - * @return The type of files being searched for. + * @return The type of results being searched for. */ public Type getType() { return type; @@ -105,7 +104,9 @@ public final class DiscoveryEventUtils { } /** - * @return the instances + * Get the list of AbstractFiles for the instances list. + * + * @return The list of AbstractFiles for the instances list. */ public List getInstances() { return Collections.unmodifiableList(instances); @@ -121,7 +122,7 @@ public final class DiscoveryEventUtils { private final List searchFilters; private final DiscoveryAttributes.AttributeType groupingAttribute; private final Group.GroupSortingAlgorithm groupSort; - private final ResultsSorter.SortingMethod fileSortMethod; + private final ResultsSorter.SortingMethod sortMethod; /** * Construct a new SearchCompleteEvent, @@ -132,16 +133,16 @@ public final class DiscoveryEventUtils { * search. * @param groupingAttribute The grouping attribute used by the search. * @param groupSort The sorting algorithm used for groups. - * @param fileSortMethod The sorting method used for files. + * @param sortMethod The sorting method used for results. */ public SearchCompleteEvent(Map groupMap, List searchfilters, DiscoveryAttributes.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, - ResultsSorter.SortingMethod fileSortMethod) { + ResultsSorter.SortingMethod sortMethod) { this.groupMap = groupMap; this.searchFilters = searchfilters; this.groupingAttribute = groupingAttribute; this.groupSort = groupSort; - this.fileSortMethod = fileSortMethod; + this.sortMethod = sortMethod; } /** @@ -154,7 +155,7 @@ public final class DiscoveryEventUtils { } /** - * Get the file filters used by the search. + * Get the filters used by the search. * * @return The search filters which were used by the search. */ @@ -181,12 +182,12 @@ public final class DiscoveryEventUtils { } /** - * Get the sorting method used for files. + * Get the sorting method used for results. * - * @return The sorting method used for files. + * @return The sorting method used for results. */ - public ResultsSorter.SortingMethod getFileSort() { - return fileSortMethod; + public ResultsSorter.SortingMethod getResultSort() { + return sortMethod; } } @@ -204,9 +205,9 @@ public final class DiscoveryEventUtils { /** * Construct a new PageRetrievedEvent. * - * @param resultType The type of files which exist in the page. + * @param resultType The type of results which exist in the page. * @param page The number of the page which was retrieved. - * @param results The list of files in the page retrieved. + * @param results The list of results in the page retrieved. */ public PageRetrievedEvent(Type resultType, int page, List results) { this.results = results; @@ -215,9 +216,9 @@ public final class DiscoveryEventUtils { } /** - * Get the list of files in the page retrieved. + * Get the list of results in the page retrieved. * - * @return The list of files in the page retrieved. + * @return The list of results in the page retrieved. */ public List getSearchResults() { return Collections.unmodifiableList(results); @@ -233,9 +234,9 @@ public final class DiscoveryEventUtils { } /** - * Get the type of files which exist in the page. + * Get the type of results which exist in the page. * - * @return The type of files which exist in the page. + * @return The type of results which exist in the page. */ public Type getType() { return resultType; @@ -256,7 +257,7 @@ public final class DiscoveryEventUtils { } /** - * Event to signal that a search has been cancelled + * Event to signal that a search has been cancelled. */ public static final class SearchCancelledEvent { @@ -280,7 +281,7 @@ public final class DiscoveryEventUtils { private final List searchfilters; private final DiscoveryAttributes.AttributeType groupingAttribute; private final Group.GroupSortingAlgorithm groupSort; - private final ResultsSorter.SortingMethod fileSortMethod; + private final ResultsSorter.SortingMethod sortMethod; /** * Construct a new GroupSelectedEvent. @@ -289,29 +290,30 @@ public final class DiscoveryEventUtils { * search. * @param groupingAttribute The grouping attribute used by the search. * @param groupSort The sorting algorithm used for groups. - * @param fileSortMethod The sorting method used for files. + * @param sortMethod The sorting method used for results. * @param groupKey The key associated with the group which was * selected. - * @param groupSize The number of files in the group which was + * @param groupSize The number of results in the group which was * selected. - * @param resultType The type of files which exist in the group. + * @param resultType The type of results which exist in the + * group. */ public GroupSelectedEvent(List searchfilters, DiscoveryAttributes.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, - ResultsSorter.SortingMethod fileSortMethod, GroupKey groupKey, int groupSize, Type resultType) { + ResultsSorter.SortingMethod sortMethod, GroupKey groupKey, int groupSize, Type resultType) { this.searchfilters = searchfilters; this.groupingAttribute = groupingAttribute; this.groupSort = groupSort; - this.fileSortMethod = fileSortMethod; + this.sortMethod = sortMethod; this.groupKey = groupKey; this.groupSize = groupSize; this.resultType = resultType; } /** - * Get the type of files which exist in the group. + * Get the type of results which exist in the group. * - * @return The type of files which exist in the group. + * @return The type of results which exist in the group. */ public Type getResultType() { return resultType; @@ -329,9 +331,9 @@ public final class DiscoveryEventUtils { } /** - * Get the number of files in the group which was selected. + * Get the number of results in the group which was selected. * - * @return The number of files in the group which was selected. + * @return The number of results in the group which was selected. */ public int getGroupSize() { return groupSize; @@ -347,16 +349,16 @@ public final class DiscoveryEventUtils { } /** - * Get the sorting method used for files in the group. + * Get the sorting method used for results in the group. * - * @return The sorting method used for files. + * @return The sorting method used for results. */ - public ResultsSorter.SortingMethod getFileSort() { - return fileSortMethod; + public ResultsSorter.SortingMethod getResultSort() { + return sortMethod; } /** - * Get the file filters which were used by the search + * Get the result filters which were used by the search. * * @return The search filters which were used by the search. */ diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryException.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryException.java index 8616351c21..13a4f87fa0 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryException.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryException.java @@ -19,7 +19,7 @@ package org.sleuthkit.autopsy.discovery.search; /** - * Exception type used for FileSearch. + * Exception type used for Discovery search. */ final public class DiscoveryException extends Exception { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java index 03427268fa..9fe4fbf946 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java @@ -49,7 +49,7 @@ public class DiscoveryKeyUtils { private final String keyString; private final Group.GroupSortingAlgorithm groupSortingType; private final DiscoveryAttributes.AttributeType groupAttributeType; - private final ResultsSorter.SortingMethod fileSortingMethod; + private final ResultsSorter.SortingMethod sortingMethod; private final List filters; private final SleuthkitCase sleuthkitCase; private final CentralRepository centralRepository; @@ -58,21 +58,21 @@ public class DiscoveryKeyUtils { * Construct a new SearchKey with all information that defines a search. * * @param userName The name of the user performing the search. - * @param filters The FileFilters being used for the search. + * @param filters The Filters being used for the search. * @param groupAttributeType The AttributeType to group by. * @param groupSortingType The algorithm to sort the groups by. - * @param fileSortingMethod The method to sort the files by. + * @param sortingMethod The method to sort the results by. * @param sleuthkitCase The SleuthkitCase being searched. * @param centralRepository The Central Repository being searched. */ SearchKey(String userName, List filters, DiscoveryAttributes.AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, - ResultsSorter.SortingMethod fileSortingMethod, + ResultsSorter.SortingMethod sortingMethod, SleuthkitCase sleuthkitCase, CentralRepository centralRepository) { this.groupAttributeType = groupAttributeType; this.groupSortingType = groupSortingType; - this.fileSortingMethod = fileSortingMethod; + this.sortingMethod = sortingMethod; this.filters = filters; StringBuilder searchStringBuilder = new StringBuilder(); @@ -80,7 +80,7 @@ public class DiscoveryKeyUtils { for (AbstractFilter filter : filters) { searchStringBuilder.append(filter.toString()); } - searchStringBuilder.append(groupAttributeType).append(groupSortingType).append(fileSortingMethod); + searchStringBuilder.append(groupAttributeType).append(groupSortingType).append(sortingMethod); keyString = searchStringBuilder.toString(); this.sleuthkitCase = sleuthkitCase; this.centralRepository = centralRepository; @@ -89,13 +89,19 @@ public class DiscoveryKeyUtils { /** * Construct a SearchKey without a SleuthkitCase or CentralRepositry * instance. + * + * @param userName The name of the user performing the search. + * @param filters The Filters being used for the search. + * @param groupAttributeType The AttributeType to group by. + * @param groupSortingType The algorithm to sort the groups by. + * @param sortingMethod The method to sort the results by. */ SearchKey(String userName, List filters, DiscoveryAttributes.AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, - ResultsSorter.SortingMethod fileSortingMethod) { + ResultsSorter.SortingMethod sortingMethod) { this(userName, filters, groupAttributeType, groupSortingType, - fileSortingMethod, null, null); + sortingMethod, null, null); } @Override @@ -166,18 +172,28 @@ public class DiscoveryKeyUtils { } /** - * Get the fileSorting + * Get the SortingMethod for this key. * - * @return + * @return The SortingMethod for this key. */ ResultsSorter.SortingMethod getFileSortingMethod() { - return fileSortingMethod; + return sortingMethod; } + /** + * Get the case database for this key. + * + * @return The case database for this key. + */ SleuthkitCase getSleuthkitCase() { return this.sleuthkitCase; } + /** + * Get the central repository for this key. + * + * @return The central repository for this key. + */ CentralRepository getCentralRepository() { return this.centralRepository; } @@ -199,7 +215,7 @@ public class DiscoveryKeyUtils { /** * Subclasses must implement equals(). * - * @param otherKey + * @param otherKey The GroupKey to compare to this key. * * @return true if the keys are equal, false otherwise */ @@ -209,7 +225,7 @@ public class DiscoveryKeyUtils { /** * Subclasses must implement hashCode(). * - * @return the hash code + * @return The hash code for the GroupKey. */ @Override abstract public int hashCode(); @@ -219,9 +235,9 @@ public class DiscoveryKeyUtils { * case where two different GroupKey subclasses are compared against * each other. Use a lexicographic comparison on the class names. * - * @param otherGroupKey The other group key + * @param otherGroupKey The other group key. * - * @return result of alphabetical comparison on the class name + * @return Result of alphabetical comparison on the class name. */ int compareClassNames(GroupKey otherGroupKey) { return this.getClass().getName().compareTo(otherGroupKey.getClass().getName()); @@ -234,12 +250,17 @@ public class DiscoveryKeyUtils { } /** - * Key representing a file size group + * Key representing a file size group. */ static class FileSizeGroupKey extends GroupKey { private final SearchData.FileSize fileSize; + /** + * Construct a new FileSizeGroupKey. + * + * @param file The file to create the group key for. + */ FileSizeGroupKey(Result file) { ResultFile resultFile = (ResultFile) file; if (resultFile.getFileType() == SearchData.Type.VIDEO) { @@ -284,7 +305,9 @@ public class DiscoveryKeyUtils { } /** - * @return the fileSize + * The size of the file. + * + * @return The size of the file. */ SearchData.FileSize getFileSize() { return fileSize; @@ -292,12 +315,17 @@ public class DiscoveryKeyUtils { } /** - * Key representing a file type group + * Key representing a file type group. */ static class FileTypeGroupKey extends GroupKey { private final SearchData.Type fileType; + /** + * Construct a new FileTypeGroupKey. + * + * @param file The file to create the group key for. + */ FileTypeGroupKey(Result file) { fileType = ((ResultFile) file).getFileType(); } @@ -337,7 +365,9 @@ public class DiscoveryKeyUtils { } /** - * @return the fileType + * Get the type of file the group exists for. + * + * @return The type of file the group exists for. */ SearchData.Type getFileType() { return fileType; @@ -345,18 +375,22 @@ public class DiscoveryKeyUtils { } /** - * Key representing a keyword list group + * Key representing a keyword list group. */ static class KeywordListGroupKey extends GroupKey { private final List keywordListNames; private final String keywordListNamesString; + /** + * Construct a new KeywordListGroupKey. + * + * @param file The file to create the group key for. + */ @NbBundle.Messages({ "DiscoveryKeyUtils.KeywordListGroupKey.noKeywords=None"}) KeywordListGroupKey(ResultFile file) { keywordListNames = file.getKeywordListNames(); - if (keywordListNames.isEmpty()) { keywordListNamesString = Bundle.DiscoveryKeyUtils_KeywordListGroupKey_noKeywords(); } else { @@ -411,14 +445,20 @@ public class DiscoveryKeyUtils { } /** - * @return the keywordListNames + * Get the list of keywords this group is for. + * + * @return The list of keywords this group is for. */ List getKeywordListNames() { return Collections.unmodifiableList(keywordListNames); } /** - * @return the keywordListNamesString + * Get the string which represents the keyword names represented by this + * group key. + * + * @return The string which represents the keyword names represented by + * this group key. */ String getKeywordListNamesString() { return keywordListNamesString; @@ -426,13 +466,18 @@ public class DiscoveryKeyUtils { } /** - * Key representing a file tag group + * Key representing a file tag group. */ static class FileTagGroupKey extends GroupKey { private final List tagNames; private final String tagNamesString; + /** + * Construct a new FileTagGroupKey. + * + * @param file The file to create the group key for. + */ @NbBundle.Messages({ "DiscoveryKeyUtils.FileTagGroupKey.noSets=None"}) FileTagGroupKey(ResultFile file) { @@ -477,11 +522,9 @@ public class DiscoveryKeyUtils { if (otherKey == this) { return true; } - if (!(otherKey instanceof FileTagGroupKey)) { return false; } - FileTagGroupKey otherFileTagGroupKey = (FileTagGroupKey) otherKey; return getTagNamesString().equals(otherFileTagGroupKey.getTagNamesString()); } @@ -492,14 +535,20 @@ public class DiscoveryKeyUtils { } /** - * @return the tagNames + * Get the list of tag names which are represented by this group. + * + * @return The list of tag names which are represented by this group. */ List getTagNames() { return Collections.unmodifiableList(tagNames); } /** - * @return the tagNamesString + * Get the String representation of the tags which are represented by + * this group. + * + * @return The String representation of the tags which are represented + * by this group. */ String getTagNamesString() { return tagNamesString; @@ -507,13 +556,18 @@ public class DiscoveryKeyUtils { } /** - * Key representing a parent path group + * Key representing a parent path group. */ static class ParentPathGroupKey extends GroupKey { private String parentPath; private Long parentID; + /** + * Construct a new ParentPathGroupKey. + * + * @param file The file to create the group key for. + */ ParentPathGroupKey(ResultFile file) { Content parent; try { @@ -600,14 +654,18 @@ public class DiscoveryKeyUtils { } /** - * @return the parentPath + * Get the parent path this group is for. + * + * @return The parent path this group is for as a String. */ String getParentPath() { return parentPath; } /** - * @return the parentID + * Get the object ID of the parent object. + * + * @return The object ID of the parent object. */ Long getParentID() { return parentID; @@ -615,13 +673,18 @@ public class DiscoveryKeyUtils { } /** - * Key representing a data source group + * Key representing a data source group. */ static class DataSourceGroupKey extends GroupKey { private final long dataSourceID; private String displayName; + /** + * Construct a new DataSourceGroupKey. + * + * @param result The Result to create the group key for. + */ @NbBundle.Messages({ "# {0} - Data source name", "# {1} - Data source ID", @@ -676,7 +739,9 @@ public class DiscoveryKeyUtils { } /** - * @return the dataSourceID + * Get the object ID of the data source. + * + * @return The object ID of the data source. */ long getDataSourceID() { return dataSourceID; @@ -689,6 +754,9 @@ public class DiscoveryKeyUtils { */ static class NoGroupingGroupKey extends GroupKey { + /** + * Constructor for dummy group which puts all files together. + */ NoGroupingGroupKey() { // Nothing to save - all files will get the same GroupKey } @@ -726,14 +794,19 @@ public class DiscoveryKeyUtils { } /** - * Key representing a central repository frequency group + * Key representing a central repository frequency group. */ static class FrequencyGroupKey extends GroupKey { private final SearchData.Frequency frequency; - FrequencyGroupKey(Result file) { - frequency = file.getFrequency(); + /** + * Construct a new FrequencyGroupKey. + * + * @param result The Result to create the group key for. + */ + FrequencyGroupKey(Result result) { + frequency = result.getFrequency(); } @Override @@ -771,7 +844,9 @@ public class DiscoveryKeyUtils { } /** - * @return the frequency + * Get the frequency which the group is for. + * + * @return The frequency which the group is for. */ SearchData.Frequency getFrequency() { return frequency; @@ -779,13 +854,18 @@ public class DiscoveryKeyUtils { } /** - * Key representing a hash hits group + * Key representing a hash hits group. */ static class HashHitsGroupKey extends GroupKey { private final List hashSetNames; private final String hashSetNamesString; + /** + * Construct a new HashHitsGroupKey. + * + * @param file The file to create the group key for. + */ @NbBundle.Messages({ "DiscoveryKeyUtils.HashHitsGroupKey.noHashHits=None"}) HashHitsGroupKey(ResultFile file) { @@ -845,14 +925,18 @@ public class DiscoveryKeyUtils { } /** - * @return the hashSetNames + * Get the list of hash set names the group is for. + * + * @return The list of hash set names the group is for. */ List getHashSetNames() { return Collections.unmodifiableList(hashSetNames); } /** - * @return the hashSetNamesString + * Get the String representation of the list of hash set names. + * + * @return The String representation of the list of hash set names. */ String getHashSetNamesString() { return hashSetNamesString; @@ -860,13 +944,18 @@ public class DiscoveryKeyUtils { } /** - * Key representing a interesting item set group + * Key representing a interesting item set group. */ static class InterestingItemGroupKey extends GroupKey { private final List interestingItemSetNames; private final String interestingItemSetNamesString; + /** + * Construct a new InterestingItemGroupKey. + * + * @param file The file to create the group key for. + */ @NbBundle.Messages({ "DiscoveryKeyUtils.InterestingItemGroupKey.noSets=None"}) InterestingItemGroupKey(ResultFile file) { @@ -926,14 +1015,20 @@ public class DiscoveryKeyUtils { } /** - * @return the interestingItemSetNames + * Get the list of interesting item set names the group is for. + * + * @return The list of interesting item set names the group is for. */ List getInterestingItemSetNames() { return Collections.unmodifiableList(interestingItemSetNames); } /** - * @return the interestingItemSetNamesString + * Get the String representation of the interesting item set names the + * group is for. + * + * @return The String representation of the interesting item set names + * the group is for. */ String getInterestingItemSetNamesString() { return interestingItemSetNamesString; @@ -948,6 +1043,11 @@ public class DiscoveryKeyUtils { private final Long epochDate; private final String dateNameString; + /** + * Construct a new MostRecentActivityDateGroupKey. + * + * @param result The Result to create the group key for. + */ @NbBundle.Messages({ "DiscoveryKeyUtils.MostRecentActivityDateGroupKey.noDate=No Date Available"}) MostRecentActivityDateGroupKey(Result result) { @@ -1018,7 +1118,7 @@ public class DiscoveryKeyUtils { /** * Get the name which identifies this group. * - * @return The dateNameString + * @return The dateNameString. */ String getDateNameString() { return dateNameString; @@ -1033,6 +1133,11 @@ public class DiscoveryKeyUtils { private final Long epochDate; private final String dateNameString; + /** + * Construct a new FirstActivityDateGroupKey. + * + * @param result The Result to create the group key for. + */ @NbBundle.Messages({ "DiscoveryKeyUtils.FirstActivityDateGroupKey.noDate=No Date Available"}) FirstActivityDateGroupKey(Result result) { @@ -1103,21 +1208,26 @@ public class DiscoveryKeyUtils { /** * Get the name which identifies this group. * - * @return The dateNameString + * @return The dateNameString. */ String getDateNameString() { return dateNameString; } } - + /** * Key representing the number of visits. */ static class NumberOfVisitsGroupKey extends GroupKey { - + private final String displayName; private final Long visits; - + + /** + * Construct a new NumberOfVisitsGroupKey. + * + * @param result The Result to create the group key for. + */ @NbBundle.Messages({ "# {0} - totalVisits", "DiscoveryKeyUtils.NumberOfVisitsGroupKey.displayName={0} visits", @@ -1135,21 +1245,26 @@ public class DiscoveryKeyUtils { visits = -1L; } } - + @Override String getDisplayName() { return displayName; } - + @Override public int hashCode() { return Objects.hash(displayName); } - + + /** + * Get the number of visits this group is for. + * + * @return The number of visits this group is for. + */ Long getVisits() { return visits; } - + @Override public boolean equals(Object otherKey) { if (otherKey == this) { @@ -1163,7 +1278,7 @@ public class DiscoveryKeyUtils { NumberOfVisitsGroupKey visitsKey = (NumberOfVisitsGroupKey) otherKey; return visits.equals(visitsKey.getVisits()); } - + @Override public int compareTo(GroupKey otherGroupKey) { if (otherGroupKey instanceof NumberOfVisitsGroupKey) { @@ -1176,18 +1291,22 @@ public class DiscoveryKeyUtils { } /** - * Key representing an object detected group + * Key representing an object detected group. */ static class ObjectDetectedGroupKey extends GroupKey { private final List objectDetectedNames; private final String objectDetectedNamesString; + /** + * Construct a new ObjectDetectedGroupKey. + * + * @param file The file to create the group key for. + */ @NbBundle.Messages({ "DiscoveryKeyUtils.ObjectDetectedGroupKey.noSets=None"}) ObjectDetectedGroupKey(ResultFile file) { objectDetectedNames = file.getObjectDetectedNames(); - if (objectDetectedNames.isEmpty()) { objectDetectedNamesString = Bundle.DiscoveryKeyUtils_ObjectDetectedGroupKey_noSets(); } else { @@ -1242,14 +1361,20 @@ public class DiscoveryKeyUtils { } /** - * @return the objectDetectedNames + * Get the list of object detected names for this group. + * + * @return The list of object detected names for this group. */ List getObjectDetectedNames() { return Collections.unmodifiableList(objectDetectedNames); } /** - * @return the objectDetectedNamesString + * Get the String representation of the object detected names for this + * group. + * + * @return The String representation of the object detected names for + * this group. */ String getObjectDetectedNamesString() { return objectDetectedNamesString; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java index be1b04ed1b..c616ba12a8 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java @@ -32,34 +32,45 @@ import org.sleuthkit.datamodel.SleuthkitCase; * Main class to perform the domain search. */ public class DomainSearch { - + private final DomainSearchCache searchCache; private final DomainSearchThumbnailCache thumbnailCache; - + + /** + * Construct a new DomainSearch object. + */ public DomainSearch() { this(new DomainSearchCache(), new DomainSearchThumbnailCache()); } - + + /** + * Construct a new DomainSearch object with an existing DomainSearchCache + * and DomainSearchThumbnailCache. + * + * @param cache The DomainSearchCache to use for this DomainSearch. + * @param thumbnailCache The DomainSearchThumnailCache to use for this + * DomainSearch. + */ DomainSearch(DomainSearchCache cache, DomainSearchThumbnailCache thumbnailCache) { this.searchCache = cache; this.thumbnailCache = thumbnailCache; } - + /** * Run the domain search to get the group keys and sizes. Clears cache of * search results, caching new results for access at later time. * * @param userName The name of the user performing the search. - * @param filters The filters to apply - * @param groupAttributeType The attribute to use for grouping - * @param groupSortingType The method to use to sort the groups + * @param filters The filters to apply. + * @param groupAttributeType The attribute to use for grouping. + * @param groupSortingType The method to use to sort the groups. * @param domainSortingMethod The method to use to sort the domains within - * the groups - * @param caseDb The case database + * the groups. + * @param caseDb The case database. * @param centralRepoDb The central repository database. Can be null * if not needed. * - * @return A LinkedHashMap grouped and sorted according to the parameters + * @return A LinkedHashMap grouped and sorted according to the parameters. * * @throws DiscoveryException */ @@ -69,9 +80,9 @@ public class DomainSearch { Group.GroupSortingAlgorithm groupSortingType, ResultsSorter.SortingMethod domainSortingMethod, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { - + final Map> searchResults = searchCache.get( - userName, filters, groupAttributeType, groupSortingType, + userName, filters, groupAttributeType, groupSortingType, domainSortingMethod, caseDb, centralRepoDb); // Transform the cached results into a map of group key to group size. @@ -88,20 +99,20 @@ public class DomainSearch { * was not cached perform a search caching the groups. * * @param userName The name of the user performing the search. - * @param filters The filters to apply - * @param groupAttributeType The attribute to use for grouping - * @param groupSortingType The method to use to sort the groups + * @param filters The filters to apply. + * @param groupAttributeType The attribute to use for grouping. + * @param groupSortingType The method to use to sort the groups. * @param domainSortingMethod The method to use to sort the Domains within - * the groups + * the groups. * @param groupKey The key which uniquely identifies the group to - * get entries from - * @param startingEntry The first entry to return - * @param numberOfEntries The number of entries to return - * @param caseDb The case database + * get entries from. + * @param startingEntry The first entry to return. + * @param numberOfEntries The number of entries to return. + * @param caseDb The case database. * @param centralRepoDb The central repository database. Can be null * if not needed. * - * @return A LinkedHashMap grouped and sorted according to the parameters + * @return A LinkedHashMap grouped and sorted according to the parameters. * * @throws DiscoveryException */ @@ -112,9 +123,9 @@ public class DomainSearch { ResultsSorter.SortingMethod domainSortingMethod, GroupKey groupKey, int startingEntry, int numberOfEntries, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { - + final Map> searchResults = searchCache.get( - userName, filters, groupAttributeType, groupSortingType, + userName, filters, groupAttributeType, groupSortingType, domainSortingMethod, caseDb, centralRepoDb); final List domainsInGroup = searchResults.get(groupKey); @@ -131,11 +142,12 @@ public class DomainSearch { * Get a thumbnail representation of a domain name. See * DomainSearchThumbnailRequest for more details. * - * @param thumbnailRequest Thumbnail request for domain + * @param thumbnailRequest Thumbnail request for domain. + * * @return An Image instance or null if no thumbnail is available. * * @throws DiscoveryException If there is an error with Discovery related - * processing + * processing. */ public Image getThumbnail(DomainSearchThumbnailRequest thumbnailRequest) throws DiscoveryException { return thumbnailCache.get(thumbnailRequest); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsCache.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsCache.java index d3bb153176..41cfcc7e9b 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsCache.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsCache.java @@ -40,10 +40,11 @@ public class DomainSearchArtifactsCache { * is new, the results will be automatically loaded. * * @param request Artifact request, specifies type, Case, and domain name. - * @return A list of matching artifacts + * + * @return A list of matching artifacts. * * @throws DiscoveryException Any error that occurs during the loading - * process. + * process. */ public List get(DomainSearchArtifactsRequest request) throws DiscoveryException { try { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsRequest.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsRequest.java index 13f607eb6c..7391858981 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsRequest.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchArtifactsRequest.java @@ -31,6 +31,13 @@ public class DomainSearchArtifactsRequest { private final String domain; private final ARTIFACT_TYPE artifactType; + /** + * Construct a new DomainSearchArtifactsRequest object. + * + * @param sleuthkitCase The case database for the search. + * @param domain The domain that artifacts are being requested for. + * @param artifactType The type of artifact being requested. + */ public DomainSearchArtifactsRequest(SleuthkitCase sleuthkitCase, String domain, ARTIFACT_TYPE artifactType) { this.sleuthkitCase = sleuthkitCase; @@ -38,14 +45,29 @@ public class DomainSearchArtifactsRequest { this.artifactType = artifactType; } + /** + * Get the case database for the search. + * + * @return The case database for the search. + */ public SleuthkitCase getSleuthkitCase() { return sleuthkitCase; } + /** + * Get the domain that artifacts are being requested for. + * + * @return The domain that artifacts are being requested for. + */ public String getDomain() { return domain; } + /** + * Get the type of artifact being requested. + * + * @return The type of artifact being requested. + */ public ARTIFACT_TYPE getArtifactType() { return artifactType; } @@ -55,11 +77,9 @@ public class DomainSearchArtifactsRequest { if (other == this) { return true; } - if (!(other instanceof DomainSearchArtifactsRequest)) { return false; } - DomainSearchArtifactsRequest otherRequest = (DomainSearchArtifactsRequest) other; return this.sleuthkitCase == otherRequest.getSleuthkitCase() && this.domain.equals(otherRequest.getDomain()) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java index e7f46821a9..306a66b287 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java @@ -44,6 +44,21 @@ class DomainSearchCache { /** * Get domain search results matching the given parameters. If no results * are found, the cache will automatically load them. + * + * + * @param userName The name of the user performing the search. + * @param filters The filters to apply. + * @param groupAttributeType The attribute to use for grouping. + * @param groupSortingType The method to use to sort the groups. + * @param fileSortingMethod The method to use to sort the domains within + * the groups. + * @param caseDb The case database. + * @param centralRepoDb The central repository database. Can be null if + * not needed. + * + * @return Domain search results matching the given parameters. + * + * @throws DiscoveryException */ Map> get(String userName, List filters, @@ -51,11 +66,9 @@ class DomainSearchCache { Group.GroupSortingAlgorithm groupSortingType, ResultsSorter.SortingMethod domainSortingMethod, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { - try { final SearchKey searchKey = new SearchKey(userName, filters, groupAttributeType, groupSortingType, domainSortingMethod, caseDb, centralRepoDb); - return cache.get(searchKey); } catch (ExecutionException ex) { throw new DiscoveryException("Error fetching results from cache", ex.getCause()); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java index 99101cf053..a1f795864d 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java @@ -47,17 +47,17 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; /** - * Loads domain search results for cache misses. This loader is a Guava cache loader, - * which will be used in tandem with the DomainSearchCache, which is backed by a - * Guava LoadingCache. + * Loads domain search results for cache misses. This loader is a Guava cache + * loader, which will be used in tandem with the DomainSearchCache, which is + * backed by a Guava LoadingCache. */ class DomainSearchCacheLoader extends CacheLoader>> { - + @Override public Map> load(SearchKey key) throws DiscoveryException, SQLException, TskCoreException { List domainResults = getResultDomainsFromDatabase(key); - + // Apply secondary in memory filters for (AbstractFilter filter : key.getFilters()) { if (filter.useAlternateFilter()) { @@ -76,95 +76,93 @@ class DomainSearchCacheLoader extends CacheLoader getResultDomainsFromDatabase(SearchKey key) throws TskCoreException, SQLException, DiscoveryException { - + // Filters chosen in the UI are aggregated into SQL statements to be used in // the queries that follow. final Pair filterClauses = createWhereAndHavingClause(key.getFilters()); final String whereClause = filterClauses.getLeft(); final String havingClause = filterClauses.getRight(); - + // You may think of each row of this result as a TSK_DOMAIN attribute, where the parent // artifact type is within the (optional) filter and the parent artifact // had a date time attribute that was within the (optional) filter. With this // table in hand, we can simply group by domain and apply aggregate functions // to get, for example, # of downloads, # of visits in last 60, etc. - final String domainsTable = - "SELECT LOWER(MAX(value_text)) AS domain," + - " MAX(value_int64) AS date," + - " artifact_id AS parent_artifact_id," + - " MAX(artifact_type_id) AS parent_artifact_type_id " + - - "FROM blackboard_attributes " + - "WHERE " + whereClause + " " + - - "GROUP BY artifact_id " + - "HAVING " + havingClause; - + final String domainsTable + = "SELECT LOWER(MAX(value_text)) AS domain," + + " MAX(value_int64) AS date," + + " artifact_id AS parent_artifact_id," + + " MAX(artifact_type_id) AS parent_artifact_type_id " + + "FROM blackboard_attributes " + + "WHERE " + whereClause + " " + + "GROUP BY artifact_id " + + "HAVING " + havingClause; + // Needed to populate the visitsInLast60 data. final Instant currentTime = Instant.now(); final Instant sixtyDaysAgo = currentTime.minus(60, ChronoUnit.DAYS); - + // Check the group attribute, if by data source then the GROUP BY clause // should group by data source id before grouping by domain. - final AttributeType groupAttribute = key.getGroupAttributeType(); - final String groupByClause = (groupAttribute instanceof DataSourceAttribute) ? - "data_source_obj_id, domain" : "domain"; - + final AttributeType groupAttribute = key.getGroupAttributeType(); + final String groupByClause = (groupAttribute instanceof DataSourceAttribute) + ? "data_source_obj_id, domain" : "domain"; + final Optional dataSourceFilter = key.getFilters().stream() .filter(filter -> filter instanceof DataSourceFilter) .findFirst(); - + String dataSourceWhereClause = null; if (dataSourceFilter.isPresent()) { dataSourceWhereClause = dataSourceFilter.get().getWhereClause(); } - + // This query just processes the domains table, performing additional // groupings and applying aggregate functions to calculate discovery data. - final String domainsQuery = - /*SELECT */" domain," + - " MIN(date) AS activity_start," + - " MAX(date) AS activity_end," + - " SUM(CASE " + - " WHEN artifact_type_id = " + TSK_WEB_DOWNLOAD.getTypeID() + " THEN 1 " + - " ELSE 0 " + - " END) AS fileDownloads," + - " SUM(CASE " + - " WHEN artifact_type_id = " + TSK_WEB_HISTORY.getTypeID() + " THEN 1 " + - " ELSE 0 " + - " END) AS totalVisits," + - " SUM(CASE " + - " WHEN artifact_type_id = " + TSK_WEB_HISTORY.getTypeID() + " AND" + - " date BETWEEN " + sixtyDaysAgo.getEpochSecond() + " AND " + currentTime.getEpochSecond() + " THEN 1 " + - " ELSE 0 " + - " END) AS last60," + - " data_source_obj_id AS dataSource " + - - "FROM blackboard_artifacts" + - " JOIN (" + domainsTable + ") AS domains_table" + - " ON artifact_id = parent_artifact_id " + - - // Add the data source where clause here if present. - ((dataSourceWhereClause != null) ? "WHERE " + dataSourceWhereClause + " " : "") + - - "GROUP BY " + groupByClause; - + final String domainsQuery + = /* + * SELECT + */ " domain," + + " MIN(date) AS activity_start," + + " MAX(date) AS activity_end," + + " SUM(CASE " + + " WHEN artifact_type_id = " + TSK_WEB_DOWNLOAD.getTypeID() + " THEN 1 " + + " ELSE 0 " + + " END) AS fileDownloads," + + " SUM(CASE " + + " WHEN artifact_type_id = " + TSK_WEB_HISTORY.getTypeID() + " THEN 1 " + + " ELSE 0 " + + " END) AS totalVisits," + + " SUM(CASE " + + " WHEN artifact_type_id = " + TSK_WEB_HISTORY.getTypeID() + " AND" + + " date BETWEEN " + sixtyDaysAgo.getEpochSecond() + " AND " + currentTime.getEpochSecond() + " THEN 1 " + + " ELSE 0 " + + " END) AS last60," + + " data_source_obj_id AS dataSource " + + "FROM blackboard_artifacts" + + " JOIN (" + domainsTable + ") AS domains_table" + + " ON artifact_id = parent_artifact_id " + + // Add the data source where clause here if present. + ((dataSourceWhereClause != null) ? "WHERE " + dataSourceWhereClause + " " : "") + + "GROUP BY " + groupByClause; + final SleuthkitCase caseDb = key.getSleuthkitCase(); - final CaseDbAccessManager dbManager = caseDb.getCaseDbAccessManager(); - + final CaseDbAccessManager dbManager = caseDb.getCaseDbAccessManager(); + final DomainCallback domainCallback = new DomainCallback(caseDb); dbManager.select(domainsQuery, domainCallback); - + if (domainCallback.getSQLException() != null) { throw domainCallback.getSQLException(); } - + if (domainCallback.getTskCoreException() != null) { throw domainCallback.getTskCoreException(); } @@ -180,49 +178,51 @@ class DomainSearchCacheLoader extends CacheLoader createWhereAndHavingClause(List filters) { + Pair createWhereAndHavingClause(List filters) { final StringJoiner whereClause = new StringJoiner(" OR "); - final StringJoiner havingClause = new StringJoiner(" AND "); - + final StringJoiner havingClause = new StringJoiner(" AND "); + String artifactTypeFilter = null; boolean hasDateTimeFilter = false; - - for (AbstractFilter filter : filters) { + + for (AbstractFilter filter : filters) { if (filter instanceof ArtifactTypeFilter) { artifactTypeFilter = filter.getWhereClause(); } else if (!(filter instanceof DataSourceFilter) && !filter.useAlternateFilter()) { if (filter instanceof ArtifactDateRangeFilter) { hasDateTimeFilter = true; } - + whereClause.add("(" + filter.getWhereClause() + ")"); havingClause.add("SUM(CASE WHEN " + filter.getWhereClause() + " THEN 1 ELSE 0 END) > 0"); } } - + if (!hasDateTimeFilter) { whereClause.add(ArtifactDateRangeFilter.createAttributeTypeClause()); } - - String domainAttributeFilter = "attribute_type_id = " + TSK_DOMAIN.getTypeID() + - " AND value_text <> ''"; - + + String domainAttributeFilter = "attribute_type_id = " + TSK_DOMAIN.getTypeID() + + " AND value_text <> ''"; + whereClause.add("(" + domainAttributeFilter + ")"); havingClause.add("SUM(CASE WHEN " + domainAttributeFilter + " THEN 1 ELSE 0 END) > 0"); - + return Pair.of( whereClause.toString() + ((artifactTypeFilter != null) ? " AND (" + artifactTypeFilter + ")" : ""), havingClause.toString() ); } - + /** - * Callback to handle the result set of the domain query. This callback - * is responsible for mapping result set rows into ResultDomain objects - * for display. + * Callback to handle the result set of the domain query. This callback is + * responsible for mapping result set rows into ResultDomain objects for + * display. */ private class DomainCallback implements CaseDbAccessQueryCallback { @@ -230,17 +230,22 @@ class DomainSearchCacheLoader extends CacheLoader(); this.skc = skc; } - + @Override public void process(ResultSet resultSet) { try { resultSet.setFetchSize(500); - + while (resultSet.next()) { String domain = resultSet.getString("domain"); Long activityStart = resultSet.getLong("activity_start"); @@ -259,15 +264,15 @@ class DomainSearchCacheLoader extends CacheLoader getResultDomains() { return Collections.unmodifiableList(this.resultDomains); } - + + /** + * Get the SQLEception in an exception occurred. + * + * @return The SQLEception in an exception occurred. + */ private SQLException getSQLException() { return this.sqlCause; } - + + /** + * Get the TskCoreException if a SQL exception occurred. + * + * @return The TskCoreException if a tsk core exception occurred. + */ private TskCoreException getTskCoreException() { return this.coreCause; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailCache.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailCache.java index d13a87bcef..4662c45b7b 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailCache.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailCache.java @@ -27,7 +27,7 @@ import java.util.concurrent.ExecutionException; * Caches thumbnail requests. */ public class DomainSearchThumbnailCache { - + private static final int MAXIMUM_CACHE_SIZE = 500; private static final LoadingCache cache = CacheBuilder.newBuilder() @@ -37,11 +37,14 @@ public class DomainSearchThumbnailCache { /** * Get a thumbnail for the requested domain. If the request is new, the * thumbnail will be automatically loaded. - * - * @param request Requested domain to thumbnail - * @return The thumbnail Image instance, or null if no thumbnail is available - * - * @throws DiscoveryException If any error occurs during thumbnail generation. + * + * @param request Requested domain to thumbnail. + * + * @return The thumbnail Image instance, or null if no thumbnail is + * available. + * + * @throws DiscoveryException If any error occurs during thumbnail + * generation. */ public Image get(DomainSearchThumbnailRequest request) throws DiscoveryException { try { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java index 2923c35b4e..9dac2c2064 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java @@ -45,33 +45,38 @@ import org.openide.util.ImageUtilities; * loaded from the DomainSearchArtifactsCache and then further analyzed. */ public class DomainSearchThumbnailLoader extends CacheLoader { - - private static final String UNSUPPORTED_IMAGE = "org/sleuthkit/autopsy/images/image-extraction-not-supported.png"; + 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 final DomainSearchArtifactsCache artifactsCache; - + + /** + * Construct a new DomainSearchThumbnailLoader. + */ public DomainSearchThumbnailLoader() { this(new DomainSearchArtifactsCache()); } + /** + * Construct a new DomainSearchThumbnailLoader with an existing + * DomainSearchArtifactsCache. + * + * @param artifactsCache The DomainSearchArtifactsCache to use for this + * DomainSearchThumnailLoader. + */ DomainSearchThumbnailLoader(DomainSearchArtifactsCache artifactsCache) { this.artifactsCache = artifactsCache; } @Override public Image load(DomainSearchThumbnailRequest thumbnailRequest) throws TskCoreException, DiscoveryException { - final SleuthkitCase caseDb = thumbnailRequest.getSleuthkitCase(); - final DomainSearchArtifactsRequest webDownloadsRequest = new DomainSearchArtifactsRequest( caseDb, thumbnailRequest.getDomain(), TSK_WEB_DOWNLOAD); - final List webDownloads = artifactsCache.get(webDownloadsRequest); final List webDownloadPictures = getJpegsFromWebDownload(caseDb, webDownloads); Collections.sort(webDownloadPictures, (file1, file2) -> Long.compare(file1.getCrtime(), file2.getCrtime())); - for (int i = webDownloadPictures.size() - 1; i >= 0; i--) { // Get the most recent image, according to creation time. final AbstractFile mostRecent = webDownloadPictures.get(i); @@ -81,47 +86,53 @@ 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())); - for (int i = webCachePictures.size() - 1; i >= 0; i--) { // Get the largest image, according to file size. final AbstractFile largest = webCachePictures.get(i); - final Image candidateThumbnail = ImageUtils.getThumbnail(largest, thumbnailRequest.getIconSize()); if (candidateThumbnail != ImageUtils.getDefaultThumbnail()) { return candidateThumbnail; } } - return ImageUtilities.loadImage(UNSUPPORTED_IMAGE, false); } /** * Finds all JPEG source files from TSK_WEB_DOWNLOAD instances. + * + * @param caseDb The case database being searched. + * @param artifacts The list of artifacts to get jpegs from. + * + * @return The list of AbstractFiles representing jpegs which were + * associated with the artifacts. + * + * @throws TskCoreException */ private List getJpegsFromWebDownload(SleuthkitCase caseDb, List artifacts) throws TskCoreException { final List jpegs = new ArrayList<>(); - for (BlackboardArtifact artifact : artifacts) { final Content sourceContent = caseDb.getContentById(artifact.getObjectID()); addIfJpeg(jpegs, sourceContent); } - return jpegs; } /** * Finds all JPEG source files from TSK_WEB_CACHE instances. + * + * @param caseDb The case database being searched. + * @param artifacts The list of artifacts to get jpegs from. + * + * @return The list of AbstractFiles representing jpegs which were + * associated with the artifacts. */ private List getJpegsFromWebCache(SleuthkitCase caseDb, List artifacts) throws TskCoreException { final BlackboardAttribute.Type TSK_PATH_ID = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH_ID); - final List jpegs = new ArrayList<>(); for (BlackboardArtifact artifact : artifacts) { final BlackboardAttribute tskPathId = artifact.getAttribute(TSK_PATH_ID); @@ -130,12 +141,15 @@ public class DomainSearchThumbnailLoader extends CacheLoader files, Content sourceContent) { if ((sourceContent instanceof AbstractFile) && !(sourceContent instanceof DataSource)) { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailRequest.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailRequest.java index ca2bbcdc5a..45ce299e61 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailRequest.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailRequest.java @@ -22,34 +22,57 @@ import java.util.Objects; import org.sleuthkit.datamodel.SleuthkitCase; /** - * Requests a thumbnail to be generated for a given Case, domain and - * size. IconSize should be a value obtained from ImageUtils. + * Requests a thumbnail to be generated for a given Case, domain and size. + * IconSize should be a value obtained from ImageUtils. */ public class DomainSearchThumbnailRequest { - + private final SleuthkitCase sleuthkitCase; private final String domain; private final int iconSize; - - public DomainSearchThumbnailRequest(SleuthkitCase sleuthkitCase, + + /** + * Construct a new DomainSearchThumbnailRequest. + * + * @param sleuthkitCase The case database for this thumbnail request. + * @param domain The domain name for this thumbnail request. + * @param iconSize The size of icon that this thumbnail request should + * retrieve. + */ + public DomainSearchThumbnailRequest(SleuthkitCase sleuthkitCase, String domain, int iconSize) { this.sleuthkitCase = sleuthkitCase; this.domain = domain; this.iconSize = iconSize; } + /** + * Get the case database for this thumbnail request. + * + * @return The case database for this thumbnail request. + */ public SleuthkitCase getSleuthkitCase() { return sleuthkitCase; } + /** + * Get the domain name for this thumbnail request. + * + * @return The domain name for this thumbnail request. + */ public String getDomain() { return domain; } + /** + * Get the size of icon that this thumbnail request should retrieve. + * + * @return The size of icon that this thumbnail request should retrieve. + */ public int getIconSize() { return iconSize; } - + @Override public boolean equals(Object other) { if (other == this) { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/Group.java b/Core/src/org/sleuthkit/autopsy/discovery/search/Group.java index 8bd72e649a..688c854338 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/Group.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/Group.java @@ -24,7 +24,7 @@ import java.util.List; import org.openide.util.NbBundle.Messages; /** - * Class for storing files that belong to a particular group. + * Class for storing results that belong to a particular group. */ public class Group implements Comparable { @@ -34,7 +34,7 @@ public class Group implements Comparable { private final String displayName; /** - * Create a FileGroup object with its first file. + * Create a Group object with its first result. * * @param groupSortingType The method for sorting the group * @param groupKey The GroupKey for this group @@ -49,13 +49,13 @@ public class Group implements Comparable { /** * Add a Result to the group. Will not be sorted at this time. * - * @param result The Result to add to the FileGroup + * @param result The Result to add to the Group. */ void addResult(Result result) { if (result.getType() != SearchData.Type.DOMAIN && results.contains(result)) { //dedupe files and show instances - ResultFile existingCopy = (ResultFile)results.get(results.indexOf(result)); //get the copy of this which exists in the list - existingCopy.addDuplicate(((ResultFile)result).getFirstInstance()); + ResultFile existingCopy = (ResultFile) results.get(results.indexOf(result)); //get the copy of this which exists in the list + existingCopy.addDuplicate(((ResultFile) result).getFirstInstance()); } else { //Domains and non files are not being deduped currently results.add(result); @@ -81,9 +81,9 @@ public class Group implements Comparable { } /** - * Sort all the files in the group + * Sort all the results in the group */ - public void sortFiles(ResultsSorter sorter) { + public void sortResults(ResultsSorter sorter) { Collections.sort(results, sorter); } @@ -91,10 +91,10 @@ public class Group implements Comparable { * Compare this group to another group for sorting. Uses the algorithm * specified in groupSortingType. * - * @param otherGroup the group to compare this one to + * @param otherGroup The group to compare this one to. * * @return -1 if this group should be displayed before the other group, 1 - * otherwise + * otherwise. */ @Override public int compareTo(Group otherGroup) { @@ -109,12 +109,12 @@ public class Group implements Comparable { } /** - * Compare two groups based on the group key + * Compare two groups based on the group key. * - * @param group1 - * @param group2 + * @param group1 The first group to be compared. + * @param group2 The second group to be compared. * - * @return -1 if group1 should be displayed before group2, 1 otherwise + * @return -1 if group1 should be displayed before group2, 1 otherwise. */ private static int compareGroupsByGroupKey(Group group1, Group group2) { return group1.getGroupKey().compareTo(group2.getGroupKey()); @@ -124,10 +124,10 @@ public class Group implements Comparable { * Compare two groups based on the group size. Falls back on the group key * if the groups are the same size. * - * @param group1 - * @param group2 + * @param group1 The first group to be compared. + * @param group2 The second group to be compared. * - * @return -1 if group1 should be displayed before group2, 1 otherwise + * @return -1 if group1 should be displayed before group2, 1 otherwise. */ private static int compareGroupsBySize(Group group1, Group group2) { if (group1.getResults().size() != group2.getResults().size()) { @@ -166,9 +166,9 @@ public class Group implements Comparable { } /** - * Get the list of ResultFile objects in the group + * Get the list of Result objects in the group. * - * @return List of ResultFile objects + * @return The list of Result objects. */ public List getResults() { return Collections.unmodifiableList(results); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultDomain.java b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultDomain.java index 65964c2d61..64a3c751c6 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultDomain.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultDomain.java @@ -26,16 +26,17 @@ import org.sleuthkit.datamodel.TskData; * Container for domains that holds all necessary data for grouping and sorting. */ public class ResultDomain extends Result { + private final String domain; private final Long activityStart; private final Long activityEnd; private final Long totalVisits; private final Long visitsInLast60; private final Long filesDownloaded; - + private final Content dataSource; private final long dataSourceId; - + /** * Create a ResultDomain from a String. * @@ -51,30 +52,61 @@ public class ResultDomain extends Result { this.totalVisits = totalVisits; this.visitsInLast60 = visitsInLast60; this.filesDownloaded = filesDownloaded; - + this.setFrequency(SearchData.Frequency.UNKNOWN); } - + + /** + * Get the domain represented as a String. + * + * @return The String representation of the domain this result is for. + */ public String getDomain() { return this.domain; } + /** + * Get the date of first activity for this domain. + * + * @return The date of first activity for this domain. + */ public Long getActivityStart() { return activityStart; } + /** + * Get the date of most recent activity for this domain. + * + * @return The date of most recent activity for this domain. + */ public Long getActivityEnd() { return activityEnd; } - + + /** + * Get the total number of visits that this domain has had. + * + * @return The total number of visits that this domain has had. + */ public Long getTotalVisits() { return totalVisits; } + /** + * Get the number of visits that this domain has had in the last 60 days. + * + * @return The number of visits that this domain has had in the last 60 + * days. + */ public Long getVisitsInLast60() { return visitsInLast60; } + /** + * Get the number of files downloaded associated with this domain. + * + * @return The number of files downloaded associated with this domain. + */ public Long getFilesDownloaded() { return filesDownloaded; } @@ -98,12 +130,12 @@ public class ResultDomain extends Result { public SearchData.Type getType() { return SearchData.Type.DOMAIN; } - + @Override public String toString() { return "[domain=" + this.domain + ", data_source=" + this.dataSourceId + ", start=" - + this.activityStart + ", end=" + this.activityEnd + ", totalVisits=" + this.totalVisits + ", visitsLast60=" - + this.visitsInLast60 + ", downloads=" + this.filesDownloaded + ", frequency=" + + this.activityStart + ", end=" + this.activityEnd + ", totalVisits=" + this.totalVisits + ", visitsLast60=" + + this.visitsInLast60 + ", downloads=" + this.filesDownloaded + ", frequency=" + this.getFrequency() + "]"; } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultsSorter.java b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultsSorter.java index 8c5ed6cfb5..b63d86a7f9 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/ResultsSorter.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/ResultsSorter.java @@ -27,7 +27,7 @@ import org.openide.util.NbBundle; import org.sleuthkit.datamodel.TskCoreException; /** - * Class used to sort ResultFiles using the supplied method. + * Class used to sort Results using the supplied method. */ public class ResultsSorter implements Comparator { @@ -35,14 +35,14 @@ public class ResultsSorter implements Comparator { /** * Set up the sorter using the supplied sorting method. The sorting is - * defined by a list of ResultFile comparators. These comparators will be - * run in order until one returns a non-zero result. + * defined by a list of Result comparators. These comparators will be run in + * order until one returns a non-zero result. * - * @param method The method that should be used to sort the files + * @param method The method that should be used to sort the results. */ public ResultsSorter(SortingMethod method) { - // Set up the primary comparators that should applied to the files + // Set up the primary comparators that should applied to the results switch (method) { case BY_DATA_SOURCE: comparators.add(getDataSourceComparator()); @@ -75,7 +75,7 @@ public class ResultsSorter implements Comparator { } // Add the default comparator to the end. This will ensure a consistent sort - // order regardless of the order the files were added to the list. + // order regardless of the order the results were added to the list. comparators.add(getDefaultComparator()); } @@ -90,36 +90,37 @@ public class ResultsSorter implements Comparator { } } - // The files are the same + // The results are the same return result; } /** - * Compare files using data source ID. Will order smallest to largest. + * Compare results using data source ID. Will order smallest to largest. * - * @return -1 if file1 has the lower data source ID, 0 if equal, 1 otherwise + * @return -1 if result1 has the lower data source ID, 0 if equal, 1 + * otherwise. */ private static Comparator getDataSourceComparator() { return (Result result1, Result result2) -> Long.compare(result1.getDataSourceObjectId(), result2.getDataSourceObjectId()); } /** - * Compare files using their FileType enum. Orders based on the ranking in - * the FileType enum. + * Compare results using their Type enum. Orders based on the ranking in the + * Type enum. * - * @return -1 if file1 has the lower FileType value, 0 if equal, 1 otherwise + * @return -1 if result1 has the lower Type value, 0 if equal, 1 otherwise. */ private static Comparator getTypeComparator() { return (Result result1, Result result2) -> Integer.compare(result1.getType().getRanking(), result2.getType().getRanking()); } - + /** * Compare files using a concatenated version of keyword list names. * Alphabetical by the list names with files with no keyword list hits going * last. * - * @return -1 if file1 has the earliest combined keyword list name, 0 if - * equal, 1 otherwise + * @return -1 if result1 has the earliest combined keyword list name, 0 if + * equal, 1 otherwise. */ private static Comparator getKeywordListNameComparator() { return (Result result1, Result result2) -> { @@ -147,8 +148,8 @@ public class ResultsSorter implements Comparator { /** * Compare files based on parent path. Order alphabetically. * - * @return -1 if file1's path comes first alphabetically, 0 if equal, 1 - * otherwise + * @return -1 if result1's path comes first alphabetically, 0 if equal, 1 + * otherwise. */ private static Comparator getParentPathComparator() { @@ -178,10 +179,11 @@ public class ResultsSorter implements Comparator { } /** - * Compare files based on number of occurrences in the central repository. + * Compare results based on number of occurrences in the central repository. * Order from most rare to least rare Frequency enum. * - * @return -1 if file1's rarity is lower than file2, 0 if equal, 1 otherwise + * @return -1 if result1's rarity is lower than result2, 0 if equal, 1 + * otherwise. */ private static Comparator getFrequencyComparator() { return (Result result1, Result result2) -> Integer.compare(result1.getFrequency().getRanking(), result2.getFrequency().getRanking()); @@ -190,8 +192,8 @@ public class ResultsSorter implements Comparator { /** * Compare files based on MIME type. Order is alphabetical. * - * @return -1 if file1's MIME type comes before file2's, 0 if equal, 1 - * otherwise + * @return -1 if result1's MIME type comes before result2's, 0 if equal, 1 + * otherwise. */ private static Comparator getMIMETypeComparator() { return (Result result1, Result result2) -> { @@ -205,7 +207,7 @@ public class ResultsSorter implements Comparator { /** * Compare files based on size. Order large to small. * - * @return -1 if file1 is larger than file2, 0 if equal, 1 otherwise + * @return -1 if result1 is larger than result2, 0 if equal, 1 otherwise. */ private static Comparator getFileSizeComparator() { return (Result result1, Result result2) -> { @@ -219,7 +221,7 @@ public class ResultsSorter implements Comparator { /** * Compare files based on file name. Order alphabetically. * - * @return -1 if file1 comes before file2, 0 if equal, 1 otherwise + * @return -1 if result1 comes before result2, 0 if equal, 1 otherwise. */ private static Comparator getFileNameComparator() { return (Result result1, Result result2) -> { @@ -232,6 +234,8 @@ public class ResultsSorter implements Comparator { /** * Sorts domain names in lexographical order, ignoring case. + * + * @return -1 if domain1 comes before domain2, 0 if equal, 1 otherwise. */ private static Comparator getDomainNameComparator() { return (Result domain1, Result domain2) -> { @@ -244,16 +248,18 @@ public class ResultsSorter implements Comparator { return compareStrings(first.getDomain().toLowerCase(), second.getDomain().toLowerCase()); }; } - + /** - * Sorts results by most recent date time + * Sorts results by most recent date time. + * + * @return -1 if domain1 comes before domain2, 0 if equal, 1 otherwise. */ private static Comparator getMostRecentDateTimeComparator() { return (Result result1, Result result2) -> { - if(result1.getType() != SearchData.Type.DOMAIN) { + if (result1.getType() != SearchData.Type.DOMAIN) { return 0; } - + ResultDomain first = (ResultDomain) result1; ResultDomain second = (ResultDomain) result2; return Long.compare(second.getActivityEnd(), first.getActivityEnd()); @@ -266,7 +272,7 @@ public class ResultsSorter implements Comparator { * include something like the object ID to ensure a consistent sorting when * the rest of the compared fields are the same. * - * @return -1 if file1 comes before file2, 0 if equal, 1 otherwise + * @return -1 if file1 comes before file2, 0 if equal, 1 otherwise. */ private static Comparator getDefaultComparator() { return (Result result1, Result result2) -> { @@ -292,7 +298,7 @@ public class ResultsSorter implements Comparator { * @param s1 * @param s2 * - * @return -1 if s1 comes before s2, 0 if equal, 1 otherwise + * @return -1 if s1 comes before s2, 0 if equal, 1 otherwise. */ private static int compareStrings(String s1, String s2) { String string1 = s1 == null ? "" : s1; @@ -334,6 +340,13 @@ public class ResultsSorter implements Comparator { private final String displayName; private final List requiredAttributes; + /** + * Construct a new SortingMethod enum value. + * + * @param attributes The list of DiscoveryAttributes required by this + * enum value. + * @param displayName The display name for this enum value. + */ SortingMethod(List attributes, String displayName) { this.requiredAttributes = attributes; this.displayName = displayName; @@ -344,23 +357,28 @@ public class ResultsSorter implements Comparator { return displayName; } + /** + * Get the list of DiscoveryAttributes required by this enum value. + * + * @return The list of DiscoveryAttributes required by this enum value. + */ public List getRequiredAttributes() { return Collections.unmodifiableList(requiredAttributes); } /** - * Get the list of enums that are valid for ordering files. + * Get the list of enum values that are valid for ordering files. * - * @return Enums that can be used to ordering files. + * @return Enum values that can be used to ordering files. */ public static List getOptionsForOrderingFiles() { return Arrays.asList(BY_FILE_SIZE, BY_FULL_PATH, BY_FILE_NAME, BY_DATA_SOURCE); } /** - * Get the list of enums that are valid for ordering files. + * Get the list of enum values that are valid for ordering files. * - * @return Enums that can be used to ordering files. + * @return Enum values that can be used to ordering files. */ public static List getOptionsForOrderingDomains() { return Arrays.asList(BY_DOMAIN_NAME, BY_DATA_SOURCE); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchData.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchData.java index 5effd4b65d..909cfb1acd 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchData.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchData.java @@ -39,7 +39,7 @@ public final class SearchData { private static final Set DOMAIN_ARTIFACT_TYPES = EnumSet.of(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY, BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY); /** - * Enum representing how often the file occurs in the Central Repository. + * Enum representing how often the result occurs in the Central Repository. */ @NbBundle.Messages({ "SearchData.Frequency.unique.displayName=Unique (1)", @@ -60,6 +60,13 @@ public final class SearchData { private final String displayName; private final int maxOccur; + /** + * Construct a new frequency enum value. + * + * @param ranking The rank for sorting. + * @param maxOccur The max occurrences this enum value is for. + * @param displayName The display name for this enum value. + */ Frequency(int ranking, int maxOccur, String displayName) { this.ranking = ranking; this.maxOccur = maxOccur; @@ -69,7 +76,7 @@ public final class SearchData { /** * Get the rank for sorting. * - * @return the rank (lower should be displayed first) + * @return The rank (lower should be displayed first). */ public int getRanking() { return ranking; @@ -78,9 +85,9 @@ public final class SearchData { /** * Get the enum matching the given occurrence count. * - * @param count Number of times a file is in the Central Repository. + * @param count Number of times a result is in the Central Repository. * - * @return the corresponding enum + * @return The corresponding enum. */ public static Frequency fromCount(long count) { if (count <= UNIQUE.getMaxOccur()) { @@ -119,7 +126,9 @@ public final class SearchData { } /** - * @return the maxOccur + * Get the maximum number of occurrences this enum value is for. + * + * @return The maximum number of occurrences this enum value is for. */ public int getMaxOccur() { return maxOccur; @@ -127,7 +136,7 @@ public final class SearchData { } /** - * Enum representing the file size + * Enum representing the file size. */ @NbBundle.Messages({ "SearchData.FileSize.XXLARGE.displayName=XXLarge", @@ -169,6 +178,16 @@ public final class SearchData { private final String displaySize; final static long NO_MAXIMUM = -1; + /** + * Construct a new FileSize enum value. + * + * @param ranking The rank for sorting. + * @param minB The minimum size included in this enum value. + * @param maxB The maximum size included in this enum value. + * @param displayName The display name for this enum value. + * @param displaySize The size to display in association with this enum + * value. + */ FileSize(int ranking, long minB, long maxB, String displayName, String displaySize) { this.ranking = ranking; this.minBytes = minB; @@ -185,9 +204,9 @@ public final class SearchData { * Get the enum corresponding to the given file size for image files. * The file size must be strictly greater than minBytes. * - * @param size the file size + * @param size The file size. * - * @return the enum whose range contains the file size + * @return The enum whose range contains the file size. */ public static FileSize fromImageSize(long size) { if (size > XXLARGE_IMAGE.getMinBytes()) { @@ -209,9 +228,9 @@ public final class SearchData { * Get the enum corresponding to the given file size for video files. * The file size must be strictly greater than minBytes. * - * @param size the file size + * @param size The file size. * - * @return the enum whose range contains the file size + * @return The enum whose range contains the file size. */ public static FileSize fromVideoSize(long size) { if (size > XXLARGE_VIDEO.getMinBytes()) { @@ -232,7 +251,7 @@ public final class SearchData { /** * Get the upper limit of the range. * - * @return the maximum file size that will fit in this range. + * @return The maximum file size that will fit in this range. */ public long getMaxBytes() { return maxBytes; @@ -241,7 +260,7 @@ public final class SearchData { /** * Get the lower limit of the range. * - * @return the maximum file size that is not part of this range + * @return The maximum file size that is not part of this range. */ public long getMinBytes() { return minBytes; @@ -250,7 +269,7 @@ public final class SearchData { /** * Get the rank for sorting. * - * @return the rank (lower should be displayed first) + * @return The rank (lower should be displayed first). */ public int getRanking() { return ranking; @@ -261,6 +280,11 @@ public final class SearchData { return sizeGroup + displaySize; } + /** + * Get the name of the size group. For example Small. + * + * @return The name of the size group. For example Small. + */ public String getSizeGroup() { return sizeGroup; } @@ -313,6 +337,13 @@ public final class SearchData { .add("application/pdf", //NON-NLS "application/xhtml+xml").build(); //NON-NLS + /** + * Get the list of document types for which image extraction is not + * supported. + * + * @return The list of document types for which image extraction is not + * supported. + */ public static Collection getDocTypesWithoutImageExtraction() { return Collections.unmodifiableCollection(IMAGE_UNSUPPORTED_DOC_TYPES); } @@ -333,17 +364,26 @@ public final class SearchData { IMAGE(0, Bundle.SearchData_FileType_Image_displayName(), FileTypeUtils.FileTypeCategory.IMAGE.getMediaTypes(), new ArrayList<>()), AUDIO(1, Bundle.SearchData_FileType_Audio_displayName(), FileTypeUtils.FileTypeCategory.AUDIO.getMediaTypes(), new ArrayList<>()), VIDEO(2, Bundle.SearchData_FileType_Video_displayName(), FileTypeUtils.FileTypeCategory.VIDEO.getMediaTypes(), new ArrayList<>()), - EXECUTABLE(3, Bundle.SearchData_FileType_Executables_displayName(), FileTypeUtils.FileTypeCategory.EXECUTABLE.getMediaTypes(),new ArrayList<>()), + EXECUTABLE(3, Bundle.SearchData_FileType_Executables_displayName(), FileTypeUtils.FileTypeCategory.EXECUTABLE.getMediaTypes(), new ArrayList<>()), DOCUMENT(4, Bundle.SearchData_FileType_Documents_displayName(), DOCUMENT_MIME_TYPES, new ArrayList<>()), DOMAIN(6, Bundle.SearchData_AttributeType_Domain_displayName(), new ArrayList<>(), DOMAIN_ARTIFACT_TYPES), OTHER(5, Bundle.SearchData_FileType_Other_displayName(), new ArrayList<>(), new ArrayList<>()); - private final int ranking; // For ordering in the UI private final String displayName; private final Collection mediaTypes; private final Collection artifactTypes; + /** + * Construct a new Type enum value. + * + * @param value Integer value for comparison. + * @param displayName The display name for this type. + * @param mediaTypes The list of mime types this type is defined by + * if it is file type. + * @param artifactTypes The list of artifact types this type is defined + * by if it is an attribute type. + */ Type(int value, String displayName, Collection mediaTypes, Collection artifactTypes) { this.ranking = value; this.displayName = displayName; @@ -359,7 +399,12 @@ public final class SearchData { public Collection getMediaTypes() { return Collections.unmodifiableCollection(mediaTypes); } - + + /** + * Get the BlackboardArtifact types matching this category. + * + * @return Collection of BlackboardArtifact.ARTIFACT_TYPE objects. + */ public Collection getArtifactTypes() { return Collections.unmodifiableCollection(artifactTypes); } @@ -395,6 +440,12 @@ public final class SearchData { private final int ranking; private final String displayName; + /** + * Construct a new Score enum value. + * + * @param ranking The rank for sorting. + * @param displayName The display name for this enum value. + */ Score(int ranking, String displayName) { this.ranking = ranking; this.displayName = displayName; @@ -403,7 +454,7 @@ public final class SearchData { /** * Get the rank for sorting. * - * @return the rank (lower should be displayed first) + * @return The rank (lower should be displayed first). */ public int getRanking() { return ranking; @@ -412,7 +463,7 @@ public final class SearchData { /** * Get the list of enums that are valid for filtering. * - * @return enums that can be used to filter + * @return Enums that can be used to filter. */ public static List getOptionsForFiltering() { return Arrays.asList(NOTABLE, INTERESTING); @@ -424,6 +475,9 @@ public final class SearchData { } } + /** + * Private constructor for SearchData class. + */ private SearchData() { // Class should not be instantiated } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java index 82ed314d6d..27a2b42342 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java @@ -43,19 +43,19 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; /** - * Run various filters to return a subset of files from the current case. + * Run various filters to return a subset of Results from the current case. */ public class SearchFiltering { /** * Run the given filters to get a list of matching files. * - * @param filters The filters to run - * @param caseDb The case database - * @param crDb The central repo. Can be null as long as no filters need - * it. + * @param filters The filters to run. + * @param caseDb The case database. + * @param centralRepoDb The central repo. Can be null as long as no filters + * need it. * - * @return + * @return List of Results from the search performed. */ static List runQueries(List filters, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { if (caseDb == null) { @@ -89,10 +89,10 @@ public class SearchFiltering { * @param filters The filters to run. * @param combinedQuery The query to get results files for. * @param caseDb The case database. - * @param crDb The central repo. Can be null as long as no filters + * @param centralRepoDb The central repo. Can be null as long as no filters * need it. * - * @return An ArrayList of ResultFiles returned by the query. + * @return An ArrayList of Results returned by the query. * * @throws TskCoreException * @throws DiscoveryException @@ -124,36 +124,42 @@ public class SearchFiltering { } return resultList; } - + /** * A filter to specify date range for artifacts, start and end times should * be in epoch seconds. */ public static class ArtifactDateRangeFilter extends AbstractFilter { - + private final Long startDate; private final Long endDate; - + // Attributes to search for date - private static List dateAttributes = - Arrays.asList( - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED, - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED - ); - + private static List dateAttributes + = Arrays.asList( + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED, + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED + ); + + /** + * Construct a new ArtifactDateRangeFilter. + * + * @param startDate The first date to include results for in the search. + * @param endDate The last date to include results for in the search. + */ public ArtifactDateRangeFilter(Long startDate, Long endDate) { this.startDate = startDate; this.endDate = endDate; } - + /** - * Create a SQL clause containing the date time attribute types - * to search. + * Create a SQL clause containing the date time attribute types to + * search. */ static String createAttributeTypeClause() { StringJoiner joiner = new StringJoiner(","); - for(BlackboardAttribute.ATTRIBUTE_TYPE type : dateAttributes) { + for (BlackboardAttribute.ATTRIBUTE_TYPE type : dateAttributes) { joiner.add("\'" + type.getTypeID() + "\'"); } return "attribute_type_id IN (" + joiner.toString() + ")"; @@ -161,8 +167,8 @@ public class SearchFiltering { @Override public String getWhereClause() { - return createAttributeTypeClause() + - " AND (value_int64 BETWEEN " + startDate + " AND " + endDate + ")"; + return createAttributeTypeClause() + + " AND (value_int64 BETWEEN " + startDate + " AND " + endDate + ")"; } @Override @@ -170,14 +176,20 @@ public class SearchFiltering { return "ArtifactDateRangeFilter Stub"; } } - + /** - * A filter to specify artifact types + * A filter to specify artifact types. */ public static class ArtifactTypeFilter extends AbstractFilter { - + private final List types; - + + /** + * Construct a new ArtifactTypeFilter. + * + * @param types The list of BlackboardArtifact types to include in + * results from. + */ public ArtifactTypeFilter(List types) { this.types = types; } @@ -185,10 +197,10 @@ public class SearchFiltering { @Override public String getWhereClause() { StringJoiner joiner = new StringJoiner(","); - for(ARTIFACT_TYPE type : types) { + for (ARTIFACT_TYPE type : types) { joiner.add("\'" + type.getTypeID() + "\'"); } - + return "artifact_type_id IN (" + joiner + ")"; } @@ -196,20 +208,20 @@ public class SearchFiltering { public String getDesc() { return "ArtifactTypeFilter Stub"; } - + } /** - * A filter for specifying the file size + * A filter for specifying the file size. */ public static class SizeFilter extends AbstractFilter { private final List fileSizes; /** - * Create the SizeFilter + * Create the SizeFilter. * - * @param fileSizes the file sizes that should match + * @param fileSizes The file sizes that should match. */ public SizeFilter(List fileSizes) { this.fileSizes = fileSizes; @@ -251,7 +263,7 @@ public class SearchFiltering { /** * A utility class for the ParentFilter to store the search string and - * whether it is a full path or a substring. + * whether it is a full path or a sub-string. */ public static class ParentSearchTerm { @@ -260,11 +272,11 @@ public class SearchFiltering { private final boolean included; /** - * Create the ParentSearchTerm object + * Create the ParentSearchTerm object. * - * @param searchStr The string to search for in the file path + * @param searchStr The string to search for in the file path. * @param isFullPath True if the path should exactly match the given - * string, false to do a substring search + * string, false to do a sub-string search. * @param isIncluded True if the results must include the path, false if * the path should be excluded from the results. */ @@ -275,9 +287,9 @@ public class SearchFiltering { } /** - * Get the SQL term to search for + * Get the SQL term to search for. * - * @return The SQL for a where clause to search for a matching path + * @return The SQL for a where clause to search for a matching path. */ public String getSQLForTerm() { // TODO - these should really be prepared statements @@ -318,21 +330,31 @@ public class SearchFiltering { } /** - * @return the fullPath + * Is the search string the full path of the of the parent or is it a + * sub-string in the parent path? + * + * @return True if the search string is the full path of the parent, + * false if it is a sub-string. */ public boolean isFullPath() { return fullPath; } /** - * @return the included + * Should the search string be included in the path, or excluded from + * the path? + * + * @return True if the search string should be included, false if it + * should be excluded. */ public boolean isIncluded() { return included; } /** - * @return the searchStr + * Get the string being searched for by this filter. + * + * @return The string being searched for by this filter. */ public String getSearchStr() { return searchStr; @@ -340,16 +362,16 @@ public class SearchFiltering { } /** - * A filter for specifying parent path (either full path or substring) + * A filter for specifying parent path (either full path or substring). */ public static class ParentFilter extends AbstractFilter { private final List parentSearchTerms; /** - * Create the ParentFilter + * Create the ParentFilter. * - * @param parentSearchTerms Full paths or substrings to filter on + * @param parentSearchTerms Full paths or substrings to filter on. */ public ParentFilter(List parentSearchTerms) { this.parentSearchTerms = parentSearchTerms; @@ -417,16 +439,16 @@ public class SearchFiltering { } /** - * A filter for specifying data sources + * A filter for specifying data sources. */ public static class DataSourceFilter extends AbstractFilter { private final List dataSources; /** - * Create the DataSourceFilter + * Create the DataSourceFilter. * - * @param dataSources the data sources to filter on + * @param dataSources The data sources to filter on. */ public DataSourceFilter(List dataSources) { this.dataSources = dataSources; @@ -475,9 +497,9 @@ public class SearchFiltering { private final List listNames; /** - * Create the KeywordListFilter + * Create the KeywordListFilter. * - * @param listNames + * @param listNames The list of keywords for this filter. */ public KeywordListFilter(List listNames) { this.listNames = listNames; @@ -511,7 +533,7 @@ public class SearchFiltering { private final List categories; /** - * Create the FileTypeFilter + * Create the FileTypeFilter. * * @param categories List of file types to filter on */ @@ -520,9 +542,9 @@ public class SearchFiltering { } /** - * Create the FileTypeFilter + * Create the FileTypeFilter. * - * @param category the file type to filter on + * @param category The file type to filter on. */ public FileTypeFilter(Type category) { this.categories = new ArrayList<>(); @@ -570,9 +592,9 @@ public class SearchFiltering { private final List frequencies; /** - * Create the FrequencyFilter + * Create the FrequencyFilter. * - * @param frequencies List of frequencies that will pass the filter + * @param frequencies List of frequencies that will pass the filter. */ public FrequencyFilter(List frequencies) { this.frequencies = frequencies; @@ -640,9 +662,9 @@ public class SearchFiltering { private final List setNames; /** - * Create the HashSetFilter + * Create the HashSetFilter. * - * @param setNames + * @param setNames The hash set names for this filter. */ public HashSetFilter(List setNames) { this.setNames = setNames; @@ -678,9 +700,9 @@ public class SearchFiltering { private final List setNames; /** - * Create the InterestingFileSetFilter + * Create the InterestingFileSetFilter. * - * @param setNames + * @param setNames The interesting file set names for this filter. */ public InterestingFileSetFilter(List setNames) { this.setNames = setNames; @@ -716,9 +738,9 @@ public class SearchFiltering { private final List typeNames; /** - * Create the ObjectDetectionFilter + * Create the ObjectDetectionFilter. * - * @param typeNames + * @param typeNames The type names for this filter. */ public ObjectDetectionFilter(List typeNames) { this.typeNames = typeNames; @@ -747,16 +769,16 @@ public class SearchFiltering { /** * A filter for specifying the score. A file must have one of the given - * scores to pass + * scores to pass. */ public static class ScoreFilter extends AbstractFilter { private final List scores; /** - * Create the ObjectDetectionFilter + * Create the ScoreFilter. * - * @param typeNames + * @param scores The list of scores for this filter. */ public ScoreFilter(List scores) { this.scores = scores; @@ -831,9 +853,9 @@ public class SearchFiltering { private final List tagNames; /** - * Create the TagsFilter + * Create the TagsFilter. * - * @param tagNames + * @param tagNames The list of tag names for this filter. */ public TagsFilter(List tagNames) { this.tagNames = tagNames; @@ -975,6 +997,13 @@ public class SearchFiltering { } } + /** + * Concatenate the set names into a "," separated list. + * + * @param setNames The List of setNames to concatenate. + * + * @return The concatenated list for display. + */ @NbBundle.Messages({ "FileSearchFiltering.concatenateSetNamesForDisplay.comma=, ",}) private static String concatenateSetNamesForDisplay(List setNames) { @@ -992,9 +1021,9 @@ public class SearchFiltering { * Concatenate the set names into an "OR" separated list. This does not do * any SQL-escaping. * - * @param setNames + * @param setNames The List of setNames to concatenate. * - * @return the list to use in the SQL query + * @return The concatenated list to use in the SQL query. */ private static String concatenateNamesForSQL(List setNames) { String result = ""; // NON-NLS @@ -1007,6 +1036,9 @@ public class SearchFiltering { return result; } + /** + * Private constructor for SearchFiltering class. + */ private SearchFiltering() { // Class should not be instantiated } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java index f427d97d28..8d07b03e22 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java @@ -76,7 +76,7 @@ class SearchResults { for (Result result : results) { // Add the file to the appropriate group, creating it if necessary GroupKey groupKey = attrType.getGroupKey(result); - + if (!groupMap.containsKey(groupKey)) { groupMap.put(groupKey, new Group(groupSortingType, groupKey)); } @@ -92,7 +92,7 @@ class SearchResults { // First sortGroupsAndFiles the files for (Group group : groupMap.values()) { - group.sortFiles(fileSorter); + group.sortResults(fileSorter); } // Now put the groups in a list and sortGroupsAndFiles them diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SummaryHelpers.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SummaryHelpers.java index 60e7e171ca..c258801f70 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SummaryHelpers.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SummaryHelpers.java @@ -59,6 +59,13 @@ class SummaryHelpers { // Class should not be instantiated } + /** + * Get the default text summary for the document. + * + * @param file The file to summarize. + * + * @return The TextSummary object which is a default summary for the file. + */ static TextSummary getDefaultSummary(AbstractFile file) { Image image = null; int countOfImages = 0; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractDiscoveryFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractDiscoveryFilterPanel.java index d3770ef5ac..3e4ab45592 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractDiscoveryFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractDiscoveryFilterPanel.java @@ -70,7 +70,8 @@ abstract class AbstractDiscoveryFilterPanel extends javax.swing.JPanel { /** * Check if this filter is configured to valid settings. * - * @return If the settings are invalid returns the error that has occurred, otherwise returns empty string. + * @return If the settings are invalid returns the error that has occurred, + * otherwise returns empty string. */ abstract String checkForError(); @@ -93,8 +94,8 @@ abstract class AbstractDiscoveryFilterPanel extends javax.swing.JPanel { /** * Get the AbstractFilter which is represented by this Panel. * - * @return The AbstractFilter for the selected settings, null if the settings - * are not in use. + * @return The AbstractFilter for the selected settings, null if the + * settings are not in use. */ abstract AbstractFilter getFilter(); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java index 298789bf3b..6e8137a6ed 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/AbstractFiltersPanel.java @@ -70,7 +70,6 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li secondColumnPanel.setLayout(new GridBagLayout()); } - /** * Get the type of results this filters panel is for. * @@ -127,7 +126,7 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li secondColumnY += constraints.gridheight; } } - + /** * Add the panels representing the two columns to the specified JSplitPane. * @@ -279,42 +278,56 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li } /** - * @return the lastSortingMethod + * Get the most recently used sorting method. + * + * @return The most recently used sorting method. */ SortingMethod getLastSortingMethod() { return lastSortingMethod; } /** - * @param lastSortingMethod the lastSortingMethod to set + * Set the most recently used sorting method. + * + * @param lastSortingMethod The most recently used sorting method. */ final void setLastSortingMethod(SortingMethod lastSortingMethod) { this.lastSortingMethod = lastSortingMethod; } /** - * @return the lastGroupingAttributeType + * Get the most recently used grouping attribute. + * + * @return The most recently used grouping attribute. */ GroupingAttributeType getLastGroupingAttributeType() { return lastGroupingAttributeType; } /** - * @param lastGroupingAttributeType the lastGroupingAttributeType to set + * Set the most recently used grouping attribute. + * + * @param lastGroupingAttributeType The most recently used grouping + * attribute. */ final void setLastGroupingAttributeType(GroupingAttributeType lastGroupingAttributeType) { this.lastGroupingAttributeType = lastGroupingAttributeType; } /** - * @return the lastGroupSortingAlg + * Get the most recently used group sorting algorithm. + * + * @return The most recently used group sorting algorithm. */ Group.GroupSortingAlgorithm getLastGroupSortingAlg() { return lastGroupSortingAlg; } /** - * @param lastGroupSortingAlg the lastGroupSortingAlg to set + * Set the group sorting algorithm that was used most recently. + * + * @param lastGroupSortingAlg The most recently used group sorting + * algorithm. */ final void setLastGroupSortingAlg(Group.GroupSortingAlgorithm lastGroupSortingAlg) { this.lastGroupSortingAlg = lastGroupSortingAlg; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.form index e24e6f6a3b..522cd9b43e 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.form @@ -6,9 +6,6 @@ - - - diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index 9b7525bbd1..783fd1616f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -318,7 +318,6 @@ final class DiscoveryDialog extends javax.swing.JDialog { setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); setMinimumSize(new java.awt.Dimension(600, 300)); - setPreferredSize(new java.awt.Dimension(1000, 650)); imagesButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/pictures-icon.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(imagesButton, org.openide.util.NbBundle.getMessage(DiscoveryDialog.class, "DiscoveryDialog.imagesButton.text")); // NOI18N diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java index 07b01c976b..1a36ab8bce 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java @@ -81,7 +81,7 @@ public final class DiscoveryTopComponent extends TopComponent { }); rightSplitPane.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, new PropertyChangeListener() { @Override - public void propertyChange(PropertyChangeEvent evt) { + public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equalsIgnoreCase(JSplitPane.DIVIDER_LOCATION_PROPERTY)) { //Only change the saved location when it was a manual change by the user and not the animation or the window opening initially if ((animator == null || !animator.isRunning()) && evt.getNewValue() instanceof Integer @@ -91,7 +91,7 @@ public final class DiscoveryTopComponent extends TopComponent { } } } - }); + }); } /** diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java index cf3209146d..bce5577054 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java @@ -98,7 +98,6 @@ public class DomainFilterPanel extends AbstractFiltersPanel { } - // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JSplitPane domainFiltersSplitPane; // End of variables declaration//GEN-END:variables diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java index b1791c3ff3..b40d77ef63 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java @@ -88,7 +88,7 @@ final class GroupListPanel extends javax.swing.JPanel { searchfilters = searchCompleteEvent.getFilters(); groupingAttribute = searchCompleteEvent.getGroupingAttr(); groupSort = searchCompleteEvent.getGroupSort(); - resultSortMethod = searchCompleteEvent.getFileSort(); + resultSortMethod = searchCompleteEvent.getResultSort(); groupKeyList.setListData(groupMap.keySet().toArray(new GroupKey[groupMap.keySet().size()])); SwingUtilities.invokeLater(() -> { if (groupKeyList.getModel().getSize() > 0) { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/OpenDiscoveryAction.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/OpenDiscoveryAction.java index 2931a962dd..33228a6a9b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/OpenDiscoveryAction.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/OpenDiscoveryAction.java @@ -38,8 +38,7 @@ import org.sleuthkit.autopsy.casemodule.Case; */ @ActionID(category = "Tools", id = "org.sleuthkit.autopsy.newpackage.OpenDiscoveryAction") @ActionReferences(value = { - @ActionReference(path = "Menu/Tools", position = 105) - , + @ActionReference(path = "Menu/Tools", position = 105), @ActionReference(path = "Toolbars/Case", position = 105)}) @ActionRegistration(displayName = "#CTL_OpenDiscoveryAction", lazy = false) @NbBundle.Messages({"CTL_OpenDiscoveryAction=Discovery"}) @@ -68,7 +67,7 @@ public final class OpenDiscoveryAction extends CallableSystemAction implements P final DiscoveryDialog discDialog = DiscoveryDialog.getDiscoveryDialogInstance(); discDialog.cancelSearch(); DiscoveryUiUtils.displayErrorMessage(discDialog); - discDialog.setVisible(true); + discDialog.setVisible(true); }); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java index 52325da82a..2c9a4d4f41 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java @@ -127,7 +127,7 @@ final class ResultsPanel extends javax.swing.JPanel { }); //JIRA-TODO 6307 Add listener for domainSummaryViewer when 6782, 6773, and the other details area related stories are done } - + SearchData.Type getActiveType() { return resultType; } @@ -294,7 +294,7 @@ final class ResultsPanel extends javax.swing.JPanel { // Do nothing, case has been closed. return; } - + for (Result result : results) { DomainThumbnailWorker domainWorker = new DomainThumbnailWorker( currentCase, (ResultDomain) result); @@ -315,7 +315,7 @@ final class ResultsPanel extends javax.swing.JPanel { searchFilters = groupSelectedEvent.getFilters(); groupingAttribute = groupSelectedEvent.getGroupingAttr(); groupSort = groupSelectedEvent.getGroupSort(); - fileSortMethod = groupSelectedEvent.getFileSort(); + fileSortMethod = groupSelectedEvent.getResultSort(); selectedGroupKey = groupSelectedEvent.getGroupKey(); resultType = groupSelectedEvent.getResultType(); groupSize = groupSelectedEvent.getGroupSize(); @@ -839,7 +839,7 @@ final class ResultsPanel extends javax.swing.JPanel { domainWrapper.getResultDomain().getDomain(), ImageUtils.ICON_SIZE_LARGE ); - + Image thumbnail = domainSearch.getThumbnail(request); domainWrapper.setThumbnail(thumbnail); return null; From ad83e0304a6e5a212b906b3b8ce0fff22c18f503 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 17 Sep 2020 12:37:37 -0400 Subject: [PATCH 106/130] Add back bundle properties merged file for UI --- .../org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED index c238335352..8ecf93bed6 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED @@ -1,7 +1,7 @@ ArtifactTypeFilterPanel.selectionNeeded.text=At least one Result type must be selected. CTL_OpenDiscoveryAction=Discovery # {0} - dataSourceName -DataSourceModuleWrapper.exifModule.text=Exif Parser module was not run on data source: {0}\n +DataSourceModuleWrapper.exifModule.text=Picture Analyzer module was not run on data source: {0}\n # {0} - dataSourceName DataSourceModuleWrapper.fileTypeModule.text=File Type Identification module was not run on data source: {0}\n # {0} - dataSourceName From 6605be4ec873b8c6141b5b529f1746ac8aa8afb2 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 17 Sep 2020 12:49:08 -0400 Subject: [PATCH 107/130] add back preferred size for domain discovery dialog --- .../src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index 783fd1616f..f2f42bd113 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -145,7 +145,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { }); Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, this.new CasePropertyChangeListener()); IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, this.new ModuleChangeListener()); - + setPreferredSize(new java.awt.Dimension(1000, 650)); } /** From 12470bac604931e43d55903e129f51a8e34ec5a4 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 17 Sep 2020 14:35:47 -0400 Subject: [PATCH 108/130] null handling --- .../datamodel/AnalysisSummary.java | 6 ++++++ .../datamodel/PastCasesSummary.java | 6 +++++- .../datamodel/RecentFilesSummary.java | 11 +++++++++- .../datamodel/UserActivitySummary.java | 16 ++++++++++++++ .../ui/BaseDataSourceSummaryPanel.java | 21 ++++++++++++------- .../datasourcesummary/ui/ContainerPanel.java | 4 ++-- 6 files changed, 52 insertions(+), 12 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java index f3f436ae62..52df15f80f 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datasourcesummary.datamodel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -146,6 +147,11 @@ public class AnalysisSummary implements DefaultArtifactUpdateGovernor { */ private List> getCountsData(DataSource dataSource, BlackboardAttribute.Type keyType, ARTIFACT_TYPE... artifactTypes) throws SleuthkitCaseProviderException, TskCoreException { + + if (dataSource == null) { + return Collections.emptyList(); + } + List artifacts = new ArrayList<>(); SleuthkitCase skCase = provider.get(); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java index f6bfe5346b..3c3e12bad8 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java @@ -292,7 +292,7 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor { * * @param dataSource The data source. * - * @return The retrieved data. + * @return The retrieved data or null if null dataSource. * * @throws SleuthkitCaseProviderException * @throws TskCoreException @@ -300,6 +300,10 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor { public PastCasesResult getPastCasesData(DataSource dataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException { + if (dataSource == null) { + return null; + } + SleuthkitCase skCase = caseProvider.get(); List deviceArtifactCases = new ArrayList<>(); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java index 4dadb8e028..a1c08237fe 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java @@ -24,6 +24,7 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Locale; @@ -108,7 +109,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { */ public List getRecentlyOpenedDocuments(DataSource dataSource, int maxCount) throws SleuthkitCaseProviderException, TskCoreException { if (dataSource == null) { - throw new IllegalArgumentException("Failed to get recently opened documents given data source was null"); + return Collections.emptyList(); } List artifactList @@ -159,6 +160,10 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { * @throws SleuthkitCaseProviderException */ public List getRecentDownloads(DataSource dataSource, int maxCount) throws TskCoreException, SleuthkitCaseProviderException { + if (dataSource == null) { + return Collections.emptyList(); + } + List artifactList = DataSourceInfoUtilities.getArtifacts(provider.get(), new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD), @@ -206,6 +211,10 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { * @throws TskCoreException */ public List getRecentAttachments(DataSource dataSource, int maxCount) throws SleuthkitCaseProviderException, TskCoreException { + if (dataSource == null) { + return Collections.emptyList(); + } + return createListFromMap(buildAttachmentMap(dataSource), maxCount); } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java index 0f048a6ed0..aea54c7314 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java @@ -148,6 +148,10 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { */ public List getRecentDomains(DataSource dataSource, int count) throws TskCoreException, SleuthkitCaseProviderException { assertValidCount(count); + + if (dataSource == null) { + return Collections.emptyList(); + } Pair>> mostRecentAndGroups = getDomainGroupsAndMostRecent(dataSource); // if no recent domains, return accordingly @@ -306,6 +310,10 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { */ public List getMostRecentWebSearches(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException { assertValidCount(count); + + if (dataSource == null) { + return Collections.emptyList(); + } // get the artifacts List webSearchArtifacts = caseProvider.get().getBlackboard() @@ -390,6 +398,10 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { */ public List getRecentDevices(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException { assertValidCount(count); + + if (dataSource == null) { + return Collections.emptyList(); + } return DataSourceInfoUtilities.getArtifacts(caseProvider.get(), TYPE_DEVICE_ATTACHED, dataSource, TYPE_DATETIME, DataSourceInfoUtilities.SortOrder.DESCENDING, 0) @@ -475,6 +487,10 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { "DataSourceUserActivitySummary_getRecentAccounts_calllogMessage=Call Log",}) public List getRecentAccounts(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException { assertValidCount(count); + + if (dataSource == null) { + return Collections.emptyList(); + } Stream messageResults = caseProvider.get().getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_MESSAGE.getTypeID(), dataSource.getId()) .stream() diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java index a97682391d..727748ee4b 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java @@ -290,15 +290,20 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { * @param dataSource The data source argument. */ protected void fetchInformation(List> dataFetchComponents, DataSource dataSource) { - // create swing workers to run for each loadable item - List> workers = dataFetchComponents - .stream() - .map((components) -> new DataFetchWorker<>(components, dataSource)) - .collect(Collectors.toList()); + if (dataSource == null || !Case.isCaseOpen()) { + dataFetchComponents.forEach((item) -> item.getResultHandler() + .accept(DataFetchResult.getSuccessResult(null))); + } else { + // create swing workers to run for each loadable item + List> workers = dataFetchComponents + .stream() + .map((components) -> new DataFetchWorker<>(components, dataSource)) + .collect(Collectors.toList()); - // submit swing workers to run - if (!workers.isEmpty()) { - submit(workers); + // submit swing workers to run + if (!workers.isEmpty()) { + submit(workers); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java index d638524471..468d71e97e 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java @@ -123,14 +123,14 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { ); }, (result) -> { - if (result.getResultType() == ResultType.SUCCESS) { + if (result != null && result.getResultType() == ResultType.SUCCESS) { ContainerPanelData data = result.getData(); updateDetailsPanelData( data.getDataSource(), data.getUnallocatedFilesSize()); } else { logger.log(Level.WARNING, "An exception occurred while attempting to fetch data for the ContainerPanel.", - result.getException()); + (result == null) ? null : result.getException()); updateDetailsPanelData(null, null); } } From 727c7e9966a8b79f9d5ff07922e81243a1223a77 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 17 Sep 2020 14:50:46 -0400 Subject: [PATCH 109/130] 6858 remove unnecssary empty list check that causes exception to be thrown --- .../autopsy/discovery/search/SearchFiltering.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java index 27a2b42342..d29ecf6d3f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java @@ -615,13 +615,6 @@ public class SearchFiltering { @Override public List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { - - // We have to have run some kind of SQL filter before getting to this point, - // and should have checked afterward to see if the results were empty. - if (currentResults.isEmpty()) { - throw new DiscoveryException("Can not run on empty list"); // NON-NLS - } - // Set the frequency for each file DiscoveryAttributes.FrequencyAttribute freqAttr = new DiscoveryAttributes.FrequencyAttribute(); freqAttr.addAttributeToResultFiles(currentResults, caseDb, centralRepoDb); From 849228437055f06b1d25ad3cce509eca62e1efd0 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 17 Sep 2020 15:05:30 -0400 Subject: [PATCH 110/130] some other null checking --- .../autopsy/datasourcesummary/ui/ContainerPanel.java | 7 ++++--- .../uiutils/DefaultArtifactUpdateGovernor.java | 4 ++++ .../datasourcesummary/uiutils/IngestRunningLabel.java | 5 ++++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java index 468d71e97e..f8cd582996 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java @@ -125,9 +125,10 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { (result) -> { if (result != null && result.getResultType() == ResultType.SUCCESS) { ContainerPanelData data = result.getData(); - updateDetailsPanelData( - data.getDataSource(), - data.getUnallocatedFilesSize()); + DataSource dataSource = (data == null) ? null : data.getDataSource(); + Long unallocatedFileSize = (data == null) ? null : data.getUnallocatedFilesSize(); + + updateDetailsPanelData(dataSource, unallocatedFileSize); } else { logger.log(Level.WARNING, "An exception occurred while attempting to fetch data for the ContainerPanel.", (result == null) ? null : result.getException()); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DefaultArtifactUpdateGovernor.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DefaultArtifactUpdateGovernor.java index d664161696..b5003bd252 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DefaultArtifactUpdateGovernor.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DefaultArtifactUpdateGovernor.java @@ -36,6 +36,10 @@ public interface DefaultArtifactUpdateGovernor extends DefaultUpdateGovernor { @Override default boolean isRefreshRequired(ModuleDataEvent evt) { + if (evt == null || evt.getBlackboardArtifactType() == null) { + return false; + } + return getArtifactTypeIdsForRefresh().contains(evt.getBlackboardArtifactType().getTypeID()); } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java index 301ad2747d..1e24f0c7b5 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java @@ -63,7 +63,10 @@ public class IngestRunningLabel extends JPanel { // if listener is not initialized, initialize it. if (classListener == null) { classListener = (evt) -> { - + if (evt == null) { + return; + } + if (evt.getPropertyName().equals(IngestManager.IngestJobEvent.STARTED.toString())) { // ingest started notifyListeners(true); From 368b330e3c926291f5b68ea829f5e8cb7be93f11 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 17 Sep 2020 15:16:40 -0400 Subject: [PATCH 111/130] formatting --- .../datasourcesummary/datamodel/AnalysisSummary.java | 4 ++-- .../datamodel/PastCasesSummary.java | 2 +- .../datamodel/RecentFilesSummary.java | 4 ++-- .../datamodel/UserActivitySummary.java | 8 ++++---- .../ui/BaseDataSourceSummaryPanel.java | 5 +++-- .../autopsy/datasourcesummary/ui/ContainerPanel.java | 12 ++++++++---- .../uiutils/DefaultArtifactUpdateGovernor.java | 2 +- .../uiutils/IngestRunningLabel.java | 2 +- 8 files changed, 22 insertions(+), 17 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java index 52df15f80f..9d35e3d28d 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java @@ -147,11 +147,11 @@ public class AnalysisSummary implements DefaultArtifactUpdateGovernor { */ private List> getCountsData(DataSource dataSource, BlackboardAttribute.Type keyType, ARTIFACT_TYPE... artifactTypes) throws SleuthkitCaseProviderException, TskCoreException { - + if (dataSource == null) { return Collections.emptyList(); } - + List artifacts = new ArrayList<>(); SleuthkitCase skCase = provider.get(); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java index 3c3e12bad8..a304d367ff 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java @@ -303,7 +303,7 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor { if (dataSource == null) { return null; } - + SleuthkitCase skCase = caseProvider.get(); List deviceArtifactCases = new ArrayList<>(); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java index a1c08237fe..0a47e0ea6c 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java @@ -163,7 +163,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { if (dataSource == null) { return Collections.emptyList(); } - + List artifactList = DataSourceInfoUtilities.getArtifacts(provider.get(), new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD), @@ -214,7 +214,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { if (dataSource == null) { return Collections.emptyList(); } - + return createListFromMap(buildAttachmentMap(dataSource), maxCount); } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java index aea54c7314..2652a450ec 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java @@ -148,7 +148,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { */ public List getRecentDomains(DataSource dataSource, int count) throws TskCoreException, SleuthkitCaseProviderException { assertValidCount(count); - + if (dataSource == null) { return Collections.emptyList(); } @@ -310,7 +310,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { */ public List getMostRecentWebSearches(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException { assertValidCount(count); - + if (dataSource == null) { return Collections.emptyList(); } @@ -398,7 +398,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { */ public List getRecentDevices(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException { assertValidCount(count); - + if (dataSource == null) { return Collections.emptyList(); } @@ -487,7 +487,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { "DataSourceUserActivitySummary_getRecentAccounts_calllogMessage=Call Log",}) public List getRecentAccounts(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException { assertValidCount(count); - + if (dataSource == null) { return Collections.emptyList(); } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java index 727748ee4b..77b4a4c688 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java @@ -303,7 +303,7 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { // submit swing workers to run if (!workers.isEmpty()) { submit(workers); - } + } } } @@ -355,9 +355,10 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { protected String getDefaultNoIngestMessage(String moduleName) { return Bundle.BaseDataSourceSummaryPanel_defaultNotIngestMessage(moduleName); } - + /** * Utility method to return the IngestModuleCheckUtil. + * * @return The IngestModuleCheckUtil. */ protected IngestModuleCheckUtil getIngestModuleCheckUtil() { diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java index f8cd582996..8f11e0dcd3 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java @@ -127,11 +127,16 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { ContainerPanelData data = result.getData(); DataSource dataSource = (data == null) ? null : data.getDataSource(); Long unallocatedFileSize = (data == null) ? null : data.getUnallocatedFilesSize(); - + updateDetailsPanelData(dataSource, unallocatedFileSize); } else { - logger.log(Level.WARNING, "An exception occurred while attempting to fetch data for the ContainerPanel.", - (result == null) ? null : result.getException()); + if (result == null) { + logger.log(Level.WARNING, "No data fetch result was provided to the ContainerPanel."); + } else { + logger.log(Level.WARNING, "An exception occurred while attempting to fetch data for the ContainerPanel.", + result.getException()); + } + updateDetailsPanelData(null, null); } } @@ -142,7 +147,6 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { setDataSource(null); } - @Override protected void onNewDataSource(DataSource dataSource) { fetchInformation(dataSource); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DefaultArtifactUpdateGovernor.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DefaultArtifactUpdateGovernor.java index b5003bd252..390317a955 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DefaultArtifactUpdateGovernor.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DefaultArtifactUpdateGovernor.java @@ -39,7 +39,7 @@ public interface DefaultArtifactUpdateGovernor extends DefaultUpdateGovernor { if (evt == null || evt.getBlackboardArtifactType() == null) { return false; } - + return getArtifactTypeIdsForRefresh().contains(evt.getBlackboardArtifactType().getTypeID()); } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java index 1e24f0c7b5..0be1e85396 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/IngestRunningLabel.java @@ -66,7 +66,7 @@ public class IngestRunningLabel extends JPanel { if (evt == null) { return; } - + if (evt.getPropertyName().equals(IngestManager.IngestJobEvent.STARTED.toString())) { // ingest started notifyListeners(true); From ddfc5a1dbd4f0d0f9ac033fc7da9fd3032f47acc Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Thu, 17 Sep 2020 15:24:41 -0400 Subject: [PATCH 112/130] Update ILeappFileProcessor.java Remove stack trace and add attribute name and file name where the date parse error is occuring. --- .../modules/ileappanalyzer/ILeappFileProcessor.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/ileappanalyzer/ILeappFileProcessor.java b/Core/src/org/sleuthkit/autopsy/modules/ileappanalyzer/ILeappFileProcessor.java index 1bc80c9019..8c9c8c340b 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/ileappanalyzer/ILeappFileProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/ileappanalyzer/ILeappFileProcessor.java @@ -202,6 +202,7 @@ public final class ILeappFileProcessor { * * @param line a tsv line to process that was read * @param columnNumberToProcess Which columns to process in the tsv line + * @param fileName name of file begin processed * * @return */ @@ -220,7 +221,7 @@ public final class ILeappFileProcessor { break; } String attrType = attributeType.getValueType().getLabel().toUpperCase(); - checkAttributeType(bbattributes, attrType, columnValues, columnNumber, attributeType); + checkAttributeType(bbattributes, attrType, columnValues, columnNumber, attributeType, fileName); } catch (TskCoreException ex) { throw new IngestModuleException(String.format("Error getting Attribute type for Attribute Name %s", attributeName), ex); //NON-NLS } @@ -234,7 +235,8 @@ public final class ILeappFileProcessor { } - private void checkAttributeType(Collection bbattributes, String attrType, String[] columnValues, Integer columnNumber, BlackboardAttribute.Type attributeType) { + private void checkAttributeType(Collection bbattributes, String attrType, String[] columnValues, Integer columnNumber, BlackboardAttribute.Type attributeType, + String fileName) { if (attrType.matches("STRING")) { bbattributes.add(new BlackboardAttribute(attributeType, MODULE_NAME, columnValues[columnNumber])); } else if (attrType.matches("INTEGER")) { @@ -256,7 +258,7 @@ public final class ILeappFileProcessor { } catch (ParseException ex) { // catching error and displaying date that could not be parsed // we set the timestamp to 0 and continue on processing - logger.log(Level.WARNING, String.format("Failed to parse date/time %s for attribute.", columnValues[columnNumber]), ex); //NON-NLS + logger.log(Level.WARNING, String.format("Failed to parse date/time %s for attribute type %s in file %s.", columnValues[columnNumber], attributeType.getDisplayName(), fileName)); //NON-NLS } } else if (attrType.matches("JSON")) { From 6cbebfb33fb20e7d9266091fcde28f93bcc69b57 Mon Sep 17 00:00:00 2001 From: apriestman Date: Thu, 17 Sep 2020 15:29:14 -0400 Subject: [PATCH 113/130] Change to Bundle message. Convert to lower case. --- .../recentactivity/Bundle.properties-MERGED | 3 +++ .../recentactivity/ExtractWebAccountType.java | 17 +++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED index a69181f228..4456663bd8 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED @@ -72,6 +72,9 @@ ExtractSru_process_errormsg_find_software_hive=Unable to find SOFTWARE HIVE file ExtractSru_process_errormsg_find_srudb_dat=Unable to find srudb.dat file ExtractSru_process_errormsg_write_software_hive=Unable to write SOFTWARE HIVE file ExtractSru_process_errormsg_write_srudb_dat=Unable to write srudb.dat file +ExtractWebAccountType.role.admin=Administrator role +ExtractWebAccountType.role.moderator=Moderator role +ExtractWebAccountType.role.user=User role ExtractZone_Internet=Internet Zone ExtractZone_Local_Intranet=Local Intranet Zone ExtractZone_Local_Machine=Local Machine Zone diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractWebAccountType.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractWebAccountType.java index c4fbb8fcba..0c05907fb6 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractWebAccountType.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractWebAccountType.java @@ -95,8 +95,8 @@ class ExtractWebAccountType extends Extract { return; } - String url = urlAttr.getValueString(); - String domain = domainAttr.getValueString(); + String url = urlAttr.getValueString().toLowerCase(); + String domain = domainAttr.getValueString().toLowerCase(); findMyBbRole(url, domain, artifact, roleProcessor); findPhpBbRole(url, domain, artifact, roleProcessor); @@ -250,7 +250,7 @@ class ExtractWebAccountType extends Extract { continue; } - String desc = role.getRole().getDesc() + " role (" + role.getPlatform() + ")"; // NON-NLS + String desc = role.getRole().getDesc() + " (" + role.getPlatform() + ")"; // NON-NLS Collection bbattributes = new ArrayList<>(); bbattributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, @@ -274,10 +274,15 @@ class ExtractWebAccountType extends Extract { /** * Possible roles with rank and display name. */ + @NbBundle.Messages({ + "ExtractWebAccountType.role.user=User role", + "ExtractWebAccountType.role.moderator=Moderator role", + "ExtractWebAccountType.role.admin=Administrator role" + }) private enum Role { - USER("User", 0), - MOD("Moderator", 1), - ADMIN("Administrator", 2); + USER(Bundle.ExtractWebAccountType_role_user(), 0), + MOD(Bundle.ExtractWebAccountType_role_moderator(), 1), + ADMIN(Bundle.ExtractWebAccountType_role_admin(), 2); private final String desc; private final int rank; From 04be4fe897de1dc5f67f48f0a2dcda3a88cd4635 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 17 Sep 2020 17:38:55 -0400 Subject: [PATCH 114/130] 6837 change disabling of details area to re-enable size adjustment --- .../discovery/ui/DiscoveryTopComponent.java | 27 ++++++++++------- .../discovery/ui/ResultsSplitPaneDivider.java | 29 ++----------------- 2 files changed, 18 insertions(+), 38 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java index 1a36ab8bce..ff3e0cb7cd 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java @@ -38,6 +38,7 @@ import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; +import static org.sleuthkit.autopsy.discovery.search.SearchData.Type.DOMAIN; /** * Create a dialog for displaying the Discovery results. @@ -108,7 +109,7 @@ public final class DiscoveryTopComponent extends TopComponent { BasicSplitPaneDividerImpl(BasicSplitPaneUI ui) { super(ui); this.setLayout(new BorderLayout()); - this.add(new ResultsSplitPaneDivider(resultsPanel)); + this.add(new ResultsSplitPaneDivider()); } private static final long serialVersionUID = 1L; @@ -258,17 +259,19 @@ public final class DiscoveryTopComponent extends TopComponent { */ @Subscribe void handleDetailsVisibleEvent(DiscoveryEventUtils.DetailsVisibleEvent detailsVisibleEvent) { - if (animator != null && animator.isRunning()) { - animator.stop(); - animator = null; + if (resultsPanel.getActiveType() != DOMAIN) { + if (animator != null && animator.isRunning()) { + animator.stop(); + animator = null; + } + dividerLocation = rightSplitPane.getDividerLocation(); + if (detailsVisibleEvent.isShowDetailsArea()) { + animator = new SwingAnimator(new ShowDetailsAreaCallback()); + } else { + animator = new SwingAnimator(new HideDetailsAreaCallback()); + } + animator.start(); } - dividerLocation = rightSplitPane.getDividerLocation(); - if (detailsVisibleEvent.isShowDetailsArea()) { - animator = new SwingAnimator(new ShowDetailsAreaCallback()); - } else { - animator = new SwingAnimator(new HideDetailsAreaCallback()); - } - animator.start(); } /** @@ -286,6 +289,8 @@ public final class DiscoveryTopComponent extends TopComponent { newSearchButton.setText(Bundle.DiscoveryTopComponent_cancelButton_text()); progressMessageTextArea.setForeground(Color.red); progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchInProgress_text(searchStartedEvent.getType().name())); + rightSplitPane.getComponent(1).setVisible(searchStartedEvent.getType() != DOMAIN); + rightSplitPane.getComponent(2).setVisible(searchStartedEvent.getType() != DOMAIN); } /** diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.java index 4306e592be..cffb2dac7f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsSplitPaneDivider.java @@ -19,10 +19,8 @@ package org.sleuthkit.autopsy.discovery.ui; import java.awt.Cursor; -import java.awt.event.MouseEvent; -import java.awt.event.MouseMotionListener; + import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; -import org.sleuthkit.autopsy.discovery.search.SearchData; /** * Panel for separating the results list from the details area. @@ -30,29 +28,12 @@ import org.sleuthkit.autopsy.discovery.search.SearchData; final class ResultsSplitPaneDivider extends javax.swing.JPanel { private static final long serialVersionUID = 1L; - private final ResultsPanel resultsPanel; /** * Creates new form LabeledSplitPaneDivider. */ - ResultsSplitPaneDivider(ResultsPanel resultsPanel) { + ResultsSplitPaneDivider() { initComponents(); - this.resultsPanel = resultsPanel; - this.addMouseMotionListener(new MouseMotionListener() { - @Override - public void mouseDragged(MouseEvent e) { - if (resultsPanel.getActiveType() == SearchData.Type.DOMAIN) { - e.consume(); - } - } - - @Override - public void mouseMoved(MouseEvent e) { - if (resultsPanel.getActiveType() == SearchData.Type.DOMAIN) { - e.consume(); - } - } - }); } /** @@ -129,16 +110,10 @@ final class ResultsSplitPaneDivider extends javax.swing.JPanel { }// //GEN-END:initComponents private void showButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showButtonActionPerformed - if (resultsPanel.getActiveType() == SearchData.Type.DOMAIN) { - return; - } DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.DetailsVisibleEvent(true)); }//GEN-LAST:event_showButtonActionPerformed private void hideButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_hideButtonActionPerformed - if (resultsPanel.getActiveType() == SearchData.Type.DOMAIN) { - return; - } DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.DetailsVisibleEvent(false)); }//GEN-LAST:event_hideButtonActionPerformed From 180f005b6bd05aa7965467dbeb48979a4236dde3 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 17 Sep 2020 18:49:29 -0400 Subject: [PATCH 115/130] 6861 prevent typing or pasting date entry --- .../autopsy/discovery/ui/DateFilterPanel.form | 8 ++++---- .../autopsy/discovery/ui/DateFilterPanel.java | 17 +++++++++++------ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form index 8ecca7e27b..b52fce7d28 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form @@ -104,7 +104,10 @@ - + + + + @@ -114,9 +117,6 @@ - - - diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java index 668e441f95..930eda4f6f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.discovery.ui; + import java.awt.event.ActionListener; import java.time.LocalDate; import java.time.Period; @@ -26,7 +27,7 @@ import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; -import javax.swing.SpinnerNumberModel; +import javax.swing.JSpinner; import javax.swing.event.ListSelectionListener; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.communications.Utils; @@ -38,7 +39,6 @@ import org.sleuthkit.autopsy.discovery.search.SearchFiltering; class DateFilterPanel extends AbstractDiscoveryFilterPanel { private static final long serialVersionUID = 1L; - private final SpinnerNumberModel numberModel; private static final long SECS_PER_DAY = 86400; /** @@ -47,10 +47,14 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { @NbBundle.Messages({"# {0} - timeZone", "DateFilterPanel.dateRange.text=Date Range ({0}):"}) DateFilterPanel() { - // numberModel is used in initComponents - numberModel = new SpinnerNumberModel(10, 1, Integer.MAX_VALUE, 1); initComponents(); rangeRadioButton.setText(Bundle.DateFilterPanel_dateRange_text(Utils.getUserPreferredZoneId().toString())); + //Disable manual entry in the spinner so it is limited to 60 days + //if a user wants farther back than that one would expect date range filter options would be more appealing + ((JSpinner.DefaultEditor) daysSpinner.getEditor()).getTextField().setEditable(false); + //Disable manual entry in the date pickers + startDatePicker.getComponentDateTextField().setEditable(false); + endDatePicker.getComponentDateTextField().setEditable(false); } /** @@ -65,7 +69,7 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { buttonGroup1 = new javax.swing.ButtonGroup(); dateFilterCheckBox = new javax.swing.JCheckBox(); jPanel1 = new javax.swing.JPanel(); - daysSpinner = new javax.swing.JSpinner(numberModel); + daysSpinner = new javax.swing.JSpinner(); daysLabel = new javax.swing.JLabel(); mostRecentRadioButton = new javax.swing.JRadioButton(); startCheckBox = new javax.swing.JCheckBox(); @@ -81,7 +85,8 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { } }); - daysSpinner.setModel(new javax.swing.SpinnerNumberModel(1, 1, null, 1)); + daysSpinner.setModel(new javax.swing.SpinnerNumberModel(7, 1, 60, 1)); + daysSpinner.setEditor(new javax.swing.JSpinner.NumberEditor(daysSpinner, "")); daysSpinner.setEnabled(false); daysSpinner.setPreferredSize(new java.awt.Dimension(75, 26)); daysSpinner.setValue(7); From f3d3d38d4e1caca9b6bbadec160b87dbe3dc190b Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 17 Sep 2020 20:49:59 -0400 Subject: [PATCH 116/130] Added banning of localhost and aliases --- .../discovery/search/DomainSearchCacheLoader.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java index a1f795864d..a253e6f893 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java @@ -26,6 +26,8 @@ import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; +import java.util.HashSet; import java.util.Map; import java.util.Optional; import java.util.StringJoiner; @@ -230,6 +232,11 @@ class DomainSearchCacheLoader extends CacheLoader bannedDomains = new HashSet() {{ + add("localhost"); + add("127.0.0.1"); + }}; /** * Construct a new DomainCallback object. @@ -248,6 +255,13 @@ class DomainSearchCacheLoader extends CacheLoader Date: Thu, 17 Sep 2020 21:10:32 -0400 Subject: [PATCH 117/130] only log exceptions in handler of result and not data fetch worker itself --- .../autopsy/datasourcesummary/uiutils/DataFetchWorker.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DataFetchWorker.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DataFetchWorker.java index a89b273fcc..9dd5d0ac27 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DataFetchWorker.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DataFetchWorker.java @@ -140,9 +140,6 @@ public class DataFetchWorker extends SwingWorker { } } - // otherwise, there is an error to log - logger.log(Level.WARNING, "There was an error while fetching results.", ex); - // and pass the result to the client resultHandler.accept(DataFetchResult.getErrorResult(inner)); return; From c39a0f94a9177aa6e66c4bd9be95f031f4501f3c Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 17 Sep 2020 21:11:38 -0400 Subject: [PATCH 118/130] removed unused import --- .../autopsy/datasourcesummary/uiutils/DataFetchWorker.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DataFetchWorker.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DataFetchWorker.java index 9dd5d0ac27..10ed19b87a 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DataFetchWorker.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DataFetchWorker.java @@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.datasourcesummary.uiutils; import java.util.concurrent.ExecutionException; import java.util.function.Consumer; -import java.util.logging.Level; import javax.swing.SwingWorker; import org.sleuthkit.autopsy.coreutils.Logger; From bd544932b5d3dce18f6ee4d6afc394a61d62783b Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 18 Sep 2020 10:28:10 -0400 Subject: [PATCH 119/130] 6861 check start before end, max spinner value 100k --- .../discovery/ui/Bundle.properties-MERGED | 1 + .../autopsy/discovery/ui/DateFilterPanel.form | 2 +- .../autopsy/discovery/ui/DateFilterPanel.java | 30 +++++++++++++++++-- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED index 8ecf93bed6..08e22e9826 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED @@ -9,6 +9,7 @@ DataSourceModuleWrapper.hashModule.text=Hash Lookup module was not run on data s # {0} - timeZone DateFilterPanel.dateRange.text=Date Range ({0}): DateFilterPanel.invalidRange.text=Range or Only Last must be selected +DateFilterPanel.startAfterEnd.text=Start date should be before the end date when both are enabled. DateFilterPanel.startOrEndNeeded.text=A start or end date must be specified to use the range filter DiscoveryDialog.name.text=Discovery DiscoveryTopComponent.cancelButton.text=Cancel Search diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form index b52fce7d28..276a4f9ef5 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.form @@ -104,7 +104,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java index 930eda4f6f..81777b5a40 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java @@ -18,7 +18,9 @@ */ package org.sleuthkit.autopsy.discovery.ui; - +import com.github.lgooddatepicker.optionalusertools.DateChangeListener; +import com.github.lgooddatepicker.zinternaltools.DateChangeEvent; +import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.time.LocalDate; import java.time.Period; @@ -85,7 +87,7 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { } }); - daysSpinner.setModel(new javax.swing.SpinnerNumberModel(7, 1, 60, 1)); + daysSpinner.setModel(new javax.swing.SpinnerNumberModel(7, 1, 100000, 1)); daysSpinner.setEditor(new javax.swing.JSpinner.NumberEditor(daysSpinner, "")); daysSpinner.setEnabled(false); daysSpinner.setPreferredSize(new java.awt.Dimension(75, 26)); @@ -259,6 +261,18 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { endCheckBox.addActionListener(actionListener); rangeRadioButton.addActionListener(actionListener); mostRecentRadioButton.addActionListener(actionListener); + startDatePicker.addDateChangeListener(new DateChangeListener() { + @Override + public void dateChanged(DateChangeEvent event) { + actionListener.actionPerformed(new ActionEvent(startDatePicker, ActionEvent.ACTION_PERFORMED, "StartDateChanged")); + } + }); + endDatePicker.addDateChangeListener(new DateChangeListener() { + @Override + public void dateChanged(DateChangeEvent event) { + actionListener.actionPerformed(new ActionEvent(endDatePicker, ActionEvent.ACTION_PERFORMED, "EndDateChanged")); + } + }); } @Override @@ -281,10 +295,17 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { for (ActionListener listener : endCheckBox.getActionListeners()) { endCheckBox.removeActionListener(listener); } + for (DateChangeListener listener : endDatePicker.getDateChangeListeners()) { + endDatePicker.removeDateChangeListener(listener); + } + for (DateChangeListener listener : startDatePicker.getDateChangeListeners()) { + startDatePicker.removeDateChangeListener(listener); + } } @NbBundle.Messages({"DateFilterPanel.invalidRange.text=Range or Only Last must be selected", - "DateFilterPanel.startOrEndNeeded.text=A start or end date must be specified to use the range filter"}) + "DateFilterPanel.startOrEndNeeded.text=A start or end date must be specified to use the range filter", + "DateFilterPanel.startAfterEnd.text=Start date should be before the end date when both are enabled."}) @Override String checkForError() { if (dateFilterCheckBox.isSelected()) { @@ -292,6 +313,9 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { return Bundle.DateFilterPanel_invalidRange_text(); } else if (rangeRadioButton.isSelected() && !(startCheckBox.isSelected() || endCheckBox.isSelected())) { return Bundle.DateFilterPanel_startOrEndNeeded_text(); + } else if (startCheckBox.isSelected() && endCheckBox.isSelected() && startDatePicker.getDate().isAfter(endDatePicker.getDate())) { + //if the dates are equal it will effectively search just that day due to the rounding up of the end date in the getFilter code + return Bundle.DateFilterPanel_startAfterEnd_text(); } } return ""; From 4baf7faaf77450775d4a489d9744806a44211a79 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Fri, 18 Sep 2020 11:24:31 -0400 Subject: [PATCH 120/130] Added in post processing for attribute types --- .../discovery/search/DiscoveryAttributes.java | 18 +++++++++++------- .../search/DomainSearchCacheLoader.java | 12 ++++++++++++ .../autopsy/discovery/search/FileSearch.java | 2 +- .../discovery/search/SearchFiltering.java | 2 +- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java index 4acb503485..637e982f98 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java @@ -80,7 +80,7 @@ public class DiscoveryAttributes { * * @throws DiscoveryException */ - public void addAttributeToResultFiles(List results, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { + public void addAttributeToResults(List results, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { // Default is to do nothing } } @@ -151,7 +151,7 @@ public class DiscoveryAttributes { } @Override - public void addAttributeToResultFiles(List results, SleuthkitCase caseDb, + public void addAttributeToResults(List results, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { // Get pairs of (object ID, keyword list name) for all files in the list of files that have @@ -231,7 +231,7 @@ public class DiscoveryAttributes { } @Override - public void addAttributeToResultFiles(List results, SleuthkitCase caseDb, + public void addAttributeToResults(List results, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { if (centralRepoDb == null) { for (Result result : results) { @@ -279,6 +279,10 @@ public class DiscoveryAttributes { } } else { ResultDomain domainInstance = (ResultDomain) result; + if (domainInstance.getFrequency() != SearchData.Frequency.UNKNOWN) { + // Frequency already calculated, skipping... + continue; + } domainsToQuery.add(domainInstance); if (domainsToQuery.size() == DOMAIN_BATCH_SIZE) { @@ -442,7 +446,7 @@ public class DiscoveryAttributes { } @Override - public void addAttributeToResultFiles(List results, SleuthkitCase caseDb, + public void addAttributeToResults(List results, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { // Get pairs of (object ID, hash set name) for all files in the list of files that have @@ -517,7 +521,7 @@ public class DiscoveryAttributes { } @Override - public void addAttributeToResultFiles(List results, SleuthkitCase caseDb, + public void addAttributeToResults(List results, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { // Get pairs of (object ID, interesting item set name) for all files in the list of files that have @@ -629,7 +633,7 @@ public class DiscoveryAttributes { } @Override - public void addAttributeToResultFiles(List results, SleuthkitCase caseDb, + public void addAttributeToResults(List results, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { // Get pairs of (object ID, object type name) for all files in the list of files that have @@ -705,7 +709,7 @@ public class DiscoveryAttributes { } @Override - public void addAttributeToResultFiles(List results, SleuthkitCase caseDb, + public void addAttributeToResults(List results, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { try { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java index c0fe5d4269..99948592bf 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java @@ -66,6 +66,18 @@ class DomainSearchCacheLoader extends CacheLoader searchAttributes = new ArrayList<>(); + searchAttributes.add(key.getGroupAttributeType()); + searchAttributes.addAll(key.getFileSortingMethod().getRequiredAttributes()); + + for (AttributeType attr : searchAttributes) { + attr.addAttributeToResults(domainResults, + key.getSleuthkitCase(), key.getCentralRepository()); + } // Sort the ResultDomains by the requested criteria. final SearchResults searchResults = new SearchResults( diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java index aea0d18249..20a2ccfb62 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java @@ -301,7 +301,7 @@ public class FileSearch { private static void addAttributes(List attrs, List results, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { for (AttributeType attr : attrs) { - attr.addAttributeToResultFiles(results, caseDb, centralRepoDb); + attr.addAttributeToResults(results, caseDb, centralRepoDb); } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java index d29ecf6d3f..dd2609a56a 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java @@ -617,7 +617,7 @@ public class SearchFiltering { CentralRepository centralRepoDb) throws DiscoveryException { // Set the frequency for each file DiscoveryAttributes.FrequencyAttribute freqAttr = new DiscoveryAttributes.FrequencyAttribute(); - freqAttr.addAttributeToResultFiles(currentResults, caseDb, centralRepoDb); + freqAttr.addAttributeToResults(currentResults, caseDb, centralRepoDb); // If the frequency matches the filter, add the file to the results List frequencyResults = new ArrayList<>(); From a61cca12e0337846ef6002fd994b146fc5b34d62 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 18 Sep 2020 15:04:22 -0400 Subject: [PATCH 121/130] 6862 update messages for no domain results --- .../discovery/ui/Bundle.properties-MERGED | 3 ++- .../autopsy/discovery/ui/GroupListPanel.java | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED index 8ecf93bed6..93f76eda75 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED @@ -46,7 +46,8 @@ DomainSummaryPanel.downloads.text=Files downloaded: DomainSummaryPanel.loadingImages.text=Loading thumbnail... DomainSummaryPanel.pages.text=Pages in past 60 days: DomainSummaryPanel.totalPages.text=Total visits: -GroupsListPanel.noResults.message.text=No results were found for the selected filters.\n\nReminder:\n -The File Type Identification module must be run on each data source you want to find results in.\n -The Hash Lookup module must be run on each data source if you want to filter by past occurrence.\n -The Exif module must be run on each data source if you are filtering by User Created content. +GroupsListPanel.noDomainResults.message.text=No domains were found for the selected filters.\n\nReminder:\n -The Recent Activity module must be run on each data source you want to find results in.\n -The Central Repository module must be run on each data source if you want to filter or sort by past occurrences.\n -The iOS Analyzer (iLEAPP) module must be run on each data source which contains data from an iOS device.\n +GroupsListPanel.noFileResults.message.text=No files were found for the selected filters.\n\nReminder:\n -The File Type Identification module must be run on each data source you want to find results in.\n -The Hash Lookup module must be run on each data source if you want to filter by past occurrence.\n -The Picture Analyzer module must be run on each data source if you are filtering by User Created content. GroupsListPanel.noResults.title.text=No results found ImageThumbnailPanel.isDeleted.text=All instances of file are deleted. # {0} - otherInstanceCount diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java index b40d77ef63..714d5202f0 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java @@ -37,6 +37,7 @@ import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; import org.sleuthkit.autopsy.discovery.search.Group; import org.sleuthkit.autopsy.discovery.search.ResultsSorter; import org.sleuthkit.autopsy.discovery.search.SearchData.Type; +import static org.sleuthkit.autopsy.discovery.search.SearchData.Type.DOMAIN; /** * Panel to display the list of groups which are provided by a search. @@ -70,11 +71,16 @@ final class GroupListPanel extends javax.swing.JPanel { groupKeyList.setListData(new GroupKey[0]); } - @Messages({"GroupsListPanel.noResults.message.text=No results were found for the selected filters.\n\n" + @Messages({"GroupsListPanel.noFileResults.message.text=No files were found for the selected filters.\n\n" + "Reminder:\n" + " -The File Type Identification module must be run on each data source you want to find results in.\n" + " -The Hash Lookup module must be run on each data source if you want to filter by past occurrence.\n" - + " -The Exif module must be run on each data source if you are filtering by User Created content.", + + " -The Picture Analyzer module must be run on each data source if you are filtering by User Created content.", + "GroupsListPanel.noDomainResults.message.text=No domains were found for the selected filters.\n\n" + + "Reminder:\n" + + " -The Recent Activity module must be run on each data source you want to find results in.\n" + + " -The Central Repository module must be run on each data source if you want to filter or sort by past occurrences.\n" + + " -The iOS Analyzer (iLEAPP) module must be run on each data source which contains data from an iOS device.\n", "GroupsListPanel.noResults.title.text=No results found"}) /** * Subscribe to and update list of groups in response to @@ -93,9 +99,14 @@ final class GroupListPanel extends javax.swing.JPanel { SwingUtilities.invokeLater(() -> { if (groupKeyList.getModel().getSize() > 0) { groupKeyList.setSelectedIndex(0); + } else if (type == DOMAIN) { + JOptionPane.showMessageDialog(DiscoveryTopComponent.getTopComponent(), + Bundle.GroupsListPanel_noDomainResults_message_text(), + Bundle.GroupsListPanel_noResults_title_text(), + JOptionPane.PLAIN_MESSAGE); } else { JOptionPane.showMessageDialog(DiscoveryTopComponent.getTopComponent(), - Bundle.GroupsListPanel_noResults_message_text(), + Bundle.GroupsListPanel_noFileResults_message_text(), Bundle.GroupsListPanel_noResults_title_text(), JOptionPane.PLAIN_MESSAGE); } From 4f87563a27904bc54a048d33b92eeda8235e3156 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Fri, 18 Sep 2020 15:21:26 -0400 Subject: [PATCH 122/130] The changed the ingestProfile argument --- .../CommandLineOptionProcessor.java | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineOptionProcessor.java b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineOptionProcessor.java index 350e99c598..ad84bdcd0f 100755 --- a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineOptionProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineOptionProcessor.java @@ -49,8 +49,7 @@ public class CommandLineOptionProcessor extends OptionProcessor { private final Option dataSourceObjectIdOption = Option.requiredArgument('i', "dataSourceObjectId"); private final Option addDataSourceCommandOption = Option.withoutArgument('a', "addDataSource"); private final Option caseDirOption = Option.requiredArgument('d', "caseDir"); - private final Option runIngestCommandOption = Option.withoutArgument('r', "runIngest"); - private final Option ingestProfileOption = Option.requiredArgument('p', "ingestProfile"); + private final Option runIngestCommandOption = Option.optionalArgument('r', "runIngest"); private final Option listAllDataSourcesCommandOption = Option.withoutArgument('l', "listAllDataSources"); private final Option generateReportsOption = Option.optionalArgument('g', "generateReports"); private final Option defaultArgument = Option.defaultArguments(); @@ -76,7 +75,6 @@ public class CommandLineOptionProcessor extends OptionProcessor { set.add(dataSourceObjectIdOption); set.add(caseDirOption); set.add(runIngestCommandOption); - set.add(ingestProfileOption); set.add(listAllDataSourcesCommandOption); set.add(generateReportsOption); set.add(defaultArgument); @@ -205,21 +203,6 @@ public class CommandLineOptionProcessor extends OptionProcessor { } } - String ingestProfile = ""; - if (values.containsKey(ingestProfileOption)) { - - argDirs = values.get(ingestProfileOption); - if (argDirs.length < 1) { - handleError("Argument missing from 'ingestProfile' option"); - } - ingestProfile = argDirs[0]; - - // verify inputs - if (ingestProfile == null || ingestProfile.isEmpty()) { - handleError("Missing argument 'ingestProfile'"); - } - } - // Create commands in order in which they should be executed: // First create the "CREATE_CASE" command, if present if (values.containsKey(createCaseCommandOption)) { @@ -263,9 +246,15 @@ public class CommandLineOptionProcessor extends OptionProcessor { runFromCommandLine = true; } + String ingestProfile = ""; // Add RUN_INGEST command, if present if (values.containsKey(runIngestCommandOption)) { + argDirs = values.get(runIngestCommandOption); + if(argDirs != null && argDirs.length > 0) { + ingestProfile = argDirs[0]; + } + // 'caseDir' must only be specified if the case is not being created during the current run if (!values.containsKey(createCaseCommandOption) && caseDir.isEmpty()) { // new case is not being created during this run, so 'caseDir' should have been specified From 36bc4e02ec6d154de3aac98baf823cf9c5504364 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 18 Sep 2020 15:23:12 -0400 Subject: [PATCH 123/130] 6867 fix data source message, change to bundle messages --- .../autopsy/discovery/ui/Bundle.properties-MERGED | 7 +++++++ .../autopsy/discovery/ui/DataSourceFilterPanel.java | 4 +++- .../sleuthkit/autopsy/discovery/ui/HashSetFilterPanel.java | 4 +++- .../autopsy/discovery/ui/InterestingItemsFilterPanel.java | 4 +++- .../autopsy/discovery/ui/ObjectDetectedFilterPanel.java | 5 +++-- .../autopsy/discovery/ui/ParentFolderFilterPanel.java | 4 +++- .../autopsy/discovery/ui/PastOccurrencesFilterPanel.java | 4 +++- .../sleuthkit/autopsy/discovery/ui/SizeFilterPanel.java | 4 +++- 8 files changed, 28 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED index 8ecf93bed6..83ced881dc 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED @@ -1,5 +1,6 @@ ArtifactTypeFilterPanel.selectionNeeded.text=At least one Result type must be selected. CTL_OpenDiscoveryAction=Discovery +DataSourceFilterPanel.error.text=At least one data source must be selected. # {0} - dataSourceName DataSourceModuleWrapper.exifModule.text=Picture Analyzer module was not run on data source: {0}\n # {0} - dataSourceName @@ -48,9 +49,14 @@ DomainSummaryPanel.pages.text=Pages in past 60 days: DomainSummaryPanel.totalPages.text=Total visits: GroupsListPanel.noResults.message.text=No results were found for the selected filters.\n\nReminder:\n -The File Type Identification module must be run on each data source you want to find results in.\n -The Hash Lookup module must be run on each data source if you want to filter by past occurrence.\n -The Exif module must be run on each data source if you are filtering by User Created content. GroupsListPanel.noResults.title.text=No results found +HashSetFilterPanel.error.text=At least one hash set name must be selected. ImageThumbnailPanel.isDeleted.text=All instances of file are deleted. # {0} - otherInstanceCount ImageThumbnailPanel.nameLabel.more.text=\ and {0} more +InterestingItemsFilterPanel.error.text=At least one interesting file set name must be selected. +ObjectDetectedFilterPanel.error.text=At least one object type name must be selected. +ParentFolderFilterPanel.error.text=At least one parent path must be entered. +PastOccurrencesFilterPanel.error.text=At least one value in the past occurrence filter must be selected. # {0} - currentPage # {1} - totalPages ResultsPanel.currentPage.displayValue=Page: {0} of {1} @@ -76,6 +82,7 @@ ResultsPanel.invalidPageNumber.title=Invalid Page Number ResultsPanel.openInExternalViewer.name=Open in External Viewer ResultsPanel.unableToCreate.text=Unable to create summary. ResultsPanel.viewFileInDir.name=View File in Directory +SizeFilterPanel.error.text=At least one size must be selected. VideoFilterPanel.videoFiltersSplitPane.border.title=Step 2: Filter which videos to show DataSourceFilterPanel.dataSourceCheckbox.text=Data Source: ParentFolderFilterPanel.parentLabel.text_1=(All will be used) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DataSourceFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DataSourceFilterPanel.java index f9b4ab9d27..ec4b819696 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DataSourceFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DataSourceFilterPanel.java @@ -26,6 +26,7 @@ import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.discovery.search.SearchFiltering; @@ -188,10 +189,11 @@ final class DataSourceFilterPanel extends AbstractDiscoveryFilterPanel { } } + @NbBundle.Messages({"DataSourceFilterPanel.error.text=At least one data source must be selected."}) @Override String checkForError() { if (dataSourceCheckbox.isSelected() && dataSourceList.getSelectedValuesList().isEmpty()) { - return "At least one size must be selected"; + return Bundle.DataSourceFilterPanel_error_text(); } return ""; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/HashSetFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/HashSetFilterPanel.java index a890edcd4e..4698c43dc3 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/HashSetFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/HashSetFilterPanel.java @@ -25,6 +25,7 @@ import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.discovery.search.SearchFiltering; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -149,10 +150,11 @@ final class HashSetFilterPanel extends AbstractDiscoveryFilterPanel { return null; } + @NbBundle.Messages({"HashSetFilterPanel.error.text=At least one hash set name must be selected."}) @Override String checkForError() { if (hashSetCheckbox.isSelected() && hashSetList.getSelectedValuesList().isEmpty()) { - return "At least one hash set name must be selected"; + return Bundle.HashSetFilterPanel_error_text(); } return ""; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/InterestingItemsFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/InterestingItemsFilterPanel.java index 0d102141f0..b77956937d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/InterestingItemsFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/InterestingItemsFilterPanel.java @@ -25,6 +25,7 @@ import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.discovery.search.SearchFiltering; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -144,10 +145,11 @@ final class InterestingItemsFilterPanel extends AbstractDiscoveryFilterPanel { return null; } + @NbBundle.Messages({"InterestingItemsFilterPanel.error.text=At least one interesting file set name must be selected."}) @Override String checkForError() { if (interestingItemsCheckbox.isSelected() && interestingItemsList.getSelectedValuesList().isEmpty()) { - return "At least one interesting file set name must be selected"; + return Bundle.InterestingItemsFilterPanel_error_text(); } return ""; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ObjectDetectedFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ObjectDetectedFilterPanel.java index 09cc912e69..eb1c1525c5 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ObjectDetectedFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ObjectDetectedFilterPanel.java @@ -25,6 +25,7 @@ import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.discovery.search.SearchFiltering; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -154,11 +155,11 @@ final class ObjectDetectedFilterPanel extends AbstractDiscoveryFilterPanel { JLabel getAdditionalLabel() { return null; } - + @NbBundle.Messages({"ObjectDetectedFilterPanel.error.text=At least one object type name must be selected."}) @Override String checkForError() { if (objectsCheckbox.isSelected() && objectsList.getSelectedValuesList().isEmpty()) { - return "At least one object type name must be selected"; + return Bundle.ObjectDetectedFilterPanel_error_text(); } return ""; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ParentFolderFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ParentFolderFilterPanel.java index 97015abc92..a2a0d9615f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ParentFolderFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ParentFolderFilterPanel.java @@ -25,6 +25,7 @@ import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.discovery.search.SearchFiltering; import org.sleuthkit.autopsy.discovery.search.SearchFiltering.ParentSearchTerm; @@ -279,11 +280,12 @@ final class ParentFolderFilterPanel extends AbstractDiscoveryFilterPanel { return parentLabel; } + @NbBundle.Messages({"ParentFolderFilterPanel.error.text=At least one parent path must be entered."}) @Override String checkForError() { // Parent uses everything in the box if (parentCheckbox.isSelected() && getParentPaths().isEmpty()) { - return "At least one parent path must be entered"; + return Bundle.ParentFolderFilterPanel_error_text(); } return ""; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java index 648566a69f..b19c793556 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/PastOccurrencesFilterPanel.java @@ -22,6 +22,7 @@ import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.discovery.search.AbstractFilter; import org.sleuthkit.autopsy.discovery.search.SearchData; @@ -153,10 +154,11 @@ final class PastOccurrencesFilterPanel extends AbstractDiscoveryFilterPanel { return null; } + @NbBundle.Messages({"PastOccurrencesFilterPanel.error.text=At least one value in the past occurrence filter must be selected."}) @Override String checkForError() { if (pastOccurrencesCheckbox.isSelected() && crFrequencyList.getSelectedValuesList().isEmpty()) { - return "At least one value in the past occurrence filter must be selected"; + return Bundle.PastOccurrencesFilterPanel_error_text(); } return ""; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/SizeFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/SizeFilterPanel.java index 9f9245937b..0585750aa4 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/SizeFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/SizeFilterPanel.java @@ -25,6 +25,7 @@ import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.discovery.search.SearchData; import org.sleuthkit.autopsy.discovery.search.SearchData.FileSize; import org.sleuthkit.autopsy.discovery.search.SearchFiltering; @@ -166,10 +167,11 @@ final class SizeFilterPanel extends AbstractDiscoveryFilterPanel { } } + @NbBundle.Messages({"SizeFilterPanel.error.text=At least one size must be selected."}) @Override String checkForError() { if (sizeCheckbox.isSelected() && sizeList.getSelectedValuesList().isEmpty()) { - return "At least one size must be selected"; + return Bundle.SizeFilterPanel_error_text(); } return ""; From 9c13cfce97631d2fa37a3f136acdb0496d0d18eb Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 18 Sep 2020 15:33:23 -0400 Subject: [PATCH 124/130] Update NEWS.txt with 4.17.0 release notes --- NEWS.txt | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/NEWS.txt b/NEWS.txt index 67620c29a0..d9c67e6a17 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -1,3 +1,39 @@ +---------------- VERSION 4.17.0 -------------- +GUI: +Expanded the Data Source Summary panel to show recent activity, past cases, analysis results, etc. Also made this available from the main UI when a data source is selected. +Expanded Discovery UI to support searching for and basic display of web domains. It collapses the various web artifacts into a single view. + +Ingest Modules: +Added iOS Analyzer module based on iLEAPP and a subset of its artifacts. +Support for HEIC/HEIF images by converting them to JPEGs using ImageMagick (which retains EXIF). +New Picture Analyzer module that does HEIC conversion and EXIF extraction (replaces the previous EXIF module). +Added support for the latest version of Edge browser that is based on Chromium into Recent Activity. Other Chromium-based browsers are also supported. +Updated the rules that search Web History artifacts for search queries. Expanded module to support multiple search engines for ambiguous URLs. +Bluetooth pairing artifacts are created based on RegRipper output. +Prefetch artifacts record the full path of exes. +PhotoRec module allows you to include or exclude specific file types. +Upgraded to Tika 1.23. + +Performance: +Documents are added to Solr in batches instead of one by one. +More efficient queries to find WAL files for SQLite databases. +Use a local drive for temp files for multi-user cases instead of the shared folder. + +Command Line +Command line support for report profiles. +Restored support for Windows file type association for opening a case in Autopsy by double clicking case metadata (.aut) file. +Better feedback for command line argument errors. + +Misc: +Updated versions of libvmdk, libvhdi, and libewf. +Persona UI fixes: Pre-populate account and changed order of New Persona dialog. +Streaming ingest support added to auto ingest. +Recent Activity module processes now use the global timeout. +Option to include Autopsy executable in portable case (Windows only.) +Upgraded to NetBeans 11 Rich Client Platform. +Added debug feature to save the stack trace on all threads. + + ---------------- VERSION 4.16.0 -------------- Ingest: - Added streaming ingest capability for disk images that allow files to be analyzed as soon as they are added to the database. From 9f0c0e33ac8400664dc59fd5dfb303d26841c7a9 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 18 Sep 2020 15:49:54 -0400 Subject: [PATCH 125/130] 6861 fix comment, add period to end of sentence --- .../autopsy/discovery/ui/Bundle.properties-MERGED | 4 ++-- .../sleuthkit/autopsy/discovery/ui/DateFilterPanel.java | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED index 08e22e9826..122d8e6591 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED @@ -8,9 +8,9 @@ DataSourceModuleWrapper.fileTypeModule.text=File Type Identification module was DataSourceModuleWrapper.hashModule.text=Hash Lookup module was not run on data source: {0}\n # {0} - timeZone DateFilterPanel.dateRange.text=Date Range ({0}): -DateFilterPanel.invalidRange.text=Range or Only Last must be selected +DateFilterPanel.invalidRange.text=Range or Only Last must be selected. DateFilterPanel.startAfterEnd.text=Start date should be before the end date when both are enabled. -DateFilterPanel.startOrEndNeeded.text=A start or end date must be specified to use the range filter +DateFilterPanel.startOrEndNeeded.text=A start or end date must be specified to use the range filter. DiscoveryDialog.name.text=Discovery DiscoveryTopComponent.cancelButton.text=Cancel Search DiscoveryTopComponent.name=\ Discovery diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java index 81777b5a40..528a5d1bc2 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DateFilterPanel.java @@ -51,8 +51,7 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { DateFilterPanel() { initComponents(); rangeRadioButton.setText(Bundle.DateFilterPanel_dateRange_text(Utils.getUserPreferredZoneId().toString())); - //Disable manual entry in the spinner so it is limited to 60 days - //if a user wants farther back than that one would expect date range filter options would be more appealing + //Disable manual entry in the spinner ((JSpinner.DefaultEditor) daysSpinner.getEditor()).getTextField().setEditable(false); //Disable manual entry in the date pickers startDatePicker.getComponentDateTextField().setEditable(false); @@ -303,8 +302,8 @@ class DateFilterPanel extends AbstractDiscoveryFilterPanel { } } - @NbBundle.Messages({"DateFilterPanel.invalidRange.text=Range or Only Last must be selected", - "DateFilterPanel.startOrEndNeeded.text=A start or end date must be specified to use the range filter", + @NbBundle.Messages({"DateFilterPanel.invalidRange.text=Range or Only Last must be selected.", + "DateFilterPanel.startOrEndNeeded.text=A start or end date must be specified to use the range filter.", "DateFilterPanel.startAfterEnd.text=Start date should be before the end date when both are enabled."}) @Override String checkForError() { From 65123b1a7095a66cbf350ee45b838c9551b5e367 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 21 Sep 2020 09:56:06 -0400 Subject: [PATCH 126/130] 6866 add domain attribute to webcache artifacts --- .../autopsy/recentactivity/ChromeCacheExtractor.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ChromeCacheExtractor.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ChromeCacheExtractor.java index ba34a98620..aedf34097f 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ChromeCacheExtractor.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ChromeCacheExtractor.java @@ -44,6 +44,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.FileManager; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.NetworkUtils; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress; import org.sleuthkit.autopsy.ingest.IngestJobContext; @@ -519,9 +520,11 @@ final class ChromeCacheExtractor { BlackboardArtifact webCacheArtifact = cacheEntryFile.newArtifact(ARTIFACT_TYPE.TSK_WEB_CACHE); if (webCacheArtifact != null) { Collection webAttr = new ArrayList<>(); + String url = cacheEntry.getKey() != null ? cacheEntry.getKey() : ""; webAttr.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL, - moduleName, - ((cacheEntry.getKey() != null) ? cacheEntry.getKey() : ""))); + moduleName, url)); + webAttr.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, + moduleName, NetworkUtils.extractDomain(url))); webAttr.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED, moduleName, cacheEntry.getCreationTime())); webAttr.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_HEADERS, From 427c5f00e17140108c90422696fe3d2f0c0a8430 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 21 Sep 2020 10:02:44 -0400 Subject: [PATCH 127/130] 6876 add description for domain specific filters --- .../discovery/search/Bundle.properties-MERGED | 9 +++++ .../discovery/search/SearchFiltering.java | 35 +++++++++++++++++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED index e1cbc654a1..037868e838 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED @@ -87,12 +87,21 @@ SearchData.Frequency.verycommon.displayName=Very Common (100+) SearchData.Score.interesting.displayName=Interesting SearchData.Score.notable.displayName=Notable SearchData.Score.unknown.displayName=Unknown +# {0} - artifactTypes +SearchFiltering.artifactTypeFilter.desc=Result type(s): {0} +SearchFiltering.artifactTypeFilter.or=, # {0} - Data source name # {1} - Data source ID SearchFiltering.DataSourceFilter.datasource={0}({1}) # {0} - filters SearchFiltering.DataSourceFilter.desc=Data source(s): {0} SearchFiltering.DataSourceFilter.or=, +# {0} - startDate +SearchFiltering.dateRangeFilter.after=after: {0} +SearchFiltering.dateRangeFilter.and=\ and +# {0} - endDate +SearchFiltering.dateRangeFilter.before=before: {0} +SearchFiltering.dateRangeFilter.lable=Activity date # {0} - filters SearchFiltering.FileTypeFilter.desc=Type: {0} SearchFiltering.FileTypeFilter.or=, diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java index dd2609a56a..47731c6be0 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.discovery.search; +import java.text.SimpleDateFormat; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; @@ -32,8 +33,11 @@ import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Date; import java.util.List; +import java.util.Locale; import java.util.StringJoiner; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import org.openide.util.NbBundle; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -171,9 +175,25 @@ public class SearchFiltering { + " AND (value_int64 BETWEEN " + startDate + " AND " + endDate + ")"; } + @NbBundle.Messages({"SearchFiltering.dateRangeFilter.lable=Activity date ", + "# {0} - startDate", + "SearchFiltering.dateRangeFilter.after=after: {0}", + "# {0} - endDate", + "SearchFiltering.dateRangeFilter.before=before: {0}", + "SearchFiltering.dateRangeFilter.and= and "}) @Override public String getDesc() { - return "ArtifactDateRangeFilter Stub"; + String desc = ""; // NON-NLS + if (!(startDate <= 0 )) { + desc += Bundle.SearchFiltering_dateRangeFilter_after(new SimpleDateFormat("yyyy/MM/dd", Locale.getDefault()).format(new Date(TimeUnit.SECONDS.toMillis(startDate)))); + } + if (!(endDate > 10000000000L)) { //arbitrary time sometime in the 23rd century to check that they specified a date and the max date isn't being used + if (!desc.isEmpty()) { + desc += Bundle.SearchFiltering_dateRangeFilter_and(); + } + desc += Bundle.SearchFiltering_dateRangeFilter_before(new SimpleDateFormat("yyyy/MM/dd", Locale.getDefault()).format(new Date(TimeUnit.SECONDS.toMillis(endDate)))); + } + return desc; } } @@ -204,9 +224,20 @@ public class SearchFiltering { return "artifact_type_id IN (" + joiner + ")"; } + @NbBundle.Messages({"# {0} - artifactTypes", + "SearchFiltering.artifactTypeFilter.desc=Result type(s): {0}", + "SearchFiltering.artifactTypeFilter.or=, "}) @Override public String getDesc() { - return "ArtifactTypeFilter Stub"; + String desc = ""; // NON-NLS + for (ARTIFACT_TYPE type : types) { + if (!desc.isEmpty()) { + desc += Bundle.SearchFiltering_artifactTypeFilter_or(); + } + desc += type.getDisplayName(); + } + desc = Bundle.SearchFiltering_artifactTypeFilter_desc(desc); + return desc; } } From c74cff253580e7f2cf295c14ecfb714883e5aa52 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 21 Sep 2020 10:07:01 -0400 Subject: [PATCH 128/130] 6870 simplify comparisons --- .../sleuthkit/autopsy/discovery/search/SearchFiltering.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java index 47731c6be0..975ffa6edd 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java @@ -184,10 +184,10 @@ public class SearchFiltering { @Override public String getDesc() { String desc = ""; // NON-NLS - if (!(startDate <= 0 )) { + if (startDate > 0 ) { desc += Bundle.SearchFiltering_dateRangeFilter_after(new SimpleDateFormat("yyyy/MM/dd", Locale.getDefault()).format(new Date(TimeUnit.SECONDS.toMillis(startDate)))); } - if (!(endDate > 10000000000L)) { //arbitrary time sometime in the 23rd century to check that they specified a date and the max date isn't being used + if (endDate < 10000000000L) { //arbitrary time sometime in the 23rd century to check that they specified a date and the max date isn't being used if (!desc.isEmpty()) { desc += Bundle.SearchFiltering_dateRangeFilter_and(); } From f129409c0f97b7a481c3025360d2e96e1476e76e Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 21 Sep 2020 10:21:12 -0400 Subject: [PATCH 129/130] 6870 add initial label --- .../sleuthkit/autopsy/discovery/search/SearchFiltering.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java index 975ffa6edd..c88726c998 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java @@ -193,6 +193,9 @@ public class SearchFiltering { } desc += Bundle.SearchFiltering_dateRangeFilter_before(new SimpleDateFormat("yyyy/MM/dd", Locale.getDefault()).format(new Date(TimeUnit.SECONDS.toMillis(endDate)))); } + if (!desc.isEmpty()){ + desc = Bundle.SearchFiltering_dateRangeFilter_lable()+desc; + } return desc; } } From 85e13e742c178b0bd29b61c8177838326812d2d8 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 21 Sep 2020 11:51:51 -0400 Subject: [PATCH 130/130] 6870 fix empty filter Domain search description --- .../discovery/ui/Bundle.properties-MERGED | 2 ++ .../discovery/ui/DiscoveryTopComponent.java | 20 ++++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED index 814d78da16..ae35449d15 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/Bundle.properties-MERGED @@ -12,7 +12,9 @@ DateFilterPanel.dateRange.text=Date Range ({0}): DateFilterPanel.invalidRange.text=Range or Only Last must be selected DateFilterPanel.startOrEndNeeded.text=A start or end date must be specified to use the range filter DiscoveryDialog.name.text=Discovery +DiscoveryTopComponent.additionalFilters.text=; DiscoveryTopComponent.cancelButton.text=Cancel Search +DiscoveryTopComponent.domainSearch.text=Type: Domain DiscoveryTopComponent.name=\ Discovery DiscoveryTopComponent.newSearch.text=New Search DiscoveryTopComponent.searchCancelled.text=Search has been cancelled. diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java index ff3e0cb7cd..07465afcfd 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java @@ -38,6 +38,7 @@ import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; +import org.sleuthkit.autopsy.discovery.search.SearchData.Type; import static org.sleuthkit.autopsy.discovery.search.SearchData.Type.DOMAIN; /** @@ -56,6 +57,7 @@ public final class DiscoveryTopComponent extends TopComponent { private final GroupListPanel groupListPanel; private final DetailsPanel detailsPanel; private final ResultsPanel resultsPanel; + private Type searchType; private int dividerLocation = -1; private SwingAnimator animator = null; @@ -288,7 +290,8 @@ public final class DiscoveryTopComponent extends TopComponent { void handleSearchStartedEvent(DiscoveryEventUtils.SearchStartedEvent searchStartedEvent) { newSearchButton.setText(Bundle.DiscoveryTopComponent_cancelButton_text()); progressMessageTextArea.setForeground(Color.red); - progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchInProgress_text(searchStartedEvent.getType().name())); + searchType = searchStartedEvent.getType(); + progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchInProgress_text(searchType.name())); rightSplitPane.getComponent(1).setVisible(searchStartedEvent.getType() != DOMAIN); rightSplitPane.getComponent(2).setVisible(searchStartedEvent.getType() != DOMAIN); } @@ -302,11 +305,22 @@ public final class DiscoveryTopComponent extends TopComponent { @Subscribe @Messages({"DiscoveryTopComponent.newSearch.text=New Search", "# {0} - search", - "DiscoveryTopComponent.searchComplete.text=Results with {0}"}) + "DiscoveryTopComponent.searchComplete.text=Results with {0}", + "DiscoveryTopComponent.domainSearch.text=Type: Domain", + "DiscoveryTopComponent.additionalFilters.text=; "}) void handleSearchCompleteEvent(DiscoveryEventUtils.SearchCompleteEvent searchCompleteEvent) { newSearchButton.setText(Bundle.DiscoveryTopComponent_newSearch_text()); progressMessageTextArea.setForeground(Color.black); - progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchComplete_text(searchCompleteEvent.getFilters().stream().map(AbstractFilter::getDesc).collect(Collectors.joining("; ")))); + String descriptionText = ""; + if (searchType == DOMAIN) { + //domain does not have a file type filter to add the type information so it is manually added + descriptionText = Bundle.DiscoveryTopComponent_domainSearch_text(); + if (!searchCompleteEvent.getFilters().isEmpty()) { + descriptionText += Bundle.DiscoveryTopComponent_additionalFilters_text(); + } + } + descriptionText += searchCompleteEvent.getFilters().stream().map(AbstractFilter::getDesc).collect(Collectors.joining("; ")); + progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchComplete_text(descriptionText)); progressMessageTextArea.setCaretPosition(0); }