19 package org.sleuthkit.autopsy.datamodel;
 
   21 import com.google.common.util.concurrent.ThreadFactoryBuilder;
 
   22 import java.beans.PropertyChangeEvent;
 
   23 import java.beans.PropertyChangeListener;
 
   24 import java.lang.ref.WeakReference;
 
   25 import java.util.ArrayList;
 
   26 import java.util.EnumSet;
 
   27 import java.util.List;
 
   30 import java.util.concurrent.ExecutorService;
 
   31 import java.util.concurrent.Executors;
 
   32 import java.util.logging.Level;
 
   33 import java.util.stream.Collectors;
 
   34 import org.apache.commons.io.FilenameUtils;
 
   35 import org.apache.commons.lang3.StringUtils;
 
   36 import org.apache.commons.lang3.tuple.Pair;
 
   37 import org.openide.nodes.Children;
 
   38 import org.openide.nodes.Sheet;
 
   39 import org.openide.util.NbBundle;
 
   40 import org.openide.util.WeakListeners;
 
   78     @NbBundle.Messages(
"AbstractAbstractFileNode.addFileProperty.desc=no description")
 
   79     private static final String 
NO_DESCR = AbstractAbstractFileNode_addFileProperty_desc();
 
   92         String ext = abstractFile.getNameExtension();
 
   93         if (StringUtils.isNotBlank(ext)) {
 
  104                     new WeakReference<>(
this), 
weakPcl));
 
  115         translationPool = Executors.newFixedThreadPool(MAX_POOL_SIZE,
 
  116                 new ThreadFactoryBuilder().setNameFormat(
"translation-task-thread-%d").build());
 
  145     enum NodeSpecificEvents {
 
  146         TRANSLATION_AVAILABLE,
 
  149     private final PropertyChangeListener 
pcl = (PropertyChangeEvent evt) -> {
 
  150         String eventType = evt.getPropertyName();
 
  158             if ((moduleContentEvent.getSource() instanceof Content) == 
false) {
 
  161             Content newContent = (Content) moduleContentEvent.getSource();
 
  164             if (
getContent().getId() == newContent.getId()) {
 
  167                     Children parentsChildren = getParentNode().getChildren();
 
  172                     if (parentsChildren instanceof ContentChildren) {
 
  173                         ((ContentChildren) parentsChildren).refreshChildren();
 
  174                         parentsChildren.getNodesCount();
 
  176                 } 
catch (NullPointerException ex) {
 
  181             if (evt.getNewValue() == null) {
 
  193             if (event.getAddedTag().getContent().equals(content)) {
 
  194                 List<ContentTag> tags = getContentTagsFromDatabase();
 
  195                 Pair<Score, String> scorePropAndDescr = getScorePropertyAndDescription(tags);
 
  196                 Score value = scorePropAndDescr.getLeft();
 
  197                 String descr = scorePropAndDescr.getRight();
 
  205             if (event.getDeletedTagInfo().getContentID() == content.getId()) {
 
  206                 List<ContentTag> tags = getContentTagsFromDatabase();
 
  207                 Pair<Score, String> scorePropAndDescr = getScorePropertyAndDescription(tags);
 
  208                 Score value = scorePropAndDescr.getLeft();
 
  209                 String descr = scorePropAndDescr.getRight();
 
  217             if (event.getContentID() == content.getId()) {
 
  218                 List<ContentTag> tags = getContentTagsFromDatabase();
 
  222         } 
else if (eventType.equals(NodeSpecificEvents.TRANSLATION_AVAILABLE.toString())) {
 
  223             this.setDisplayName(evt.getNewValue().toString());
 
  225             this.setShortDescription(content.getName());
 
  237     private final PropertyChangeListener 
weakPcl = WeakListeners.propertyChange(pcl, null);
 
  255         Sheet visibleSheet = this.getSheet();
 
  256         Sheet.Set visibleSheetSet = visibleSheet.get(Sheet.PROPERTIES);
 
  257         Property<?>[] visibleProps = visibleSheetSet.getProperties();
 
  259             for (
int i = 0; i < visibleProps.length; i++) {
 
  260                 if (visibleProps[i].
getName().equals(newProp.getName())) {
 
  261                     visibleProps[i] = newProp;
 
  265         visibleSheetSet.put(visibleProps);
 
  266         visibleSheet.put(visibleSheetSet);
 
  268         this.setSheet(visibleSheet);
 
  279         Sheet sheet = 
new Sheet();
 
  280         Sheet.Set sheetSet = Sheet.createPropertiesSet();
 
  285         newProperties.forEach((property) -> {
 
  286             sheetSet.put(property);
 
  292     @NbBundle.Messages({
"AbstractAbstractFileNode.nameColLbl=Name",
 
  293         "AbstractAbstractFileNode.originalName=Original Name",
 
  294         "AbstractAbstractFileNode.createSheet.score.name=S",
 
  295         "AbstractAbstractFileNode.createSheet.comment.name=C",
 
  296         "AbstractAbstractFileNode.createSheet.count.name=O",
 
  297         "AbstractAbstractFileNode.locationColLbl=Location",
 
  298         "AbstractAbstractFileNode.modifiedTimeColLbl=Modified Time",
 
  299         "AbstractAbstractFileNode.changeTimeColLbl=Change Time",
 
  300         "AbstractAbstractFileNode.accessTimeColLbl=Access Time",
 
  301         "AbstractAbstractFileNode.createdTimeColLbl=Created Time",
 
  302         "AbstractAbstractFileNode.sizeColLbl=Size",
 
  303         "AbstractAbstractFileNode.flagsDirColLbl=Flags(Dir)",
 
  304         "AbstractAbstractFileNode.flagsMetaColLbl=Flags(Meta)",
 
  305         "AbstractAbstractFileNode.modeColLbl=Mode",
 
  306         "AbstractAbstractFileNode.useridColLbl=UserID",
 
  307         "AbstractAbstractFileNode.groupidColLbl=GroupID",
 
  308         "AbstractAbstractFileNode.metaAddrColLbl=Meta Addr.",
 
  309         "AbstractAbstractFileNode.attrAddrColLbl=Attr. Addr.",
 
  310         "AbstractAbstractFileNode.typeDirColLbl=Type(Dir)",
 
  311         "AbstractAbstractFileNode.typeMetaColLbl=Type(Meta)",
 
  312         "AbstractAbstractFileNode.knownColLbl=Known",
 
  313         "AbstractAbstractFileNode.md5HashColLbl=MD5 Hash",
 
  314         "AbstractAbstractFileNode.objectId=Object ID",
 
  315         "AbstractAbstractFileNode.mimeType=MIME Type",
 
  316         "AbstractAbstractFileNode.extensionColLbl=Extension"})
 
  319         NAME(AbstractAbstractFileNode_nameColLbl()),
 
  321         SCORE(AbstractAbstractFileNode_createSheet_score_name()),
 
  322         COMMENT(AbstractAbstractFileNode_createSheet_comment_name()),
 
  324         LOCATION(AbstractAbstractFileNode_locationColLbl()),
 
  325         MOD_TIME(AbstractAbstractFileNode_modifiedTimeColLbl()),
 
  329         SIZE(AbstractAbstractFileNode_sizeColLbl()),
 
  332         MODE(AbstractAbstractFileNode_modeColLbl()),
 
  333         USER_ID(AbstractAbstractFileNode_useridColLbl()),
 
  334         GROUP_ID(AbstractAbstractFileNode_groupidColLbl()),
 
  337         TYPE_DIR(AbstractAbstractFileNode_typeDirColLbl()),
 
  339         KNOWN(AbstractAbstractFileNode_knownColLbl()),
 
  340         MD5HASH(AbstractAbstractFileNode_md5HashColLbl()),
 
  348             this.displayString = displayString;
 
  353             return displayString;
 
  361         List<NodeProperty<?>> properties = 
new ArrayList<>();
 
  362         properties.add(
new NodeProperty<>(NAME.toString(), NAME.toString(), 
NO_DESCR, getContentDisplayName(content)));
 
  373         List<ContentTag> tags = getContentTagsFromDatabase();
 
  377         properties.add(
new NodeProperty<>(SCORE.toString(), SCORE.toString(), scoreAndDescription.getRight(), scoreAndDescription.getLeft()));
 
  381             Pair<Long, String> countAndDescription = getCountPropertyAndDescription(attribute);
 
  382             properties.add(
new NodeProperty<>(OCCURRENCES.toString(), OCCURRENCES.toString(), countAndDescription.getRight(), countAndDescription.getLeft()));
 
  384         properties.add(
new NodeProperty<>(LOCATION.toString(), LOCATION.toString(), 
NO_DESCR, getContentPath(content)));
 
  390         properties.add(
new NodeProperty<>(FLAGS_DIR.toString(), FLAGS_DIR.toString(), 
NO_DESCR, content.getDirFlagAsString()));
 
  391         properties.add(
new NodeProperty<>(FLAGS_META.toString(), FLAGS_META.toString(), 
NO_DESCR, content.getMetaFlagsAsString()));
 
  392         properties.add(
new NodeProperty<>(KNOWN.toString(), KNOWN.toString(), 
NO_DESCR, content.getKnown().getName()));
 
  393         properties.add(
new NodeProperty<>(MD5HASH.toString(), MD5HASH.toString(), 
NO_DESCR, StringUtils.defaultString(content.getMd5Hash())));
 
  394         properties.add(
new NodeProperty<>(MIMETYPE.toString(), MIMETYPE.toString(), 
NO_DESCR, StringUtils.defaultString(content.getMIMEType())));
 
  395         properties.add(
new NodeProperty<>(EXTENSION.toString(), EXTENSION.toString(), 
NO_DESCR, content.getNameExtension()));
 
  409     @NbBundle.Messages(
"AbstractAbstractFileNode.tagsProperty.displayName=Tags")
 
  412         List<ContentTag> tags = getContentTagsFromDatabase();
 
  413         sheetSet.put(
new NodeProperty<>(
"Tags", AbstractAbstractFileNode_tagsProperty_displayName(),
 
  414                 NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName())
 
  416                         .collect(Collectors.joining(
", "))));
 
  432             return StringUtils.join(file.getHashSetNames(), 
", ");
 
  433         } 
catch (TskCoreException tskCoreException) {
 
  434             logger.log(Level.WARNING, 
"Error getting hashset hits: ", tskCoreException); 
 
  440         "AbstractAbstractFileNode.createSheet.count.displayName=O",
 
  441         "AbstractAbstractFileNode.createSheet.count.noCentralRepo.description=Central repository was not enabled when this column was populated",
 
  442         "AbstractAbstractFileNode.createSheet.count.hashLookupNotRun.description=Hash lookup had not been run on this file when the column was populated",
 
  443         "# {0} - occuranceCount",
 
  444         "AbstractAbstractFileNode.createSheet.count.description=There were {0} datasource(s) found with occurances of the correlation value"})
 
  445     Pair<Long, String> getCountPropertyAndDescription(CorrelationAttributeInstance attribute) {
 
  447         String description = Bundle.AbstractAbstractFileNode_createSheet_count_noCentralRepo_description();
 
  450             if (attribute != null && StringUtils.isNotBlank(attribute.getCorrelationValue())) {
 
  451                 count = EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(attribute.getCorrelationType(), attribute.getCorrelationValue());
 
  452                 description = Bundle.AbstractAbstractFileNode_createSheet_count_description(count);
 
  453             } 
else if (attribute != null) {
 
  454                 description = Bundle.AbstractAbstractFileNode_createSheet_count_hashLookupNotRun_description();
 
  456         } 
catch (EamDbException ex) {
 
  457             logger.log(Level.WARNING, 
"Error getting count of datasources with correlation attribute", ex);
 
  458         } 
catch (CorrelationAttributeNormalizationException ex) {
 
  459             logger.log(Level.WARNING, 
"Unable to normalize data to get count of datasources with correlation attribute", ex);
 
  462         return Pair.of(count, description);
 
  466         "AbstractAbstractFileNode.createSheet.score.displayName=S",
 
  467         "AbstractAbstractFileNode.createSheet.notableFile.description=File recognized as notable.",
 
  468         "AbstractAbstractFileNode.createSheet.interestingResult.description=File has interesting result associated with it.",
 
  469         "AbstractAbstractFileNode.createSheet.taggedFile.description=File has been tagged.",
 
  470         "AbstractAbstractFileNode.createSheet.notableTaggedFile.description=File tagged with notable tag.",
 
  471         "AbstractAbstractFileNode.createSheet.noScore.description=No score"})
 
  472     Pair<DataResultViewerTable.Score, String> getScorePropertyAndDescription(List<ContentTag> tags) {
 
  473         DataResultViewerTable.Score score = DataResultViewerTable.Score.NO_SCORE;
 
  474         String description = Bundle.AbstractAbstractFileNode_createSheet_noScore_description();
 
  475         if (content.getKnown() == TskData.FileKnown.BAD) {
 
  476             score = DataResultViewerTable.Score.NOTABLE_SCORE;
 
  477             description = Bundle.AbstractAbstractFileNode_createSheet_notableFile_description();
 
  480             if (score == DataResultViewerTable.Score.NO_SCORE && !content.getArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT).isEmpty()) {
 
  481                 score = DataResultViewerTable.Score.INTERESTING_SCORE;
 
  482                 description = Bundle.AbstractAbstractFileNode_createSheet_interestingResult_description();
 
  484         } 
catch (TskCoreException ex) {
 
  485             logger.log(Level.WARNING, 
"Error getting artifacts for file: " + content.getName(), ex);
 
  487         if (!tags.isEmpty() && (score == DataResultViewerTable.Score.NO_SCORE || score == DataResultViewerTable.Score.INTERESTING_SCORE)) {
 
  488             score = DataResultViewerTable.Score.INTERESTING_SCORE;
 
  489             description = Bundle.AbstractAbstractFileNode_createSheet_taggedFile_description();
 
  490             for (ContentTag tag : tags) {
 
  491                 if (tag.getName().getKnownStatus() == TskData.FileKnown.BAD) {
 
  492                     score = DataResultViewerTable.Score.NOTABLE_SCORE;
 
  493                     description = Bundle.AbstractAbstractFileNode_createSheet_notableTaggedFile_description();
 
  498         return Pair.of(score, description);
 
  502         "AbstractAbstractFileNode.createSheet.comment.displayName=C"})
 
  503     HasCommentStatus getCommentProperty(List<ContentTag> tags, CorrelationAttributeInstance attribute) {
 
  505         DataResultViewerTable.HasCommentStatus status = !tags.isEmpty() ? DataResultViewerTable.HasCommentStatus.TAG_NO_COMMENT : DataResultViewerTable.HasCommentStatus.NO_COMMENT;
 
  507         for (ContentTag tag : tags) {
 
  508             if (!StringUtils.isBlank(tag.getComment())) {
 
  510                 status = DataResultViewerTable.HasCommentStatus.TAG_COMMENT;
 
  514         if (attribute != null && !StringUtils.isBlank(attribute.getComment())) {
 
  515             if (status == DataResultViewerTable.HasCommentStatus.TAG_COMMENT) {
 
  516                 status = DataResultViewerTable.HasCommentStatus.CR_AND_TAG_COMMENTS;
 
  518                 status = DataResultViewerTable.HasCommentStatus.CR_COMMENT;
 
  528     String getTranslatedFileName() {
 
  530         if (content.getName().matches(
"^\\p{ASCII}+$")) {
 
  533         TextTranslationService tts = TextTranslationService.getInstance();
 
  534         if (tts.hasProvider()) {
 
  536             String base = FilenameUtils.getBaseName(content.getName());
 
  538                 String translation = tts.translate(base);
 
  539                 String ext = FilenameUtils.getExtension(content.getName());
 
  542                 String extensionDelimiter = (ext.isEmpty()) ? 
"" : 
".";
 
  546                 if (!translation.isEmpty()) {
 
  547                     return translation + extensionDelimiter + ext;
 
  549             } 
catch (NoServiceProviderException noServiceEx) {
 
  550                 logger.log(Level.WARNING, 
"Translate unsuccessful because no TextTranslator " 
  551                         + 
"implementation was provided.", noServiceEx.getMessage());
 
  552             } 
catch (TranslationException noTranslationEx) {
 
  553                 logger.log(Level.WARNING, 
"Could not successfully translate file name " 
  554                         + content.getName(), noTranslationEx.getMessage());
 
  565     List<ContentTag> getContentTagsFromDatabase() {
 
  566         List<ContentTag> tags = 
new ArrayList<>();
 
  568             tags.addAll(Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByContent(content));
 
  569         } 
catch (TskCoreException | NoCurrentCaseException ex) {
 
  570             logger.log(Level.SEVERE, 
"Failed to get tags for content " + content.getName(), ex);
 
  575     CorrelationAttributeInstance getCorrelationAttributeInstance() {
 
  576         CorrelationAttributeInstance attribute = null;
 
  577         if (EamDb.isEnabled() && !UserPreferences.hideCentralRepoCommentsAndOccurrences()) {
 
  578             attribute = EamArtifactUtil.getInstanceFromContent(content);
 
  583     static String getContentPath(AbstractFile file) {
 
  585             return file.getUniquePath();
 
  586         } 
catch (TskCoreException ex) {
 
  587             logger.log(Level.SEVERE, 
"Except while calling Content.getUniquePath() on " + file.getName(), ex); 
 
  592     static String getContentDisplayName(AbstractFile file) {
 
  593         String name = file.getName();
 
  596                 return DirectoryNode.DOTDOTDIR;
 
  598                 return DirectoryNode.DOTDIR;
 
  615         map.put(NAME.toString(), getContentDisplayName(content));
 
  616         map.put(LOCATION.toString(), getContentPath(content));
 
  621         map.put(SIZE.toString(), content.getSize());
 
  622         map.put(FLAGS_DIR.toString(), content.getDirFlagAsString());
 
  623         map.put(FLAGS_META.toString(), content.getMetaFlagsAsString());
 
  624         map.put(KNOWN.toString(), content.getKnown().getName());
 
  625         map.put(MD5HASH.toString(), StringUtils.defaultString(content.getMd5Hash()));
 
  626         map.put(MIMETYPE.toString(), StringUtils.defaultString(content.getMIMEType()));
 
  627         map.put(EXTENSION.toString(), content.getNameExtension());
 
static final Logger logger
void removeIngestModuleEventListener(final PropertyChangeListener listener)
static String getStringTime(long epochSeconds, TimeZone tzone)
static List< String > getArchiveExtensions()
final String displayString
static synchronized IngestManager getInstance()
synchronized Sheet createSheet()
static void fillPropertyMap(Map< String, Object > map, AbstractFile content)
static final Set< Case.Events > CASE_EVENTS_OF_INTEREST
static boolean displayTranslatedFileNames()
static final ExecutorService translationPool
synchronized void updateSheet(NodeProperty<?>...newProps)
static final String NO_DESCR
static final Integer MAX_POOL_SIZE
AbstractFilePropertyType(String displayString)
void addIngestModuleEventListener(final PropertyChangeListener listener)
synchronized static Logger getLogger(String name)
static void addEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
static boolean hideCentralRepoCommentsAndOccurrences()
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