mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
More work
This commit is contained in:
parent
e8f9ed9fbc
commit
94e8f893a9
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user