19 package org.sleuthkit.autopsy.contentviewers.annotations;
 
   21 import java.util.ArrayList;
 
   22 import java.util.Arrays;
 
   23 import java.util.List;
 
   24 import java.util.function.Function;
 
   25 import java.util.logging.Level;
 
   26 import java.util.stream.Collectors;
 
   27 import org.apache.commons.lang.StringUtils;
 
   28 import org.apache.commons.lang3.tuple.Pair;
 
   29 import org.jsoup.Jsoup;
 
   30 import org.jsoup.nodes.Document;
 
   31 import org.jsoup.nodes.Element;
 
   32 import org.openide.nodes.Node;
 
   33 import org.openide.util.NbBundle;
 
   62         "AnnotationUtils.title=Annotations",
 
   63         "AnnotationUtils.toolTip=Displays tags and comments associated with the selected content.",
 
   64         "AnnotationUtils.centralRepositoryEntry.title=Central Repository Comments",
 
   65         "AnnotationUtils.centralRepositoryEntryDataLabel.case=Case:",
 
   66         "AnnotationUtils.centralRepositoryEntryDataLabel.type=Type:",
 
   67         "AnnotationUtils.centralRepositoryEntryDataLabel.comment=Comment:",
 
   68         "AnnotationUtils.centralRepositoryEntryDataLabel.path=Path:",
 
   69         "AnnotationUtils.tagEntry.title=Tags",
 
   70         "AnnotationUtils.tagEntryDataLabel.tag=Tag:",
 
   71         "AnnotationUtils.tagEntryDataLabel.tagUser=Examiner:",
 
   72         "AnnotationUtils.tagEntryDataLabel.comment=Comment:",
 
   73         "AnnotationUtils.fileHitEntry.artifactCommentTitle=Artifact Comment",
 
   74         "AnnotationUtils.fileHitEntry.hashSetHitTitle=Hash Set Hit Comments",
 
   75         "AnnotationUtils.fileHitEntry.interestingFileHitTitle=Interesting File Hit Comments",
 
   76         "AnnotationUtils.fileHitEntry.setName=Set Name:",
 
   77         "AnnotationUtils.fileHitEntry.comment=Comment:",
 
   78         "AnnotationUtils.sourceFile.title=Source File",
 
   79         "AnnotationUtils.onEmpty=No annotations were found for this particular item." 
   84     private static final String 
EMPTY_HTML = 
"<html><head></head><body></body></html>";
 
   87     private static final List<ItemEntry<Tag>> 
TAG_ENTRIES = Arrays.asList(
 
   88             new ItemEntry<>(Bundle.AnnotationUtils_tagEntryDataLabel_tag(),
 
   89                     (tag) -> (tag.getName() != null) ? tag.getName().getDisplayName() : null),
 
   90             new ItemEntry<>(Bundle.AnnotationUtils_tagEntryDataLabel_tagUser(), (tag) -> tag.getUserName()),
 
   91             new ItemEntry<>(Bundle.AnnotationUtils_tagEntryDataLabel_comment(), (tag) -> tag.getComment())
 
   94     private static final SectionConfig<Tag> 
TAG_CONFIG 
   95             = 
new SectionConfig<>(Bundle.AnnotationUtils_tagEntry_title(), 
TAG_ENTRIES);
 
   99             new ItemEntry<>(Bundle.AnnotationUtils_fileHitEntry_setName(),
 
  100                     (bba) -> 
tryGetAttribute(bba, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)),
 
  101             new ItemEntry<>(Bundle.AnnotationUtils_fileHitEntry_comment(),
 
  102                     (bba) -> 
tryGetAttribute(bba, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT))
 
  106             = 
new SectionConfig<>(Bundle.AnnotationUtils_fileHitEntry_interestingFileHitTitle(), 
FILESET_HIT_ENTRIES);
 
  108     private static final SectionConfig<BlackboardArtifact> 
HASHSET_CONFIG 
  116             new ItemEntry<>(Bundle.AnnotationUtils_centralRepositoryEntryDataLabel_case(),
 
  117                     cai -> (cai.getCorrelationCase() != null) ? cai.getCorrelationCase().getDisplayName() : null),
 
  118             new ItemEntry<>(Bundle.AnnotationUtils_centralRepositoryEntryDataLabel_comment(), cai -> cai.getComment()),
 
  119             new ItemEntry<>(Bundle.AnnotationUtils_centralRepositoryEntryDataLabel_path(), cai -> cai.getFilePath())
 
  140     static DisplayTskItems getDisplayContent(Node node) {
 
  142         BlackboardArtifact artifact = artItem == null ? null : artItem.
getTskContent();
 
  144         Content content = artItem != null
 
  146                 : node.getLookup().lookup(AbstractFile.class);
 
  148         return new DisplayTskItems(artifact, content);
 
  159         return getDisplayContent(node).getContent() != null;
 
  172         Document html = Jsoup.parse(EMPTY_HTML);
 
  173         Element body = html.getElementsByTag(
"body").first();
 
  175         DisplayTskItems displayItems = getDisplayContent(node);
 
  176         BlackboardArtifact artifact = displayItems.getArtifact();
 
  177         Content srcContent = displayItems.getContent();
 
  179         boolean somethingWasRendered = 
false;
 
  180         if (artifact != null) {
 
  181             somethingWasRendered = 
renderArtifact(body, artifact, srcContent);
 
  183             somethingWasRendered = 
renderContent(body, srcContent, 
false);
 
  186         if (!somethingWasRendered) {
 
  203     private static boolean renderArtifact(Element parent, BlackboardArtifact bba, Content sourceContent) {
 
  209             contentRendered = contentRendered || crRendered;
 
  213         if ((BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() == bba.getArtifactTypeID()
 
  214                 || BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() == bba.getArtifactTypeID())
 
  218             contentRendered = contentRendered || filesetRendered;
 
  221         Element sourceFileSection = 
appendSection(parent, Bundle.AnnotationUtils_sourceFile_title());
 
  224         Element sourceFileContainer = sourceFileSection.appendElement(
"div");
 
  227         boolean sourceFileRendered = 
renderContent(sourceFileContainer, sourceContent, 
true);
 
  229         if (!sourceFileRendered) {
 
  230             sourceFileSection.remove();
 
  233         return contentRendered || sourceFileRendered;
 
  246     private static boolean renderContent(Element parent, Content sourceContent, 
boolean isSubheader) {
 
  249         if (sourceContent instanceof AbstractFile) {
 
  250             AbstractFile sourceFile = (AbstractFile) sourceContent;
 
  256                 contentRendered = contentRendered || crRendered;
 
  260                     getFileSetHits(sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT),
 
  265                     getFileSetHits(sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT),
 
  269             contentRendered = contentRendered || hashsetRendered || interestingFileRendered;
 
  271         return contentRendered;
 
  281     private static List<ContentTag> 
getTags(Content sourceContent) {
 
  284             return tskCase.getContentTagsByContent(sourceContent);
 
  286             logger.log(Level.SEVERE, 
"Exception while getting open case.", ex); 
 
  287         } 
catch (TskCoreException ex) {
 
  288             logger.log(Level.SEVERE, 
"Exception while getting tags from the case database.", ex); 
 
  290         return new ArrayList<>();
 
  300     private static List<BlackboardArtifactTag> 
getTags(BlackboardArtifact bba) {
 
  303             return tskCase.getBlackboardArtifactTagsByArtifact(bba);
 
  305             logger.log(Level.SEVERE, 
"Exception while getting open case.", ex); 
 
  306         } 
catch (TskCoreException ex) {
 
  307             logger.log(Level.SEVERE, 
"Exception while getting tags from the case database.", ex); 
 
  309         return new ArrayList<>();
 
  321     private static List<BlackboardArtifact> 
getFileSetHits(AbstractFile sourceFile, BlackboardArtifact.ARTIFACT_TYPE type) {
 
  324             return tskCase.getBlackboardArtifacts(type, sourceFile.getId()).stream()
 
  326                     .collect(Collectors.toList());
 
  328             logger.log(Level.SEVERE, 
"Exception while getting open case.", ex); 
 
  329         } 
catch (TskCoreException ex) {
 
  330             logger.log(Level.SEVERE, 
"Exception while getting file set hits from the case database.", ex); 
 
  332         return new ArrayList<>();
 
  343         return StringUtils.isNotBlank(
tryGetAttribute(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT));
 
  355     private static String 
tryGetAttribute(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE attributeType) {
 
  356         if (artifact == null) {
 
  360         BlackboardAttribute attr = null;
 
  362             attr = artifact.getAttribute(
new BlackboardAttribute.Type(attributeType));
 
  363         } 
catch (TskCoreException ex) {
 
  364             logger.log(Level.WARNING, String.format(
"Unable to fetch attribute of type %s for artifact %s", attributeType, artifact), ex);
 
  371         return attr.getValueString();
 
  384         if (artifact == null) {
 
  385             return new ArrayList<>();
 
  387         List<CorrelationAttributeInstance> instances = 
new ArrayList<>();
 
  388         if (artifact instanceof DataArtifact) {
 
  390         } 
else if (artifact instanceof AnalysisResult) {
 
  395                 .map(cai -> Pair.of(cai.getCorrelationType(), cai.getCorrelationValue()))
 
  396                 .collect(Collectors.toList());
 
  411         if (sourceFile == null || StringUtils.isEmpty(sourceFile.getMd5Hash())) {
 
  412             return new ArrayList<>();
 
  419             logger.log(Level.SEVERE, 
"Error connecting to the Central Repository database.", ex); 
 
  422         if (artifactTypes == null || artifactTypes.isEmpty()) {
 
  423             return new ArrayList<>();
 
  426         String md5 = sourceFile.getMd5Hash();
 
  431                 .map((attributeType) -> Pair.of(attributeType, md5))
 
  432                 .collect(Collectors.toList());
 
  446         List<CorrelationAttributeInstance> instancesToRet = 
new ArrayList<>();
 
  450             for (Pair<CorrelationAttributeInstance.Type, String> typeVal : lookupKeys) {
 
  455                         .filter((cai) -> StringUtils.isNotBlank(cai.getComment()))
 
  456                         .collect(Collectors.toList()));
 
  460             logger.log(Level.SEVERE, 
"Error connecting to the Central Repository database.", ex); 
 
  462             logger.log(Level.SEVERE, 
"Error normalizing instance from Central Repository database.", ex); 
 
  465         return instancesToRet;
 
  486             boolean isSubsection, 
boolean isFirstSection) {
 
  487         if (items == null || items.isEmpty()) {
 
  492         if (!isFirstSection) {
 
  496         Element sectionContainer = sectionDiv.appendElement(
"div");
 
  517         boolean isFirst = 
true;
 
  518         for (T item : items) {
 
  523             List<List<String>> tableData = rowHeaders.stream()
 
  524                     .map(row -> Arrays.asList(row.getItemName(), row.retrieveValue(item)))
 
  525                     .collect(Collectors.toList());
 
  527             Element childTable = 
appendTable(parent, 2, tableData, null);
 
  551     private static Element 
appendTable(Element parent, 
int columnNumber, List<List<String>> content, List<String> columnHeaders) {
 
  552         Element table = parent.appendElement(
"table")
 
  553                 .attr(
"valign", 
"top")
 
  554                 .attr(
"align", 
"left");
 
  556         if (columnHeaders != null && !columnHeaders.isEmpty()) {
 
  557             Element header = table.appendElement(
"thead");
 
  558             appendRow(header, columnHeaders, columnNumber, 
true);
 
  560         Element tableBody = table.appendElement(
"tbody");
 
  562         content.forEach((rowData) -> 
appendRow(tableBody, rowData, columnNumber, 
false));
 
  577     private static Element 
appendRow(Element rowParent, List<String> data, 
int columnNumber, 
boolean isHeader) {
 
  578         String cellType = isHeader ? 
"th" : 
"td";
 
  579         Element row = rowParent.appendElement(
"tr");
 
  580         for (
int i = 0; i < columnNumber; i++) {
 
  581             Element cell = row.appendElement(cellType);
 
  587             if (data != null && i < data.size()) {
 
  588                 cell.appendElement(
"span")
 
  590                         .text(StringUtils.isEmpty(data.get(i)) ? 
"" : data.get(i));
 
  605         Element sectionDiv = parent.appendElement(
"div");
 
  606         Element header = sectionDiv.appendElement(
"h1");
 
  607         header.text(headerText);
 
  621         Element subsectionDiv = parent.appendElement(
"div");
 
  622         Element header = subsectionDiv.appendElement(
"h2");
 
  623         header.text(headerText);
 
  625         return subsectionDiv;
 
  635     static class ItemEntry<T> {
 
  637         private final String itemName;
 
  638         private final Function<T, String> valueRetriever;
 
  640         ItemEntry(String itemName, Function<T, String> valueRetriever) {
 
  641             this.itemName = itemName;
 
  642             this.valueRetriever = valueRetriever;
 
  645         String getItemName() {
 
  649         Function<T, String> getValueRetriever() {
 
  650             return valueRetriever;
 
  653         String retrieveValue(T 
object) {
 
  654             return valueRetriever.apply(
object);
 
  663     static class SectionConfig<T> {
 
  665         private final String title;
 
  666         private final List<ItemEntry<T>> attributes;
 
  668         SectionConfig(String title, List<ItemEntry<T>> attributes) {
 
  670             this.attributes = attributes;
 
  684         List<ItemEntry<T>> getAttributes() {
 
  693     static class DisplayTskItems {
 
  695         private final BlackboardArtifact artifact;
 
  696         private final Content content;
 
  705         DisplayTskItems(BlackboardArtifact artifact, Content content) {
 
  706             this.artifact = artifact;
 
  707             this.content = content;
 
  713         BlackboardArtifact getArtifact() {
 
  720         Content getContent() {
 
static String tryGetAttribute(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE attributeType)
 
static List< CorrelationAttributeInstance > getCentralRepositoryData(AbstractFile sourceFile)
 
static Element appendRow(Element rowParent, List< String > data, int columnNumber, boolean isHeader)
 
static Element appendSubsection(Element parent, String headerText)
 
static String getSpacedSectionClassName()
 
static< T > boolean appendEntries(Element parent, AnnotationUtils.SectionConfig< T > config, List<?extends T > items, boolean isSubsection, boolean isFirstSection)
 
static List< ContentTag > getTags(Content sourceContent)
 
static String getTextClassName()
 
static final List< ItemEntry< BlackboardArtifact > > FILESET_HIT_ENTRIES
 
static final SectionConfig< BlackboardArtifact > HASHSET_CONFIG
 
List< CorrelationAttributeInstance > getArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String value)
 
static final SectionConfig< BlackboardArtifact > INTERESTING_FILE_CONFIG
 
static Element appendSection(Element parent, String headerText)
 
static final String EMPTY_HTML
 
static List< BlackboardArtifact > getFileSetHits(AbstractFile sourceFile, BlackboardArtifact.ARTIFACT_TYPE type)
 
static String getKeyColumnClassName()
 
static< T > Element appendVerticalEntryTables(Element parent, List<?extends T > items, List< ItemEntry< T >> rowHeaders)
 
static final List< ItemEntry< CorrelationAttributeInstance > > CR_COMMENTS_ENTRIES
 
static String getIndentedClassName()
 
List< CorrelationAttributeInstance.Type > getDefinedCorrelationTypes()
 
static List< BlackboardArtifactTag > getTags(BlackboardArtifact bba)
 
static List< CorrelationAttributeInstance > makeCorrAttrsForSearch(AnalysisResult analysisResult)
 
static final SectionConfig< BlackboardArtifact > ARTIFACT_COMMENT_CONFIG
 
static boolean hasTskComment(BlackboardArtifact artifact)
 
static Element appendTable(Element parent, int columnNumber, List< List< String >> content, List< String > columnHeaders)
 
static final SectionConfig< CorrelationAttributeInstance > CR_COMMENTS_CONFIG
 
SleuthkitCase getSleuthkitCase()
 
static boolean renderContent(Element parent, Content sourceContent, boolean isSubheader)
 
static boolean isSupported(Node node)
 
static Document buildDocument(Node node)
 
static String getHeaderClassName()
 
static List< CorrelationAttributeInstance > getCentralRepositoryData(BlackboardArtifact artifact)
 
static List< CorrelationAttributeInstance > getCorrelationAttributeComments(List< Pair< CorrelationAttributeInstance.Type, String >> lookupKeys)
 
synchronized static Logger getLogger(String name)
 
static Case getCurrentCaseThrows()
 
static final List< ItemEntry< Tag > > TAG_ENTRIES
 
static final Logger logger
 
Content getSourceContent()
 
static boolean renderArtifact(Element parent, BlackboardArtifact bba, Content sourceContent)
 
static CentralRepository getInstance()
 
static final SectionConfig< Tag > TAG_CONFIG
 
static final int FILES_TYPE_ID
 
static boolean isEnabled()