19 package org.sleuthkit.autopsy.datamodel;
 
   21 import java.beans.PropertyChangeEvent;
 
   22 import java.beans.PropertyChangeListener;
 
   23 import java.lang.ref.WeakReference;
 
   24 import java.util.ArrayList;
 
   25 import java.util.EnumSet;
 
   26 import java.util.List;
 
   29 import java.util.logging.Level;
 
   30 import java.util.stream.Collectors;
 
   31 import org.apache.commons.io.FilenameUtils;
 
   32 import org.apache.commons.lang3.StringUtils;
 
   33 import org.apache.commons.lang3.tuple.Pair;
 
   34 import org.openide.nodes.Sheet;
 
   35 import org.openide.util.NbBundle;
 
   36 import org.openide.util.WeakListeners;
 
   88         String ext = abstractFile.getNameExtension();
 
   89         if (StringUtils.isNotBlank(ext)) {
 
   99             backgroundTasksPool.submit(
new TranslationTask(
 
  100                     new WeakReference<>(
this), 
weakPcl));
 
  128     private final PropertyChangeListener 
pcl = (PropertyChangeEvent evt) -> {
 
  129         String eventType = evt.getPropertyName();
 
  137             if ((moduleContentEvent.getSource() instanceof Content) == 
false) {
 
  140             Content newContent = (Content) moduleContentEvent.getSource();
 
  143             if (
getContent().getId() == newContent.getId()) {
 
  151                 } 
catch (NullPointerException ex) {
 
  154                     logger.log(Level.WARNING, 
"Failed to post key refresh event", ex); 
 
  158             if (evt.getNewValue() == null) {
 
  170             if (event.getAddedTag().getContent().equals(content)) {
 
  173                 Score value = scorePropAndDescr.getLeft();
 
  174                 String descr = scorePropAndDescr.getRight();
 
  182             if (event.getDeletedTagInfo().getContentID() == content.getId()) {
 
  185                 Score value = scorePropAndDescr.getLeft();
 
  186                 String descr = scorePropAndDescr.getRight();
 
  194             if (event.getContentID() == content.getId()) {
 
  199         } 
else if (eventType.equals(NodeSpecificEvents.TRANSLATION_AVAILABLE.toString())) {
 
  200             this.setDisplayName(evt.getNewValue().toString());
 
  202             this.setShortDescription(content.getName());
 
  205             SCOData scoData = (SCOData) evt.getNewValue();
 
  206             if (scoData.getScoreAndDescription() != null) {
 
  207                 updateSheet(
new NodeProperty<>(SCORE.toString(), SCORE.toString(), scoData.getScoreAndDescription().getRight(), scoData.getScoreAndDescription().getLeft()));
 
  209             if (scoData.getComment() != null) {
 
  212             if (scoData.getCountAndDescription() != null) {
 
  213                 updateSheet(
new NodeProperty<>(OCCURRENCES.toString(), OCCURRENCES.toString(), scoData.getCountAndDescription().getRight(), scoData.getCountAndDescription().getLeft()));
 
  225     private final PropertyChangeListener 
weakPcl = WeakListeners.propertyChange(pcl, null);
 
  235         Sheet sheet = 
new Sheet();
 
  236         Sheet.Set sheetSet = Sheet.createPropertiesSet();
 
  241         newProperties.forEach((property) -> {
 
  242             sheetSet.put(property);
 
  248     @NbBundle.Messages({
"AbstractAbstractFileNode.nameColLbl=Name",
 
  249         "AbstractAbstractFileNode.originalName=Original Name",
 
  250         "AbstractAbstractFileNode.createSheet.score.name=S",
 
  251         "AbstractAbstractFileNode.createSheet.comment.name=C",
 
  252         "AbstractAbstractFileNode.createSheet.count.name=O",
 
  253         "AbstractAbstractFileNode.locationColLbl=Location",
 
  254         "AbstractAbstractFileNode.modifiedTimeColLbl=Modified Time",
 
  255         "AbstractAbstractFileNode.changeTimeColLbl=Change Time",
 
  256         "AbstractAbstractFileNode.accessTimeColLbl=Access Time",
 
  257         "AbstractAbstractFileNode.createdTimeColLbl=Created Time",
 
  258         "AbstractAbstractFileNode.sizeColLbl=Size",
 
  259         "AbstractAbstractFileNode.flagsDirColLbl=Flags(Dir)",
 
  260         "AbstractAbstractFileNode.flagsMetaColLbl=Flags(Meta)",
 
  261         "AbstractAbstractFileNode.modeColLbl=Mode",
 
  262         "AbstractAbstractFileNode.useridColLbl=UserID",
 
  263         "AbstractAbstractFileNode.groupidColLbl=GroupID",
 
  264         "AbstractAbstractFileNode.metaAddrColLbl=Meta Addr.",
 
  265         "AbstractAbstractFileNode.attrAddrColLbl=Attr. Addr.",
 
  266         "AbstractAbstractFileNode.typeDirColLbl=Type(Dir)",
 
  267         "AbstractAbstractFileNode.typeMetaColLbl=Type(Meta)",
 
  268         "AbstractAbstractFileNode.knownColLbl=Known",
 
  269         "AbstractAbstractFileNode.md5HashColLbl=MD5 Hash",
 
  270         "AbstractAbstractFileNode.objectId=Object ID",
 
  271         "AbstractAbstractFileNode.mimeType=MIME Type",
 
  272         "AbstractAbstractFileNode.extensionColLbl=Extension"})
 
  275         NAME(AbstractAbstractFileNode_nameColLbl()),
 
  277         SCORE(AbstractAbstractFileNode_createSheet_score_name()),
 
  278         COMMENT(AbstractAbstractFileNode_createSheet_comment_name()),
 
  280         LOCATION(AbstractAbstractFileNode_locationColLbl()),
 
  281         MOD_TIME(AbstractAbstractFileNode_modifiedTimeColLbl()),
 
  285         SIZE(AbstractAbstractFileNode_sizeColLbl()),
 
  288         MODE(AbstractAbstractFileNode_modeColLbl()),
 
  289         USER_ID(AbstractAbstractFileNode_useridColLbl()),
 
  290         GROUP_ID(AbstractAbstractFileNode_groupidColLbl()),
 
  293         TYPE_DIR(AbstractAbstractFileNode_typeDirColLbl()),
 
  295         KNOWN(AbstractAbstractFileNode_knownColLbl()),
 
  296         MD5HASH(AbstractAbstractFileNode_md5HashColLbl()),
 
  304             this.displayString = displayString;
 
  309             return displayString;
 
  317         List<NodeProperty<?>> properties = 
new ArrayList<>();
 
  318         properties.add(
new NodeProperty<>(NAME.toString(), NAME.toString(), 
NO_DESCR, getContentDisplayName(content)));
 
  336             backgroundTasksPool.submit(
new GetSCOTask(
 
  337                     new WeakReference<>(
this), weakPcl));
 
  345         properties.add(
new NodeProperty<>(FLAGS_DIR.toString(), FLAGS_DIR.toString(), 
NO_DESCR, content.getDirFlagAsString()));
 
  346         properties.add(
new NodeProperty<>(FLAGS_META.toString(), FLAGS_META.toString(), 
NO_DESCR, content.getMetaFlagsAsString()));
 
  347         properties.add(
new NodeProperty<>(KNOWN.toString(), KNOWN.toString(), 
NO_DESCR, content.getKnown().getName()));
 
  348         properties.add(
new NodeProperty<>(LOCATION.toString(), LOCATION.toString(), 
NO_DESCR, getContentPath(content)));
 
  349         properties.add(
new NodeProperty<>(MD5HASH.toString(), MD5HASH.toString(), 
NO_DESCR, StringUtils.defaultString(content.getMd5Hash())));
 
  350         properties.add(
new NodeProperty<>(MIMETYPE.toString(), MIMETYPE.toString(), 
NO_DESCR, StringUtils.defaultString(content.getMIMEType())));
 
  351         properties.add(
new NodeProperty<>(EXTENSION.toString(), EXTENSION.toString(), 
NO_DESCR, content.getNameExtension()));
 
  365     @NbBundle.Messages(
"AbstractAbstractFileNode.tagsProperty.displayName=Tags")
 
  368         List<ContentTag> tags = getContentTagsFromDatabase();
 
  369         sheetSet.put(
new NodeProperty<>(
"Tags", AbstractAbstractFileNode_tagsProperty_displayName(),
 
  370                 NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName())
 
  372                         .collect(Collectors.joining(
", "))));
 
  388             return StringUtils.join(file.getHashSetNames(), 
", ");
 
  389         } 
catch (TskCoreException tskCoreException) {
 
  390             logger.log(Level.WARNING, 
"Error getting hashset hits: ", tskCoreException); 
 
  396         "AbstractAbstractFileNode.createSheet.count.displayName=O",
 
  397         "AbstractAbstractFileNode.createSheet.count.hashLookupNotRun.description=Hash lookup had not been run on this file when the column was populated",
 
  398         "# {0} - occurrenceCount",
 
  399         "AbstractAbstractFileNode.createSheet.count.description=There were {0} datasource(s) found with occurrences of the MD5 correlation value"})
 
  402             String defaultDescription) {
 
  404         String description = defaultDescription;
 
  407             if (attributeType != null && StringUtils.isNotBlank(attributeValue)) {
 
  409                 description = Bundle.AbstractAbstractFileNode_createSheet_count_description(count);
 
  410             } 
else if (attributeType != null) {
 
  411                 description = Bundle.AbstractAbstractFileNode_createSheet_count_hashLookupNotRun_description();
 
  414             logger.log(Level.WARNING, 
"Error getting count of datasources with correlation attribute", ex);
 
  416             logger.log(Level.WARNING, 
"Unable to normalize data to get count of datasources with correlation attribute", ex);
 
  418         return Pair.of(count, description);
 
  422         "AbstractAbstractFileNode.createSheet.score.displayName=S",
 
  423         "AbstractAbstractFileNode.createSheet.notableFile.description=File recognized as notable.",
 
  424         "AbstractAbstractFileNode.createSheet.interestingResult.description=File has interesting result associated with it.",
 
  425         "AbstractAbstractFileNode.createSheet.taggedFile.description=File has been tagged.",
 
  426         "AbstractAbstractFileNode.createSheet.notableTaggedFile.description=File tagged with notable tag.",
 
  427         "AbstractAbstractFileNode.createSheet.noScore.description=No score"})
 
  431         String description = Bundle.AbstractAbstractFileNode_createSheet_noScore_description();
 
  432         if (content.getKnown() == TskData.FileKnown.BAD) {
 
  434             description = Bundle.AbstractAbstractFileNode_createSheet_notableFile_description();
 
  439                 description = Bundle.AbstractAbstractFileNode_createSheet_interestingResult_description();
 
  441         } 
catch (TskCoreException ex) {
 
  442             logger.log(Level.WARNING, 
"Error getting artifacts for file: " + content.getName(), ex);
 
  446             description = Bundle.AbstractAbstractFileNode_createSheet_taggedFile_description();
 
  447             for (Tag tag : tags) {
 
  448                 if (tag.getName().getKnownStatus() == TskData.FileKnown.BAD) {
 
  450                     description = Bundle.AbstractAbstractFileNode_createSheet_notableTaggedFile_description();
 
  455         return Pair.of(score, description);
 
  459         "AbstractAbstractFileNode.createSheet.comment.displayName=C"})
 
  465         for (Tag tag : tags) {
 
  466             if (!StringUtils.isBlank(tag.getComment())) {
 
  472         if (attribute != null && !StringUtils.isBlank(attribute.
getComment())) {
 
  486     String getTranslatedFileName() {
 
  488         if (content.getName().matches(
"^\\p{ASCII}+$")) {
 
  491         TextTranslationService tts = TextTranslationService.getInstance();
 
  492         if (tts.hasProvider()) {
 
  494             String base = FilenameUtils.getBaseName(content.getName());
 
  496                 String translation = tts.translate(base);
 
  497                 String ext = FilenameUtils.getExtension(content.getName());
 
  500                 String extensionDelimiter = (ext.isEmpty()) ? 
"" : 
".";
 
  504                 if (!translation.isEmpty()) {
 
  505                     return translation + extensionDelimiter + ext;
 
  507             } 
catch (NoServiceProviderException noServiceEx) {
 
  508                 logger.log(Level.WARNING, 
"Translate unsuccessful because no TextTranslator " 
  509                         + 
"implementation was provided.", noServiceEx.getMessage());
 
  510             } 
catch (TranslationException noTranslationEx) {
 
  511                 logger.log(Level.WARNING, 
"Could not successfully translate file name " 
  512                         + content.getName(), noTranslationEx.getMessage());
 
  523     List<ContentTag> getContentTagsFromDatabase() {
 
  524         List<ContentTag> tags = 
new ArrayList<>();
 
  526             tags.addAll(Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByContent(content));
 
  527         } 
catch (TskCoreException | NoCurrentCaseException ex) {
 
  528             logger.log(Level.SEVERE, 
"Failed to get tags for content " + content.getName(), ex);
 
  535         return new ArrayList<>(getContentTagsFromDatabase());
 
  547     static String getContentPath(AbstractFile file) {
 
  549             return file.getUniquePath();
 
  550         } 
catch (TskCoreException ex) {
 
  551             logger.log(Level.SEVERE, 
"Except while calling Content.getUniquePath() on " + file.getName(), ex); 
 
  556     static String getContentDisplayName(AbstractFile file) {
 
  557         String name = file.getName();
 
  560                 return DirectoryNode.DOTDOTDIR;
 
  562                 return DirectoryNode.DOTDIR;
 
  579         map.put(NAME.toString(), getContentDisplayName(content));
 
  580         map.put(LOCATION.toString(), getContentPath(content));
 
  585         map.put(SIZE.toString(), content.getSize());
 
  586         map.put(FLAGS_DIR.toString(), content.getDirFlagAsString());
 
  587         map.put(FLAGS_META.toString(), content.getMetaFlagsAsString());
 
  588         map.put(KNOWN.toString(), content.getKnown().getName());
 
  589         map.put(MD5HASH.toString(), StringUtils.defaultString(content.getMd5Hash()));
 
  590         map.put(MIMETYPE.toString(), StringUtils.defaultString(content.getMIMEType()));
 
  591         map.put(EXTENSION.toString(), content.getNameExtension());
 
synchronized void updateSheet(NodeProperty<?>...newProps)
 
static final Logger logger
 
static final String VALUE_LOADING
 
void removeIngestModuleEventListener(final PropertyChangeListener listener)
 
static String getStringTime(long epochSeconds, TimeZone tzone)
 
static List< String > getArchiveExtensions()
 
final String displayString
 
static synchronized IngestManager getInstance()
 
CorrelationAttributeInstance getCorrelationAttributeInstance()
 
synchronized Sheet createSheet()
 
static final Set< IngestManager.IngestModuleEvent > INGEST_MODULE_EVENTS_OF_INTEREST
 
Pair< DataResultViewerTable.Score, String > getScorePropertyAndDescription(List< Tag > tags)
 
List< Tag > getAllTagsFromDatabase()
 
static void fillPropertyMap(Map< String, Object > map, AbstractFile content)
 
Long getCountUniqueCaseDataSourceTuplesHavingTypeValue(CorrelationAttributeInstance.Type aType, String value)
 
static final Set< Case.Events > CASE_EVENTS_OF_INTEREST
 
static EamDb getInstance()
 
static boolean displayTranslatedFileNames()
 
static CorrelationAttributeInstance getInstanceFromContent(Content content)
 
Pair< Long, String > getCountPropertyAndDescription(CorrelationAttributeInstance.Type attributeType, String attributeValue, String defaultDescription)
 
static boolean getHideSCOColumns()
 
static boolean isEnabled()
 
AbstractFilePropertyType(String displayString)
 
static void post(String nodeName, Object event)
 
void addIngestModuleEventListener(final PropertyChangeListener listener)
 
synchronized static Logger getLogger(String name)
 
HasCommentStatus getCommentProperty(List< Tag > tags, CorrelationAttributeInstance attribute)
 
static void addEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
 
final PropertyChangeListener pcl
 
List< NodeProperty<?> > getProperties()
 
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
 
static String getHashSetHitsCsvList(AbstractFile file)
 
void addTagProperty(Sheet.Set sheetSet)
 
final PropertyChangeListener weakPcl
 
static final String NO_DESCR