From 94e8f893a9e9c59bca5ccaa0f14fd4378ea4387e Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 27 Oct 2021 17:00:45 -0400 Subject: [PATCH] More work --- .../autopsy/mainui/datamodel/TagsDAO.java | 221 ++++++++++-------- .../mainui/datamodel/TagsSearchParams.java | 19 +- 2 files changed, 136 insertions(+), 104 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/TagsDAO.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/TagsDAO.java index 4a422d3e2a..d71f199191 100755 --- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/TagsDAO.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/TagsDAO.java @@ -22,27 +22,25 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -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.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; import org.sleuthkit.autopsy.datamodel.FileTypeExtensions; import org.sleuthkit.autopsy.mainui.datamodel.FileRowDTO.ExtensionMediaType; 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.TagName; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.datamodel.TskData; /** * 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 final Cache, 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 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 FILE_TAG_COLUMNS = Arrays.asList( 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_commentColLbl()), 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 { - if (key.getMimeType() == null) { + public SearchResultsDTO getTags(TagsSearchParams key, long startItem, Long maxCount, boolean hardRefresh) throws ExecutionException, IllegalArgumentException { + if (key.getTagName() == 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"); } - SearchParams searchParams = new SearchParams<>(key, startItem, maxCount); + SearchParams searchParams = new SearchParams<>(key, startItem, maxCount); if (hardRefresh) { this.searchParamsCache.invalidate(searchParams); } - return searchParamsCache.get(searchParams, () -> fetchMimeSearchResultsDTOs(key.getMimeType(), 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; + return searchParamsCache.get(searchParams, () -> fetchTagsDTOs(key.getTagName(), key.getTagType(), key.getDataSourceId(), startItem, maxCount)); } @NbBundle.Messages({"FileTag.name.text=File Tag"}) - private SearchResultsDTO fetchMimeSearchResultsDTOs(String mimeType, Long dataSourceId, long startItem, Long maxResultCount) throws NoCurrentCaseException, TskCoreException { - String whereStatement = getFileMimeWhereStatement(mimeType, dataSourceId); - final String FILE_TAG_DISPLAY_NAME = Bundle.FileTag_name_text(); - return fetchFileViewFiles(whereStatement, FILE_TAG_DISPLAY_NAME, startItem, maxResultCount); + private SearchResultsDTO fetchTagsDTOs(TagName tagName, TagsSearchParams.TagType type, Long dataSourceId, long startItem, Long maxResultCount) throws NoCurrentCaseException, TskCoreException { + if (null == type) { + // ELTODO throw? + 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 tags) + * BlackboardArtifactTagNode.createSheet() + */ + + /* GET FILE TAGS + * ContentTagNodeFactory.createKeys(List 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 - String modifiedWhereStatement = originalWhereStatement - + " ORDER BY obj_id ASC" - + (maxResultCount != null && maxResultCount > 0 ? " LIMIT " + maxResultCount : "") - + (startItem > 0 ? " OFFSET " + startItem : ""); - - List files = getCase().findAllFilesWhere(modifiedWhereStatement); - - long totalResultsCount; - // get total number of results - 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(); + List tags = new ArrayList<>(); + // Use the blackboard artifact tags bearing the specified tag name as the tags. + List artifactTags = (dataSourceId != null && dataSourceId > 0) + ? Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName, dataSourceId) + : Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName); + if (UserPreferences.showOnlyCurrentUserTags()) { + String userName = System.getProperty(USER_NAME_PROPERTY); + for (BlackboardArtifactTag tag : artifactTags) { + if (userName.equals(tag.getUserName())) { + tags.add(tag); + } + } } else { - // do a query to get total number of results - totalResultsCount = getCase().countFilesWhere(originalWhereStatement); + tags.addAll(artifactTags); } List 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 cellValues = Arrays.asList( - file.getName(), // GVDTODO handle . and .. from getContentDisplayName() - // GVDTODO translation column - null, - //GVDTDO replace nulls with SCO - null, - null, - 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, + name, + null, // ELTODO translation column + contentPath, + tag.getArtifact().getDisplayName(), + tag.getComment(), + tag.getUserName()); - file.getKnown().getName(), - StringUtils.defaultString(file.getMd5Hash()), - StringUtils.defaultString(file.getSha256Hash()), - // objectId, - - 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)); + fileRows.add(new BaseRowDTO( + cellValues, + RESULT_TAG_TYPE_ID, + tag.getId())); } - 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 tags = new ArrayList<>(); + List 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 fileRows = new ArrayList<>(); + for (ContentTag tag : tags) { + Content content = tag.getContent(); + String contentPath = content.getUniquePath(); + AbstractFile file = content instanceof AbstractFile ? (AbstractFile) content : null; + + List 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()); + } } diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/TagsSearchParams.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/TagsSearchParams.java index 80a97392a6..2f239047cd 100755 --- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/TagsSearchParams.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/TagsSearchParams.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.mainui.datamodel; import java.util.Objects; +import org.sleuthkit.datamodel.TagName; /** * Key for accessing data about tags from the DAO. @@ -31,25 +32,23 @@ public class TagsSearchParams { } private final TagType type; - private final String tagName; + private final TagName tagName; private final Long dataSourceId; - public TagsSearchParams(String tagName, TagType type, Long dataSourceId) { + public TagsSearchParams(TagName tagName, TagType type, Long dataSourceId) { this.tagName = tagName; this.type = type; this.dataSourceId = dataSourceId; } - public TagsSearchParams(String tagName, TagType type, Long dataSourceId, long startItem, Long maxResultsCount) { - this.tagName = tagName; - this.type = type; - this.dataSourceId = dataSourceId; - } - - public String getMimeType() { + public TagName getTagName() { return tagName; } + public TagType getTagType() { + return type; + } + public Long getDataSourceId() { return dataSourceId; } @@ -75,7 +74,7 @@ public class TagsSearchParams { return false; } final TagsSearchParams other = (TagsSearchParams) obj; - if (!(this.tagName.equals(other.tagName))) { + if (!Objects.equals(this.tagName, other.tagName)) { return false; } if (!Objects.equals(this.dataSourceId, other.dataSourceId)) {