Merge pull request #7342 from eugene7646/view_by_mime_8091

Add View by MIME DTO/DAO (8091)
This commit is contained in:
Brian Carrier 2021-10-13 17:16:00 -04:00 committed by GitHub
commit a42b4292ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 151 additions and 38 deletions

View File

@ -43,7 +43,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.mainui.datamodel.DataArtifactSearchParam;
import org.sleuthkit.autopsy.mainui.nodes.DataArtifactNode;
import org.sleuthkit.autopsy.mainui.nodes.FileNode;
import org.sleuthkit.autopsy.mainui.datamodel.FileTypeExtensionsSearchParam;
import org.sleuthkit.autopsy.mainui.datamodel.FileTypeExtensionsSearchParams;
import org.sleuthkit.autopsy.mainui.nodes.SearchResultRootNode;
import org.sleuthkit.autopsy.mainui.datamodel.MainDAO;
import org.sleuthkit.autopsy.mainui.datamodel.SearchResultsDTO;
@ -386,7 +386,7 @@ public final class DataResultTopComponent extends TopComponent implements DataRe
}
public void displayFileExtensions(FileTypeExtensionsSearchParam fileExtensionsKey) {
public void displayFileExtensions(FileTypeExtensionsSearchParams fileExtensionsKey) {
try {
displaySearchResults(threePanelDAO.getViewsDAO().getFilesByExtension(fileExtensionsKey));
} catch (ExecutionException | IllegalArgumentException ex) {

View File

@ -18,7 +18,7 @@
*/
package org.sleuthkit.autopsy.datamodel;
import org.sleuthkit.autopsy.mainui.datamodel.FileTypeExtensionsSearchParam;
import org.sleuthkit.autopsy.mainui.datamodel.FileTypeExtensionsSearchParams;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Arrays;
@ -350,10 +350,9 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
FileExtensionNode(FileExtSearchFilter filter, SleuthkitCase skCase, FileTypesByExtObservable o) {
super(typesRoot, Children.LEAF,
Lookups.fixed(filter.getDisplayName(),
new FileTypeExtensionsSearchParam(
new FileTypeExtensionsSearchParams(
filter,
filteringDataSourceObjId() > 0 ? filteringDataSourceObjId() : null,
!UserPreferences.hideKnownFilesInViewsTree())));
filteringDataSourceObjId() > 0 ? filteringDataSourceObjId() : null)));
this.filter = filter;
super.setName(filter.getDisplayName());

View File

@ -84,7 +84,7 @@ import org.sleuthkit.autopsy.datamodel.KeywordHits;
import org.sleuthkit.autopsy.datamodel.AutopsyTreeChildFactory;
import org.sleuthkit.autopsy.mainui.datamodel.DataArtifactSearchParam;
import org.sleuthkit.autopsy.datamodel.DataArtifacts;
import org.sleuthkit.autopsy.mainui.datamodel.FileTypeExtensionsSearchParam;
import org.sleuthkit.autopsy.mainui.datamodel.FileTypeExtensionsSearchParams;
import org.sleuthkit.autopsy.datamodel.OsAccounts;
import org.sleuthkit.autopsy.datamodel.PersonNode;
import org.sleuthkit.autopsy.datamodel.Tags;
@ -872,7 +872,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
Node drfn = new DataResultFilterNode(originNode, DirectoryTreeTopComponent.this.em);
// Create a TableFilterNode with knowledge of the node's type to allow for column order settings
DataArtifactSearchParam dataArtifactKey = originNode.getLookup().lookup(DataArtifactSearchParam.class);
FileTypeExtensionsSearchParam fileExtensionsKey = originNode.getLookup().lookup(FileTypeExtensionsSearchParam.class);
FileTypeExtensionsSearchParams fileExtensionsKey = originNode.getLookup().lookup(FileTypeExtensionsSearchParams.class);
if (dataArtifactKey != null) {
dataResult.displayDataArtifact(dataArtifactKey);
} else if (fileExtensionsKey != null) {

View File

@ -21,18 +21,18 @@ package org.sleuthkit.autopsy.mainui.datamodel;
/**
* Base implementation of search parameters to provide to a DAO.
*/
public class BaseSearchParam implements SearchParam {
public class BaseSearchParams implements SearchParams {
private final long startItem;
private final Long maxResultsCount;
/**
* Constructor that gets all results.
*/
public BaseSearchParam() {
public BaseSearchParams() {
this(0, null);
}
public BaseSearchParam(long startItem, Long maxResultsCount) {
public BaseSearchParams(long startItem, Long maxResultsCount) {
this.startItem = startItem;
this.maxResultsCount = maxResultsCount;
}

View File

@ -16,6 +16,7 @@ FileExtRootFilter_documents_displayName=Documents
FileExtRootFilter_executable_displayName=Executable
FileExtRootFilter_image_displayName=Images
FileExtRootFilter_video_displayName=Video
FileTypesByMimeType.name.text=By MIME Type
ThreePanelDataArtifactDAO.dataArtifact.columnKeys.comment.description=Comment
ThreePanelDataArtifactDAO.dataArtifact.columnKeys.comment.displayName=C
ThreePanelDataArtifactDAO.dataArtifact.columnKeys.comment.name=Comment

View File

@ -24,7 +24,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
/**
* Key for data artifact in order to retrieve data from DAO.
*/
public class DataArtifactSearchParam extends BaseSearchParam {
public class DataArtifactSearchParam extends BaseSearchParams {
private final BlackboardArtifact.Type artifactType;
private final Long dataSourceId;

View File

@ -23,25 +23,22 @@ import java.util.Objects;
/**
* Key for accessing data about file type extensions from the DAO.
*/
public class FileTypeExtensionsSearchParam extends BaseSearchParam {
public class FileTypeExtensionsSearchParams extends BaseSearchParams {
private final FileExtSearchFilter filter;
private final Long dataSourceId;
private final boolean knownShown;
// TODO: This should ideally take in some kind of ENUM once we redo the tree.
// this assumes that filters implicitly or explicitly implement hashCode and equals to work
public FileTypeExtensionsSearchParam(FileExtSearchFilter filter, Long dataSourceId, boolean showKnown) {
public FileTypeExtensionsSearchParams(FileExtSearchFilter filter, Long dataSourceId) {
this.filter = filter;
this.dataSourceId = dataSourceId;
this.knownShown = showKnown;
}
public FileTypeExtensionsSearchParam(FileExtSearchFilter filter, Long dataSourceId, boolean knownShown, long startItem, Long maxResultsCount) {
public FileTypeExtensionsSearchParams(FileExtSearchFilter filter, Long dataSourceId, long startItem, Long maxResultsCount) {
super(startItem, maxResultsCount);
this.filter = filter;
this.dataSourceId = dataSourceId;
this.knownShown = knownShown;
}
public FileExtSearchFilter getFilter() {
@ -52,16 +49,11 @@ public class FileTypeExtensionsSearchParam extends BaseSearchParam {
return dataSourceId;
}
public boolean isKnownShown() {
return knownShown;
}
@Override
public int hashCode() {
int hash = 7;
hash = 23 * hash + Objects.hashCode(this.filter);
hash = 23 * hash + Objects.hashCode(this.dataSourceId);
hash = 23 * hash + (this.knownShown ? 1 : 0);
return hash;
}
@ -76,10 +68,7 @@ public class FileTypeExtensionsSearchParam extends BaseSearchParam {
if (getClass() != obj.getClass()) {
return false;
}
final FileTypeExtensionsSearchParam other = (FileTypeExtensionsSearchParam) obj;
if (this.knownShown != other.knownShown) {
return false;
}
final FileTypeExtensionsSearchParams other = (FileTypeExtensionsSearchParams) obj;
if (!Objects.equals(this.filter, other.filter)) {
return false;
}

View File

@ -0,0 +1,80 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.mainui.datamodel;
import java.util.Objects;
/**
* Key for accessing data about file MIME type from the DAO.
*/
public class FileTypeMimeSearchParams extends BaseSearchParams {
private final String mimeType;
private final Long dataSourceId;
// @@@ TODO: Remove shownKnown from constructors and have DAO figure it out.
public FileTypeMimeSearchParams(String mimeType, Long dataSourceId, boolean showKnown) {
this.mimeType = mimeType;
this.dataSourceId = dataSourceId;
}
public FileTypeMimeSearchParams(String mimeType, Long dataSourceId, boolean knownShown, long startItem, Long maxResultsCount) {
super(startItem, maxResultsCount);
this.mimeType = mimeType;
this.dataSourceId = dataSourceId;
}
public String getMimeType() {
return mimeType;
}
public Long getDataSourceId() {
return dataSourceId;
}
@Override
public int hashCode() {
int hash = 7;
hash = 23 * hash + Objects.hashCode(this.mimeType);
hash = 23 * hash + Objects.hashCode(this.dataSourceId);
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final FileTypeMimeSearchParams other = (FileTypeMimeSearchParams) obj;
if (!(this.mimeType.equals(other.mimeType))) {
return false;
}
if (!Objects.equals(this.dataSourceId, other.dataSourceId)) {
return false;
}
return true;
}
}

View File

@ -21,7 +21,7 @@ package org.sleuthkit.autopsy.mainui.datamodel;
/**
* Describes parameters to provide to the DAO for fetching data.
*/
public interface SearchParam {
public interface SearchParams {
long getStartItem();

View File

@ -28,9 +28,12 @@ import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import static org.sleuthkit.autopsy.core.UserPreferences.hideKnownFilesInViewsTree;
import static org.sleuthkit.autopsy.core.UserPreferences.hideSlackFilesInViewsTree;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.autopsy.datamodel.FileTypeExtensions;
import org.sleuthkit.autopsy.mainui.datamodel.FileRowDTO.ExtensionMediaType;
@ -150,18 +153,30 @@ public class ViewsDAO {
return Case.getCurrentCaseThrows().getSleuthkitCase();
}
private final Cache<FileTypeExtensionsSearchParam, SearchResultsDTO> fileTypeByExtensionCache = CacheBuilder.newBuilder().maximumSize(1000).build();
private final Cache<FileTypeExtensionsSearchParams, SearchResultsDTO> fileTypeByExtensionCache = CacheBuilder.newBuilder().maximumSize(1000).build();
private final Cache<FileTypeMimeSearchParams, SearchResultsDTO> fileTypeByMimeCache = CacheBuilder.newBuilder().maximumSize(1000).build();
public SearchResultsDTO getFilesByExtension(FileTypeExtensionsSearchParam key) throws ExecutionException, IllegalArgumentException {
public SearchResultsDTO getFilesByExtension(FileTypeExtensionsSearchParams key) throws ExecutionException, IllegalArgumentException {
if (key.getFilter() == null) {
throw new IllegalArgumentException("Must have non-null filter");
} else if (key.getDataSourceId() != null && key.getDataSourceId() <= 0) {
throw new IllegalArgumentException("Data source id must be greater than 0 or null");
}
return fileTypeByExtensionCache.get(key, () -> fetchFileViewFiles(key.getFilter(), key.getDataSourceId(), key.isKnownShown()));
return fileTypeByExtensionCache.get(key, () -> fetchExtensionSearchResultsDTOs(key.getFilter(), key.getDataSourceId()));
}
public SearchResultsDTO getFilesByMime(FileTypeMimeSearchParams key) throws ExecutionException, IllegalArgumentException {
if (key.getMimeType() == null) {
throw new IllegalArgumentException("Must have non-null filter");
} else if (key.getDataSourceId() != null && key.getDataSourceId() <= 0) {
throw new IllegalArgumentException("Data source id must be greater than 0 or null");
}
return fileTypeByMimeCache.get(key, () -> fetchMimeSearchResultsDTOs(key.getMimeType(), key.getDataSourceId()));
}
// private ViewFileTableSearchResultsDTO fetchFilesForTable(ViewFileCacheKey cacheKey) throws NoCurrentCaseException, TskCoreException {
//
// }
@ -176,10 +191,10 @@ public class ViewsDAO {
// ViewFileCacheKey cacheKey = new ViewFileCacheKey(artType, dataSourceId);
// return dataArtifactCache.get(cacheKey, () -> fetchFilesForTable(cacheKey));
// }
private Map<Integer, Long> fetchFileViewCounts(List<FileExtSearchFilter> filters, Long dataSourceId, boolean showKnown) throws NoCurrentCaseException, TskCoreException {
private Map<Integer, Long> fetchFileViewCounts(List<FileExtSearchFilter> filters, Long dataSourceId) throws NoCurrentCaseException, TskCoreException {
Map<Integer, Long> counts = new HashMap<>();
for (FileExtSearchFilter filter : filters) {
String whereClause = getFileWhereStatement(filter, dataSourceId, showKnown);
String whereClause = getFileExtensionWhereStatement(filter, dataSourceId);
long count = getCase().countFilesWhere(whereClause);
counts.put(filter.getId(), count);
}
@ -187,9 +202,9 @@ public class ViewsDAO {
return counts;
}
private String getFileWhereStatement(FileExtSearchFilter filter, Long dataSourceId, boolean showKnown) {
private String getFileExtensionWhereStatement(FileExtSearchFilter filter, Long dataSourceId) {
String whereClause = "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")"
+ (showKnown
+ (hideKnownFilesInViewsTree()
? " "
: " AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")")
+ (dataSourceId != null && dataSourceId > 0
@ -202,8 +217,37 @@ public class ViewsDAO {
return whereClause;
}
private SearchResultsDTO fetchFileViewFiles(FileExtSearchFilter filter, Long dataSourceId, boolean showKnown) throws NoCurrentCaseException, TskCoreException {
String whereStatement = getFileWhereStatement(filter, dataSourceId, showKnown);
private String getFileMimeWhereStatement(String mimeType, Long dataSourceId) {
String whereClause = "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")"
+ " AND (type IN ("
+ TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal() + ","
+ TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal() + ","
+ TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal() + ","
+ TskData.TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.ordinal() + ","
+ TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()
+ (hideSlackFilesInViewsTree() ? "" : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()))
+ "))"
+ ((dataSourceId > 0) ? " AND data_source_obj_id = " + dataSourceId : " ")
+ (hideKnownFilesInViewsTree() ? (" AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")") : "")
+ " AND mime_type = '" + mimeType + "'";
return whereClause;
}
private SearchResultsDTO fetchExtensionSearchResultsDTOs(FileExtSearchFilter filter, Long dataSourceId) throws NoCurrentCaseException, TskCoreException {
String whereStatement = getFileExtensionWhereStatement(filter, dataSourceId);
return fetchFileViewFiles(whereStatement, filter.getDisplayName());
}
@NbBundle.Messages({"FileTypesByMimeType.name.text=By MIME Type"})
private SearchResultsDTO fetchMimeSearchResultsDTOs(String mimeType, Long dataSourceId) throws NoCurrentCaseException, TskCoreException {
String whereStatement = getFileMimeWhereStatement(mimeType, dataSourceId);
final String MIME_TYPE_DISPLAY_NAME = Bundle.FileTypesByMimeType_name_text();
return fetchFileViewFiles(whereStatement, MIME_TYPE_DISPLAY_NAME);
}
private SearchResultsDTO fetchFileViewFiles(String whereStatement, String displayName) throws NoCurrentCaseException, TskCoreException {
List<AbstractFile> files = getCase().findAllFilesWhere(whereStatement);
List<RowDTO> fileRows = new ArrayList<>();
@ -259,7 +303,7 @@ public class ViewsDAO {
cellValues));
}
return new BaseSearchResultsDTO(FILE_VIEW_EXT_TYPE_ID, filter.getDisplayName(), FILE_COLUMNS, fileRows);
return new BaseSearchResultsDTO(FILE_VIEW_EXT_TYPE_ID, displayName, FILE_COLUMNS, fileRows);
}
}