More work

This commit is contained in:
Eugene Livis 2021-10-27 17:00:45 -04:00
parent e8f9ed9fbc
commit 94e8f893a9
2 changed files with 136 additions and 104 deletions

View File

@ -22,27 +22,25 @@ import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import static org.sleuthkit.autopsy.core.UserPreferences.hideKnownFilesInViewsTree; import org.sleuthkit.autopsy.core.UserPreferences;
import static org.sleuthkit.autopsy.core.UserPreferences.hideSlackFilesInViewsTree;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.autopsy.datamodel.FileTypeExtensions; import org.sleuthkit.autopsy.datamodel.FileTypeExtensions;
import org.sleuthkit.autopsy.mainui.datamodel.FileRowDTO.ExtensionMediaType; import org.sleuthkit.autopsy.mainui.datamodel.FileRowDTO.ExtensionMediaType;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
/** /**
* Provides information to populate the results viewer for data in the views * Provides information to populate the results viewer for data in the views
@ -73,12 +71,16 @@ public class TagsDAO {
private static final TimeUnit CACHE_DURATION_UNITS = TimeUnit.MINUTES; private static final TimeUnit CACHE_DURATION_UNITS = TimeUnit.MINUTES;
private final Cache<SearchParams<?>, SearchResultsDTO> searchParamsCache = CacheBuilder.newBuilder().maximumSize(CACHE_SIZE).expireAfterAccess(CACHE_DURATION, CACHE_DURATION_UNITS).build(); private final Cache<SearchParams<?>, SearchResultsDTO> searchParamsCache = CacheBuilder.newBuilder().maximumSize(CACHE_SIZE).expireAfterAccess(CACHE_DURATION, CACHE_DURATION_UNITS).build();
private static final String USER_NAME_PROPERTY = "user.name"; //NON-NLS
private static final String FILE_TAG_TYPE_ID = "FILE_TAG"; private static final String FILE_TAG_TYPE_ID = "FILE_TAG";
private static final String RESULT_TAG_TYPE_ID = "RESULT_TAG"; private static final String RESULT_TAG_TYPE_ID = "RESULT_TAG";
private static final String FILE_TAG_DISPLAY_NAME = "File Tag";
private static final String RESULT_TAG_DISPLAY_NAME = "Result Tag";
private static final List<ColumnKey> FILE_TAG_COLUMNS = Arrays.asList( private static final List<ColumnKey> FILE_TAG_COLUMNS = Arrays.asList(
getFileColumnKey(Bundle.TagsDAO_fileColumns_nameColLbl()), getFileColumnKey(Bundle.TagsDAO_fileColumns_nameColLbl()),
getFileColumnKey(Bundle.TagsDAO_fileColumns_originalName()), getFileColumnKey(Bundle.TagsDAO_fileColumns_originalName()), // ELODO handle translation
getFileColumnKey(Bundle.TagsDAO_fileColumns_filePathColLbl()), getFileColumnKey(Bundle.TagsDAO_fileColumns_filePathColLbl()),
getFileColumnKey(Bundle.TagsDAO_fileColumns_commentColLbl()), getFileColumnKey(Bundle.TagsDAO_fileColumns_commentColLbl()),
getFileColumnKey(Bundle.TagsDAO_fileColumns_modifiedTimeColLbl()), getFileColumnKey(Bundle.TagsDAO_fileColumns_modifiedTimeColLbl()),
@ -144,115 +146,146 @@ public class TagsDAO {
} }
} }
public SearchResultsDTO getFilesByMime(FileTypeMimeSearchParams key, long startItem, Long maxCount, boolean hardRefresh) throws ExecutionException, IllegalArgumentException { public SearchResultsDTO getTags(TagsSearchParams key, long startItem, Long maxCount, boolean hardRefresh) throws ExecutionException, IllegalArgumentException {
if (key.getMimeType() == null) { if (key.getTagName() == null) {
throw new IllegalArgumentException("Must have non-null filter"); throw new IllegalArgumentException("Must have non-null filter");
} else if (key.getDataSourceId() != null && key.getDataSourceId() <= 0) { } else if (key.getDataSourceId() != null && key.getDataSourceId() <= 0) {
throw new IllegalArgumentException("Data source id must be greater than 0 or null"); throw new IllegalArgumentException("Data source id must be greater than 0 or null");
} }
SearchParams<FileTypeMimeSearchParams> searchParams = new SearchParams<>(key, startItem, maxCount); SearchParams<TagsSearchParams> searchParams = new SearchParams<>(key, startItem, maxCount);
if (hardRefresh) { if (hardRefresh) {
this.searchParamsCache.invalidate(searchParams); this.searchParamsCache.invalidate(searchParams);
} }
return searchParamsCache.get(searchParams, () -> fetchMimeSearchResultsDTOs(key.getMimeType(), key.getDataSourceId(), startItem, maxCount)); return searchParamsCache.get(searchParams, () -> fetchTagsDTOs(key.getTagName(), key.getTagType(), key.getDataSourceId(), startItem, maxCount));
}
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 != null && 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;
} }
@NbBundle.Messages({"FileTag.name.text=File Tag"}) @NbBundle.Messages({"FileTag.name.text=File Tag"})
private SearchResultsDTO fetchMimeSearchResultsDTOs(String mimeType, Long dataSourceId, long startItem, Long maxResultCount) throws NoCurrentCaseException, TskCoreException { private SearchResultsDTO fetchTagsDTOs(TagName tagName, TagsSearchParams.TagType type, Long dataSourceId, long startItem, Long maxResultCount) throws NoCurrentCaseException, TskCoreException {
String whereStatement = getFileMimeWhereStatement(mimeType, dataSourceId); if (null == type) {
final String FILE_TAG_DISPLAY_NAME = Bundle.FileTag_name_text(); // ELTODO throw?
return fetchFileViewFiles(whereStatement, FILE_TAG_DISPLAY_NAME, startItem, maxResultCount); return null;
}
switch (type) {
case FILE:
return fetchFileTags(tagName, dataSourceId, startItem, maxResultCount);
case RESULT:
return fetchResultTags(tagName, dataSourceId, startItem, maxResultCount);
default:
// ELTODO throw?
return null;
}
} }
/* GET RESULT TAGS
* BlackboardArtifactTagNodeFactory.createKeys(List<BlackboardArtifactTag> tags)
* BlackboardArtifactTagNode.createSheet()
*/
/* GET FILE TAGS
* ContentTagNodeFactory.createKeys(List<ContentTag> tags)
* ContentTagNode.createSheet()
*/
private SearchResultsDTO fetchResultTags(TagName tagName, Long dataSourceId, long startItem, Long maxResultCount) throws NoCurrentCaseException, TskCoreException {
private SearchResultsDTO fetchFileViewFiles(String originalWhereStatement, String displayName, long startItem, Long maxResultCount) throws NoCurrentCaseException, TskCoreException { // ELTODO startItem, maxResultCount
// Add offset and/or paging, if specified List<BlackboardArtifactTag> tags = new ArrayList<>();
String modifiedWhereStatement = originalWhereStatement // Use the blackboard artifact tags bearing the specified tag name as the tags.
+ " ORDER BY obj_id ASC" List<BlackboardArtifactTag> artifactTags = (dataSourceId != null && dataSourceId > 0)
+ (maxResultCount != null && maxResultCount > 0 ? " LIMIT " + maxResultCount : "") ? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName, dataSourceId)
+ (startItem > 0 ? " OFFSET " + startItem : ""); : Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName);
if (UserPreferences.showOnlyCurrentUserTags()) {
List<AbstractFile> files = getCase().findAllFilesWhere(modifiedWhereStatement); String userName = System.getProperty(USER_NAME_PROPERTY);
for (BlackboardArtifactTag tag : artifactTags) {
long totalResultsCount; if (userName.equals(tag.getUserName())) {
// get total number of results tags.add(tag);
if ( (startItem == 0) // offset is zero AND }
&& ( (maxResultCount != null && files.size() < maxResultCount) // number of results is less than max }
|| (maxResultCount == null)) ) { // OR max number of results was not specified
totalResultsCount = files.size();
} else { } else {
// do a query to get total number of results tags.addAll(artifactTags);
totalResultsCount = getCase().countFilesWhere(originalWhereStatement);
} }
List<RowDTO> fileRows = new ArrayList<>(); List<RowDTO> fileRows = new ArrayList<>();
for (AbstractFile file : files) { for (BlackboardArtifactTag tag : tags) {
String name = tag.getContent().getName(); // As a backup.
try {
name = tag.getArtifact().getShortDescription();
} catch (TskCoreException ignore) {
// it's a WARNING, skip
}
String contentPath;
try {
contentPath = tag.getContent().getUniquePath();
} catch (TskCoreException ex) {
contentPath = NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.unavail.text");
}
List<Object> cellValues = Arrays.asList( List<Object> cellValues = Arrays.asList(
file.getName(), // GVDTODO handle . and .. from getContentDisplayName() name,
// GVDTODO translation column null, // ELTODO translation column
null, contentPath,
//GVDTDO replace nulls with SCO tag.getArtifact().getDisplayName(),
null, tag.getComment(),
null, tag.getUserName());
null,
file.getUniquePath(),
TimeZoneUtils.getFormattedTime(file.getMtime()),
TimeZoneUtils.getFormattedTime(file.getCtime()),
TimeZoneUtils.getFormattedTime(file.getAtime()),
TimeZoneUtils.getFormattedTime(file.getCrtime()),
file.getSize(),
file.getDirFlagAsString(),
file.getMetaFlagsAsString(),
// mode,
// userid,
// groupid,
// metaAddr,
// attrAddr,
// typeDir,
// typeMeta,
file.getKnown().getName(), fileRows.add(new BaseRowDTO(
StringUtils.defaultString(file.getMd5Hash()), cellValues,
StringUtils.defaultString(file.getSha256Hash()), RESULT_TAG_TYPE_ID,
// objectId, tag.getId()));
StringUtils.defaultString(file.getMIMEType()),
file.getNameExtension()
);
fileRows.add(new FileRowDTO(
file,
file.getId(),
file.getName(),
file.getNameExtension(),
getExtensionMediaType(file.getNameExtension()),
file.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.ALLOC),
file.getType(),
cellValues));
} }
return new BaseSearchResultsDTO(FILE_TAG_TYPE_ID, displayName, FILE_TAG_COLUMNS, fileRows, startItem, totalResultsCount); return new BaseSearchResultsDTO(RESULT_TAG_TYPE_ID, RESULT_TAG_DISPLAY_NAME, RESULT_TAG_COLUMNS, fileRows, startItem, fileRows.size());
} }
private SearchResultsDTO fetchFileTags(TagName tagName, Long dataSourceId, long startItem, Long maxResultCount) throws NoCurrentCaseException, TskCoreException {
// ELTODO startItem, maxResultCount
List<ContentTag> tags = new ArrayList<>();
List<ContentTag> contentTags = (dataSourceId != null && dataSourceId > 0)
? Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName, dataSourceId)
: Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName);
if (UserPreferences.showOnlyCurrentUserTags()) {
String userName = System.getProperty(USER_NAME_PROPERTY);
for (ContentTag tag : contentTags) {
if (userName.equals(tag.getUserName())) {
tags.add(tag);
}
}
} else {
tags.addAll(contentTags);
}
List<RowDTO> fileRows = new ArrayList<>();
for (ContentTag tag : tags) {
Content content = tag.getContent();
String contentPath = content.getUniquePath();
AbstractFile file = content instanceof AbstractFile ? (AbstractFile) content : null;
List<Object> cellValues = Arrays.asList(
content.getName(),
null, // ELTODO translation column
contentPath,
tag.getComment(),
file != null ? TimeZoneUtils.getFormattedTime(file.getMtime()) : "",
file != null ? TimeZoneUtils.getFormattedTime(file.getCtime()) : "",
file != null ? TimeZoneUtils.getFormattedTime(file.getAtime()) : "",
file != null ? TimeZoneUtils.getFormattedTime(file.getCrtime()) : "",
content.getSize(),
file != null ? StringUtils.defaultString(file.getMd5Hash()) : "",
tag.getUserName());
fileRows.add(new BaseRowDTO(
cellValues,
FILE_TAG_TYPE_ID,
file.getId()));
}
return new BaseSearchResultsDTO(FILE_TAG_TYPE_ID, FILE_TAG_DISPLAY_NAME, FILE_TAG_COLUMNS, fileRows, startItem, fileRows.size());
}
} }

View File

@ -19,6 +19,7 @@
package org.sleuthkit.autopsy.mainui.datamodel; package org.sleuthkit.autopsy.mainui.datamodel;
import java.util.Objects; import java.util.Objects;
import org.sleuthkit.datamodel.TagName;
/** /**
* Key for accessing data about tags from the DAO. * Key for accessing data about tags from the DAO.
@ -31,25 +32,23 @@ public class TagsSearchParams {
} }
private final TagType type; private final TagType type;
private final String tagName; private final TagName tagName;
private final Long dataSourceId; private final Long dataSourceId;
public TagsSearchParams(String tagName, TagType type, Long dataSourceId) { public TagsSearchParams(TagName tagName, TagType type, Long dataSourceId) {
this.tagName = tagName; this.tagName = tagName;
this.type = type; this.type = type;
this.dataSourceId = dataSourceId; this.dataSourceId = dataSourceId;
} }
public TagsSearchParams(String tagName, TagType type, Long dataSourceId, long startItem, Long maxResultsCount) { public TagName getTagName() {
this.tagName = tagName;
this.type = type;
this.dataSourceId = dataSourceId;
}
public String getMimeType() {
return tagName; return tagName;
} }
public TagType getTagType() {
return type;
}
public Long getDataSourceId() { public Long getDataSourceId() {
return dataSourceId; return dataSourceId;
} }
@ -75,7 +74,7 @@ public class TagsSearchParams {
return false; return false;
} }
final TagsSearchParams other = (TagsSearchParams) obj; final TagsSearchParams other = (TagsSearchParams) obj;
if (!(this.tagName.equals(other.tagName))) { if (!Objects.equals(this.tagName, other.tagName)) {
return false; return false;
} }
if (!Objects.equals(this.dataSourceId, other.dataSourceId)) { if (!Objects.equals(this.dataSourceId, other.dataSourceId)) {