19package org.sleuthkit.autopsy.datamodel;
21import java.beans.PropertyChangeEvent;
22import java.beans.PropertyChangeListener;
23import java.lang.ref.WeakReference;
24import java.text.MessageFormat;
25import java.util.ArrayList;
26import java.util.EnumSet;
30import java.util.logging.Level;
31import java.util.stream.Collectors;
32import org.apache.commons.lang3.StringUtils;
33import org.apache.commons.lang3.tuple.Pair;
34import org.openide.nodes.Sheet;
35import org.openide.util.NbBundle;
36import org.openide.util.WeakListeners;
37import org.sleuthkit.autopsy.casemodule.Case;
38import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
39import org.sleuthkit.autopsy.casemodule.events.CommentChangedEvent;
40import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
41import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
42import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbUtil;
43import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
44import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException;
45import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeUtil;
46import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
47import org.sleuthkit.autopsy.core.UserPreferences;
48import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
49import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable.HasCommentStatus;
50import org.sleuthkit.autopsy.coreutils.Logger;
51import static org.sleuthkit.autopsy.datamodel.Bundle.*;
52import static org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFilePropertyType.*;
53import org.sleuthkit.autopsy.datamodel.BaseChildFactory.NoSuchEventBusException;
54import org.sleuthkit.autopsy.datamodel.BaseChildFactory.RefreshKeysEvent;
55import org.sleuthkit.autopsy.ingest.IngestManager;
56import static org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent.CONTENT_CHANGED;
57import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
58import org.sleuthkit.autopsy.texttranslation.NoServiceProviderException;
59import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
60import org.sleuthkit.autopsy.texttranslation.TranslationException;
61import org.sleuthkit.datamodel.AbstractFile;
62import org.sleuthkit.datamodel.Content;
63import org.sleuthkit.datamodel.ContentTag;
64import org.sleuthkit.datamodel.Tag;
65import org.sleuthkit.datamodel.TskCoreException;
66import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
67import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
68import org.sleuthkit.autopsy.texttranslation.utils.FileNameTranslationUtil;
69import org.sleuthkit.datamodel.Score;
70import org.sleuthkit.datamodel.VirtualDirectory;
77public abstract class AbstractAbstractFileNode<T
extends AbstractFile> extends AbstractContentNode<T> {
88 AbstractAbstractFileNode(T abstractFile) {
90 String ext = abstractFile.getNameExtension();
91 if (StringUtils.isNotBlank(ext)) {
101 if (VirtualDirectory.NAME_CARVED.equals(abstractFile.getName())) {
109 }
catch (TskCoreException ex) {
110 logger.log(Level.SEVERE, String.format(
"Failed attempt to cache the "
111 +
"unique path of the abstract file instance. Name: %s (objID=%d)",
112 this.content.getName(),
this.content.getId()), ex);
116 backgroundTasksPool.submit(
new TranslationTask(
117 new WeakReference<>(
this),
weakPcl));
145 private final PropertyChangeListener
pcl = (PropertyChangeEvent evt) -> {
146 String eventType = evt.getPropertyName();
154 if ((moduleContentEvent.getSource() instanceof Content) ==
false) {
157 Content newContent = (Content) moduleContentEvent.getSource();
160 if (
getContent().getId() == newContent.getId()) {
174 }
catch (NullPointerException ex) {
177 logger.log(Level.WARNING,
"Failed to post key refresh event", ex);
181 if (evt.getNewValue() ==
null) {
193 if (event.getAddedTag().getContent().equals(
content)) {
196 Score value = scorePropAndDescr.getLeft();
197 String descr = scorePropAndDescr.getRight();
198 List<CorrelationAttributeInstance> listWithJustFileAttr =
new ArrayList<>();
200 if (corrInstance !=
null) {
201 listWithJustFileAttr.add(corrInstance);
209 if (event.getDeletedTagInfo().getContentID() ==
content.getId()) {
212 Score value = scorePropAndDescr.getLeft();
213 String descr = scorePropAndDescr.getRight();
214 List<CorrelationAttributeInstance> listWithJustFileAttr =
new ArrayList<>();
216 if (corrInstance !=
null) {
217 listWithJustFileAttr.add(corrInstance);
225 if (event.getContentID() ==
content.getId()) {
226 List<CorrelationAttributeInstance> listWithJustFileAttr =
new ArrayList<>();
228 if (corrInstance !=
null) {
229 listWithJustFileAttr.add(corrInstance);
233 }
else if (eventType.equals(NodeSpecificEvents.TRANSLATION_AVAILABLE.toString())) {
234 this.setDisplayName(evt.getNewValue().toString());
236 this.setShortDescription(
content.getName());
239 SCOData scoData = (SCOData) evt.getNewValue();
240 if (scoData.getScoreAndDescription() !=
null) {
241 updateSheet(
new NodeProperty<>(SCORE.toString(), SCORE.toString(), scoData.getScoreAndDescription().getRight(), scoData.getScoreAndDescription().getLeft()));
243 if (scoData.getComment() !=
null) {
246 if (scoData.getCountAndDescription() !=
null) {
247 updateSheet(
new NodeProperty<>(OCCURRENCES.toString(), OCCURRENCES.toString(), scoData.getCountAndDescription().getRight(), scoData.getCountAndDescription().getLeft()));
259 private final PropertyChangeListener
weakPcl = WeakListeners.propertyChange(
pcl,
null);
269 Sheet sheet =
new Sheet();
270 Sheet.Set sheetSet = Sheet.createPropertiesSet();
275 newProperties.forEach((property) -> {
276 sheetSet.put(property);
282 @NbBundle.Messages({
"AbstractAbstractFileNode.nameColLbl=Name",
283 "AbstractAbstractFileNode.originalName=Original Name",
284 "AbstractAbstractFileNode.createSheet.score.name=S",
285 "AbstractAbstractFileNode.createSheet.comment.name=C",
286 "AbstractAbstractFileNode.createSheet.count.name=O",
287 "AbstractAbstractFileNode.locationColLbl=Location",
288 "AbstractAbstractFileNode.modifiedTimeColLbl=Modified Time",
289 "AbstractAbstractFileNode.changeTimeColLbl=Change Time",
290 "AbstractAbstractFileNode.accessTimeColLbl=Access Time",
291 "AbstractAbstractFileNode.createdTimeColLbl=Created Time",
292 "AbstractAbstractFileNode.sizeColLbl=Size",
293 "AbstractAbstractFileNode.flagsDirColLbl=Flags(Dir)",
294 "AbstractAbstractFileNode.flagsMetaColLbl=Flags(Meta)",
295 "AbstractAbstractFileNode.modeColLbl=Mode",
296 "AbstractAbstractFileNode.useridColLbl=UserID",
297 "AbstractAbstractFileNode.groupidColLbl=GroupID",
298 "AbstractAbstractFileNode.metaAddrColLbl=Meta Addr.",
299 "AbstractAbstractFileNode.attrAddrColLbl=Attr. Addr.",
300 "AbstractAbstractFileNode.typeDirColLbl=Type(Dir)",
301 "AbstractAbstractFileNode.typeMetaColLbl=Type(Meta)",
302 "AbstractAbstractFileNode.knownColLbl=Known",
303 "AbstractAbstractFileNode.md5HashColLbl=MD5 Hash",
304 "AbstractAbstractFileNode.sha256HashColLbl=SHA-256 Hash",
305 "AbstractAbstractFileNode.objectId=Object ID",
306 "AbstractAbstractFileNode.mimeType=MIME Type",
307 "AbstractAbstractFileNode.extensionColLbl=Extension"})
310 NAME(AbstractAbstractFileNode_nameColLbl()),
312 SCORE(AbstractAbstractFileNode_createSheet_score_name()),
313 COMMENT(AbstractAbstractFileNode_createSheet_comment_name()),
315 LOCATION(AbstractAbstractFileNode_locationColLbl()),
316 MOD_TIME(AbstractAbstractFileNode_modifiedTimeColLbl()),
320 SIZE(AbstractAbstractFileNode_sizeColLbl()),
323 MODE(AbstractAbstractFileNode_modeColLbl()),
324 USER_ID(AbstractAbstractFileNode_useridColLbl()),
325 GROUP_ID(AbstractAbstractFileNode_groupidColLbl()),
328 TYPE_DIR(AbstractAbstractFileNode_typeDirColLbl()),
330 KNOWN(AbstractAbstractFileNode_knownColLbl()),
331 MD5HASH(AbstractAbstractFileNode_md5HashColLbl()),
353 List<NodeProperty<?>> properties =
new ArrayList<>();
372 backgroundTasksPool.submit(
new GetSCOTask(
373 new WeakReference<>(
this),
weakPcl));
386 properties.add(
new NodeProperty<>(SHA256HASH.toString(), SHA256HASH.toString(),
NO_DESCR, StringUtils.defaultString(
content.getSha256Hash())));
402 @NbBundle.Messages(
"AbstractAbstractFileNode.tagsProperty.displayName=Tags")
405 List<ContentTag>
tags = getContentTagsFromDatabase();
406 sheetSet.put(
new NodeProperty<>(
"Tags", AbstractAbstractFileNode_tagsProperty_displayName(),
407 NO_DESCR,
tags.stream().map(t -> t.getName().getDisplayName())
409 .collect(Collectors.joining(
", "))));
425 return StringUtils.join(file.getHashSetNames(),
", ");
426 }
catch (TskCoreException tskCoreException) {
427 logger.log(Level.WARNING,
"Error getting hashset hits: ", tskCoreException);
433 "AbstractAbstractFileNode.createSheet.count.displayName=O",
434 "AbstractAbstractFileNode.createSheet.count.hashLookupNotRun.description=Hash lookup had not been run on this file when the column was populated",
435 "# {0} - occurrenceCount",
436 "AbstractAbstractFileNode.createSheet.count.description=There were {0} datasource(s) found with occurrences of the MD5 correlation value"})
440 String description = defaultDescription;
443 if (attributeInstance !=
null && StringUtils.isNotBlank(attributeInstance.
getCorrelationValue())) {
445 description = Bundle.AbstractAbstractFileNode_createSheet_count_description(count);
446 }
else if (attributeInstance !=
null) {
447 description = Bundle.AbstractAbstractFileNode_createSheet_count_hashLookupNotRun_description();
450 logger.log(Level.SEVERE,
"Error getting count of datasources with correlation attribute", ex);
452 logger.log(Level.WARNING,
"Unable to normalize data to get count of datasources with correlation attribute", ex);
454 return Pair.of(count, description);
458 "AbstractAbstractFileNode.createSheet.comment.displayName=C"})
462 for (Tag tag :
tags) {
463 if (!StringUtils.isBlank(tag.getComment())) {
482 logger.log(Level.SEVERE,
"Attempted to Query CR for presence of comments in a file node and was unable to perform query, comment column will only reflect caseDB", ex);
493 String getTranslatedFileName() {
496 }
catch (NoServiceProviderException | TranslationException ex) {
497 logger.log(Level.WARNING, MessageFormat.format(
"Error translating file name (objID={0}))",
content.getId()), ex);
507 List<ContentTag> getContentTagsFromDatabase() {
508 List<ContentTag> tags =
new ArrayList<>();
510 tags.addAll(Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByContent(
content));
511 }
catch (TskCoreException | NoCurrentCaseException ex) {
512 logger.log(Level.SEVERE,
"Failed to get tags for content " +
content.getName(), ex);
519 return new ArrayList<>(getContentTagsFromDatabase());
522 static String getContentPath(AbstractFile file) {
524 return file.getUniquePath();
525 }
catch (TskCoreException ex) {
526 logger.log(Level.SEVERE,
"Except while calling Content.getUniquePath() on " + file.getName(), ex);
531 static String getContentDisplayName(AbstractFile file) {
532 String name = file.getName();
535 return DirectoryNode.DOTDOTDIR;
537 return DirectoryNode.DOTDIR;
554 map.put(NAME.toString(), getContentDisplayName(
content));
555 map.put(LOCATION.toString(), getContentPath(
content));
560 map.put(SIZE.toString(),
content.getSize());
561 map.put(FLAGS_DIR.toString(),
content.getDirFlagAsString());
562 map.put(FLAGS_META.toString(),
content.getMetaFlagsAsString());
563 map.put(KNOWN.toString(),
content.getKnown().getName());
564 map.put(MD5HASH.toString(), StringUtils.defaultString(
content.getMd5Hash()));
565 map.put(SHA256HASH.toString(), StringUtils.defaultString(
content.getSha256Hash()));
566 map.put(MIMETYPE.toString(), StringUtils.defaultString(
content.getMIMEType()));
567 map.put(EXTENSION.toString(),
content.getNameExtension());
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
static void addEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
static boolean commentExistsOnAttributes(List< CorrelationAttributeInstance > attributes)
String getCorrelationValue()
static CorrelationAttributeInstance getCorrAttrForFile(AbstractFile file)
static boolean displayTranslatedFileNames()
static boolean getHideSCOColumns()
synchronized static Logger getLogger(String name)
static String getFormattedTime(long epochTime)
Pair< Long, String > getCountPropertyAndDescription(CorrelationAttributeInstance attributeInstance, String defaultDescription)
static void fillPropertyMap(Map< String, Object > map, AbstractFile content)
static final Set< IngestManager.IngestModuleEvent > INGEST_MODULE_EVENTS_OF_INTEREST
List< NodeProperty<?> > getProperties()
static final Set< Case.Events > CASE_EVENTS_OF_INTEREST
HasCommentStatus getCommentProperty(List< Tag > tags, List< CorrelationAttributeInstance > attributes)
synchronized Sheet createSheet()
void addTagProperty(Sheet.Set sheetSet)
final PropertyChangeListener pcl
List< Tag > getAllTagsFromDatabase()
final PropertyChangeListener weakPcl
static final Logger logger
static String getHashSetHitsCsvList(AbstractFile file)
static final String NO_DESCR
static final String VALUE_LOADING
synchronized void updateSheet(NodeProperty<?>... newProps)
Pair< Score, String > getScorePropertyAndDescription()
static void post(String nodeName, Object event)
static List< String > getArchiveExtensions()
static synchronized IngestManager getInstance()
void removeIngestModuleEventListener(final PropertyChangeListener listener)
void addIngestModuleEventListener(final PropertyChangeListener listener)
synchronized boolean hasProvider()
static TextTranslationService getInstance()
static String translate(String fileName)
AbstractFilePropertyType(String displayString)
final String displayString
Long getCountCasesWithOtherInstances(CorrelationAttributeInstance instance)
static CentralRepository getInstance()
static boolean isEnabled()