From c49e33e5b68723c12866db256be2b7b817e40089 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 24 Jan 2018 17:20:01 -0500 Subject: [PATCH 1/8] Updated logic to properly handle artifact and content nodes. --- .../keywordsearch/ExtractedContentViewer.java | 104 +++++++++++------- .../keywordsearch/HighlightedText.java | 31 +++--- .../KeywordSearchFilterNode.java | 15 ++- .../KeywordSearchResultFactory.java | 57 +++++++++- 4 files changed, 143 insertions(+), 64 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java index dbed68e660..222ca18ebd 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,6 +33,8 @@ import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.keywordsearch.KeywordSearchResultFactory.QueryContent; +import org.sleuthkit.datamodel.AbstractContent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -50,7 +52,7 @@ import org.sleuthkit.datamodel.TskCoreException; @ServiceProvider(service = DataContentViewer.class, position = 4) public class ExtractedContentViewer implements DataContentViewer { - private static final Logger logger = Logger.getLogger(ExtractedContentViewer.class.getName()); + private static final Logger LOGGER = Logger.getLogger(ExtractedContentViewer.class.getName()); private static final long INVALID_DOCUMENT_ID = 0L; private static final BlackboardAttribute.Type TSK_ASSOCIATED_ARTIFACT_TYPE = new BlackboardAttribute.Type(TSK_ASSOCIATED_ARTIFACT); @@ -93,7 +95,7 @@ public class ExtractedContentViewer implements DataContentViewer { } Lookup nodeLookup = node.getLookup(); - AbstractFile content = nodeLookup.lookup(AbstractFile.class); + AbstractContent content = nodeLookup.lookup(AbstractFile.class); /* * Assemble a collection of all of the indexed text "sources" for the @@ -104,41 +106,56 @@ public class ExtractedContentViewer implements DataContentViewer { IndexedText rawContentText = null; if (null != content && solrHasContent(content.getId())) { - QueryResults hits = nodeLookup.lookup(QueryResults.class); - BlackboardArtifact artifact = nodeLookup.lookup(BlackboardArtifact.class); - if (hits != null) { - /* - * if there is a QueryReslt object, in the lookup use that. This - * happens when a user selects a row in an ad-hoc search result - */ - highlightedHitText = new HighlightedText(content.getId(), hits); - } else if (artifact != null - && artifact.getArtifactTypeID() == TSK_ACCOUNT.getTypeID()) { - try { - // if the artifact is an account artifact, get an account text . - highlightedHitText = getAccountsText(content, nodeLookup); - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to create AccountsText for " + content, ex); //NON-NLS - - } - } else if (artifact != null - && artifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID()) { - try { - //if there is kwh artifact use that to construct the HighlightedText - highlightedHitText = new HighlightedText(artifact); - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to create HighlightedText for " + artifact, ex); //NON-NLS - } - } - - if (highlightedHitText != null) { - sources.add(highlightedHitText); - } - /* - * Next, add the "raw" (not highlighted) text, if any, for any - * content associated with the node. + * Results for Keyword Hits. */ + BlackboardArtifact artifact = nodeLookup.lookup(BlackboardArtifact.class); + if (artifact != null) { + if (artifact.getArtifactTypeID() == TSK_ACCOUNT.getTypeID()) { + try { + // if the artifact is an account artifact, get an account text. + highlightedHitText = getAccountsText(content, nodeLookup); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to create AccountsText for " + content, ex); //NON-NLS + } + } else if (artifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID()) { + try { + //if there is kwh artifact use that to construct the HighlightedText + highlightedHitText = new HighlightedText(artifact); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to create HighlightedText for " + artifact, ex); //NON-NLS + } + } + } + } else { + /* + * Results for ad-hoc search. + */ + QueryContent queryContent = nodeLookup.lookup(QueryContent.class); + content = (AbstractFile) queryContent.getContent(); + + if (null != content && solrHasContent(content.getId())) { + QueryResults queryResults = queryContent.getResults(); + if (queryResults != null) { + /* + * If there's a QueryContent object in the lookup, use that. + * This happens when a user selects a row in an ad-hoc + * search result. + */ + highlightedHitText = new HighlightedText(queryContent.getSolrObjectId(), queryResults); + } + } + } + + if (highlightedHitText != null) { + sources.add(highlightedHitText); + } + + /* + * Next, add the "raw" (not highlighted) text, if any, for any + * content associated with the node. + */ + if (content != null) { rawContentText = new RawText(content, content.getId()); sources.add(rawContentText); } @@ -151,7 +168,7 @@ public class ExtractedContentViewer implements DataContentViewer { try { rawArtifactText = getRawArtifactText(nodeLookup); } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error creating RawText for " + content, ex); //NON-NLS + LOGGER.log(Level.SEVERE, "Error creating RawText for " + content, ex); //NON-NLS } if (rawArtifactText != null) { @@ -288,7 +305,7 @@ public class ExtractedContentViewer implements DataContentViewer { return true; } } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error getting TSK_ACCOUNT_TYPE attribute from artifact " + art.getArtifactID(), ex); + LOGGER.log(Level.SEVERE, "Error getting TSK_ACCOUNT_TYPE attribute from artifact " + art.getArtifactID(), ex); } } else if (artifactTypeID == TSK_KEYWORD_HIT.getTypeID()) { return true; @@ -352,7 +369,7 @@ public class ExtractedContentViewer implements DataContentViewer { try { return solrServer.queryIsIndexed(objectId); } catch (NoOpenCoreException | KeywordSearchModuleException ex) { - logger.log(Level.SEVERE, "Error querying Solr server", ex); //NON-NLS + LOGGER.log(Level.SEVERE, "Error querying Solr server", ex); //NON-NLS return false; } } @@ -386,7 +403,7 @@ public class ExtractedContentViewer implements DataContentViewer { return blackboardAttribute.getValueLong(); } } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error getting associated artifact attributes", ex); //NON-NLS + LOGGER.log(Level.SEVERE, "Error getting associated artifact attributes", ex); //NON-NLS } } } @@ -398,6 +415,13 @@ public class ExtractedContentViewer implements DataContentViewer { * handled above. */ Content content = node.getLookup().lookup(Content.class); + if (content == null) { + QueryContent queryContent = node.getLookup().lookup(QueryContent.class); + if (queryContent != null) { + content = queryContent.getContent(); + } + } + if (content != null) { return content.getId(); } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedText.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedText.java index 70d2e69194..9bcbdd7b2a 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedText.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedText.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.keywordsearch; import com.google.common.collect.Iterators; import com.google.common.collect.Range; -import com.google.common.collect.RangeSet; import com.google.common.collect.TreeRangeSet; import java.util.Arrays; import java.util.Collection; @@ -55,7 +54,7 @@ import org.sleuthkit.datamodel.TskCoreException; */ class HighlightedText implements IndexedText { - private static final Logger logger = Logger.getLogger(HighlightedText.class.getName()); + private static final Logger LOGGER = Logger.getLogger(HighlightedText.class.getName()); private static final boolean DEBUG = (Version.getBuildType() == Version.Type.DEVELOPMENT); @@ -70,7 +69,7 @@ class HighlightedText implements IndexedText { final private Server solrServer = KeywordSearch.getServer(); - private final long objectId; + private final long solrObjectId; /* * The keywords to highlight */ @@ -106,14 +105,14 @@ class HighlightedText implements IndexedText { * search results. In that case we have the entire QueryResults object and need to arrange the paging. * - * @param objectId The objectID of the content whose text will be + * @param solrObjectId The solrObjectId of the content whose text will be * highlighted. * @param QueryResults The QueryResults for the ad-hoc search from whose results a selection was made leading to this HighlightedText. */ - HighlightedText(long objectId, QueryResults hits) { - this.objectId = objectId; + HighlightedText(long solrObjectId, QueryResults hits) { + this.solrObjectId = solrObjectId; this.hits = hits; } @@ -129,9 +128,9 @@ class HighlightedText implements IndexedText { this.artifact = artifact; BlackboardAttribute attribute = artifact.getAttribute(TSK_ASSOCIATED_ARTIFACT); if (attribute != null) { - this.objectId = attribute.getValueLong(); + this.solrObjectId = attribute.getValueLong(); } else { - this.objectId = artifact.getObjectID(); + this.solrObjectId = artifact.getObjectID(); } } @@ -146,7 +145,7 @@ class HighlightedText implements IndexedText { return; } - this.numberPages = solrServer.queryNumFileChunks(this.objectId); + this.numberPages = solrServer.queryNumFileChunks(this.solrObjectId); if (artifact != null) { loadPageInfoFromArtifact(); @@ -194,7 +193,7 @@ class HighlightedText implements IndexedText { // Run a query to figure out which chunks for the current object have // hits for this keyword. - chunksQuery.addFilter(new KeywordQueryFilter(FilterType.CHUNK, this.objectId)); + chunksQuery.addFilter(new KeywordQueryFilter(FilterType.CHUNK, this.solrObjectId)); hits = chunksQuery.performQuery(); loadPageInfoFromHits(); @@ -216,7 +215,7 @@ class HighlightedText implements IndexedText { for (KeywordHit hit : hits.getResults(k)) { int chunkID = hit.getChunkId(); if (artifact != null) { - if (chunkID != 0 && this.objectId == hit.getSolrObjectId()) { + if (chunkID != 0 && this.solrObjectId == hit.getSolrObjectId()) { String hit1 = hit.getHit(); if (keywords.stream().anyMatch(hit1::contains)) { numberOfHitsPerPage.put(chunkID, 0); //unknown number of matches in the page @@ -225,7 +224,7 @@ class HighlightedText implements IndexedText { } } } else { - if (chunkID != 0 && this.objectId == hit.getSolrObjectId()) { + if (chunkID != 0 && this.solrObjectId == hit.getSolrObjectId()) { numberOfHitsPerPage.put(chunkID, 0); //unknown number of matches in the page currentHitPerPage.put(chunkID, 0); //set current hit to 0th @@ -354,7 +353,7 @@ class HighlightedText implements IndexedText { SolrQuery q = new SolrQuery(); q.setShowDebugInfo(DEBUG); //debug - String contentIdStr = Long.toString(this.objectId); + String contentIdStr = Long.toString(this.solrObjectId); if (numberPages != 0) { chunkID = Integer.toString(this.currentPage); contentIdStr += "0".equals(chunkID) ? "" : "_" + chunkID; @@ -401,7 +400,7 @@ class HighlightedText implements IndexedText { // either be a single chunk containing hits or we narrow our // query down to the current page/chunk. if (response.getResults().size() > 1) { - logger.log(Level.WARNING, "Unexpected number of results for Solr highlighting query: {0}", q); //NON-NLS + LOGGER.log(Level.WARNING, "Unexpected number of results for Solr highlighting query: {0}", q); //NON-NLS } String highlightedContent; Map>> responseHighlight = response.getHighlighting(); @@ -427,7 +426,7 @@ class HighlightedText implements IndexedText { return "
" + highlightedContent + "
"; //NON-NLS } catch (TskCoreException | KeywordSearchModuleException | NoOpenCoreException ex) { - logger.log(Level.SEVERE, "Error getting highlighted text for Solr doc id " + objectId + ", chunkID " + chunkID + ", highlight query: " + highlightField, ex); //NON-NLS + LOGGER.log(Level.SEVERE, "Error getting highlighted text for Solr doc id " + solrObjectId + ", chunkID " + chunkID + ", highlight query: " + highlightField, ex); //NON-NLS return NbBundle.getMessage(this.getClass(), "HighlightedMatchesSource.getMarkup.queryFailedMsg"); } } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java index 7674ee5e34..b848892691 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2017 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -39,6 +39,7 @@ import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; +import org.sleuthkit.autopsy.keywordsearch.KeywordSearchResultFactory.QueryContent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentVisitor; @@ -52,12 +53,18 @@ import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.VirtualDirectory; /** - * + * FilterNode containing data pertaining to keyword search. */ class KeywordSearchFilterNode extends FilterNode { - KeywordSearchFilterNode(QueryResults highlights, Node original) { - super(original, null, new ProxyLookup(Lookups.singleton(highlights), original.getLookup())); + /** + * Instantiate a KeywordSearchFilterNode. + * + * @param queryContent The query content. + * @param original The original source node. + */ + KeywordSearchFilterNode(QueryContent queryContent, Node original) { + super(original, null, new ProxyLookup(Lookups.singleton(queryContent), original.getLookup())); } @Override diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java index a8bc995eae..c8c1c07b15 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java @@ -250,13 +250,12 @@ class KeywordSearchResultFactory extends ChildFactory { Node resultNode; if (key instanceof KeyValueQueryContent) { - final Content content = ((KeyValueQueryContent) key).getContent(); - QueryResults hits = ((KeyValueQueryContent) key).getHits(); + QueryContent queryContent = new QueryContent((KeyValueQueryContent) key); - Node kvNode = new KeyValueNode(key, Children.LEAF, Lookups.singleton(content)); + Node kvNode = new KeyValueNode(key, Children.LEAF, Lookups.singleton(queryContent)); //wrap in KeywordSearchFilterNode for the markup content, might need to override FilterNode for more customization - resultNode = new KeywordSearchFilterNode(hits, kvNode); + resultNode = new KeywordSearchFilterNode(queryContent, kvNode); } else { resultNode = new EmptyNode("This Node Is Empty"); resultNode.setDisplayName(NbBundle.getMessage(this.getClass(), "KeywordSearchResultFactory.createNodeForKey.noResultsFound.text")); @@ -265,6 +264,56 @@ class KeywordSearchResultFactory extends ChildFactory { return resultNode; } + + /** + * This class encapsulates content, query results, and an associated Solr + * object ID for storing in the Lookup to be read later. + */ + class QueryContent { + private final long solrObjectId; + private final Content content; + private final QueryResults results; + + /** + * Instantiate a QueryContent object. + * + * @param solrObjectId The Solr object ID associated with the content. + * @param content The content for the query result. + * @param results The query results. + */ + QueryContent(KeyValueQueryContent key) { + this.solrObjectId = key.getSolrObjectId(); + this.content = key.getContent(); + this.results = key.getHits(); + } + + /** + * Get the Solr object ID associated with the content. + * + * @return The Solr object ID. + */ + long getSolrObjectId() { + return solrObjectId; + } + + /** + * Get the content for the query result. + * + * @return The content. + */ + Content getContent() { + return content; + } + + /** + * Get the query results. + * + * @return The query results. + */ + QueryResults getResults() { + return results; + } + } /** * Used to display keyword search results in table. Eventually turned into a From eeb83e270ce10a21f3d6e1a1529a1db808eab435 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 24 Jan 2018 17:31:32 -0500 Subject: [PATCH 2/8] Revised some code comments. --- .../keywordsearch/ExtractedContentViewer.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java index 222ca18ebd..bf4b2eb317 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java @@ -113,14 +113,18 @@ public class ExtractedContentViewer implements DataContentViewer { if (artifact != null) { if (artifact.getArtifactTypeID() == TSK_ACCOUNT.getTypeID()) { try { - // if the artifact is an account artifact, get an account text. + /* + * Generate AccountsText for the account artifact. + */ highlightedHitText = getAccountsText(content, nodeLookup); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to create AccountsText for " + content, ex); //NON-NLS } } else if (artifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID()) { try { - //if there is kwh artifact use that to construct the HighlightedText + /* + * Generate HighlightedText for the keyword hit artifact. + */ highlightedHitText = new HighlightedText(artifact); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to create HighlightedText for " + artifact, ex); //NON-NLS @@ -137,11 +141,6 @@ public class ExtractedContentViewer implements DataContentViewer { if (null != content && solrHasContent(content.getId())) { QueryResults queryResults = queryContent.getResults(); if (queryResults != null) { - /* - * If there's a QueryContent object in the lookup, use that. - * This happens when a user selects a row in an ad-hoc - * search result. - */ highlightedHitText = new HighlightedText(queryContent.getSolrObjectId(), queryResults); } } From a33e4c9b3bb478863ba87561346bf8f04e90aeea Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 24 Jan 2018 17:35:50 -0500 Subject: [PATCH 3/8] Corrected typo. --- .../autopsy/keywordsearch/ExtractedContentViewer.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java index bf4b2eb317..43f0d7baf8 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java @@ -34,7 +34,6 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.keywordsearch.KeywordSearchResultFactory.QueryContent; -import org.sleuthkit.datamodel.AbstractContent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -95,7 +94,7 @@ public class ExtractedContentViewer implements DataContentViewer { } Lookup nodeLookup = node.getLookup(); - AbstractContent content = nodeLookup.lookup(AbstractFile.class); + AbstractFile content = nodeLookup.lookup(AbstractFile.class); /* * Assemble a collection of all of the indexed text "sources" for the From 1621cd5d43fccad3669eaf50ed770c8cf0fb8ddf Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 9 Feb 2018 14:23:39 -0500 Subject: [PATCH 4/8] Partial changes. --- .../keywordsearch/ExtractedContentViewer.java | 194 ++++++++---------- .../keywordsearch/HighlightedText.java | 6 +- .../KeywordSearchFilterNode.java | 10 +- .../KeywordSearchResultFactory.java | 28 +-- 4 files changed, 106 insertions(+), 132 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java index 43f0d7baf8..b8fef30f01 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java @@ -27,13 +27,14 @@ import java.util.Collection; import java.util.List; import java.util.logging.Level; import org.openide.nodes.Node; +import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.keywordsearch.KeywordSearchResultFactory.QueryContent; +import org.sleuthkit.autopsy.keywordsearch.KeywordSearchResultFactory.AdHocQueryResult; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -51,7 +52,7 @@ import org.sleuthkit.datamodel.TskCoreException; @ServiceProvider(service = DataContentViewer.class, position = 4) public class ExtractedContentViewer implements DataContentViewer { - private static final Logger LOGGER = Logger.getLogger(ExtractedContentViewer.class.getName()); + private static final Logger logger = Logger.getLogger(ExtractedContentViewer.class.getName()); private static final long INVALID_DOCUMENT_ID = 0L; private static final BlackboardAttribute.Type TSK_ASSOCIATED_ARTIFACT_TYPE = new BlackboardAttribute.Type(TSK_ASSOCIATED_ARTIFACT); @@ -93,9 +94,6 @@ public class ExtractedContentViewer implements DataContentViewer { currentNode = node; } - Lookup nodeLookup = node.getLookup(); - AbstractFile content = nodeLookup.lookup(AbstractFile.class); - /* * Assemble a collection of all of the indexed text "sources" for the * node. @@ -104,44 +102,37 @@ public class ExtractedContentViewer implements DataContentViewer { IndexedText highlightedHitText = null; IndexedText rawContentText = null; - if (null != content && solrHasContent(content.getId())) { - /* - * Results for Keyword Hits. - */ - BlackboardArtifact artifact = nodeLookup.lookup(BlackboardArtifact.class); - if (artifact != null) { - if (artifact.getArtifactTypeID() == TSK_ACCOUNT.getTypeID()) { - try { - /* - * Generate AccountsText for the account artifact. - */ - highlightedHitText = getAccountsText(content, nodeLookup); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to create AccountsText for " + content, ex); //NON-NLS - } - } else if (artifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID()) { - try { - /* - * Generate HighlightedText for the keyword hit artifact. - */ - highlightedHitText = new HighlightedText(artifact); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to create HighlightedText for " + artifact, ex); //NON-NLS - } + Lookup nodeLookup = node.getLookup(); + + AdHocQueryResult adHocQueryResult = nodeLookup.lookup(AdHocQueryResult.class); + BlackboardArtifact artifact = nodeLookup.lookup(BlackboardArtifact.class); + AbstractFile content = nodeLookup.lookup(AbstractFile.class); + + if (adHocQueryResult != null) { + highlightedHitText = new HighlightedText(adHocQueryResult.getSolrObjectId(), adHocQueryResult.getResults()); + } else if (artifact != null) { + if (artifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID()) { + try { + highlightedHitText = new HighlightedText(artifact); + } catch (TskCoreException ex) { + Exceptions.printStackTrace(ex); + } + } else if (artifact.getArtifactTypeID() == TSK_ACCOUNT.getTypeID() && content != null) { + try { + highlightedHitText = getAccountsText(content, nodeLookup); + } catch (TskCoreException ex) { + Exceptions.printStackTrace(ex); } } - } else { - /* - * Results for ad-hoc search. - */ - QueryContent queryContent = nodeLookup.lookup(QueryContent.class); - content = (AbstractFile) queryContent.getContent(); - - if (null != content && solrHasContent(content.getId())) { - QueryResults queryResults = queryContent.getResults(); - if (queryResults != null) { - highlightedHitText = new HighlightedText(queryContent.getSolrObjectId(), queryResults); - } + } + + if (content != null) { + rawContentText = new RawText(content, content.getId()); + } else if (artifact != null) { + try { + rawContentText = getRawArtifactText(nodeLookup); + } catch (TskCoreException ex) { + Exceptions.printStackTrace(ex); } } @@ -150,11 +141,10 @@ public class ExtractedContentViewer implements DataContentViewer { } /* - * Next, add the "raw" (not highlighted) text, if any, for any - * content associated with the node. + * Next, add the "raw" (not highlighted) text, if any, for any content + * associated with the node. */ - if (content != null) { - rawContentText = new RawText(content, content.getId()); + if (rawContentText != null) { sources.add(rawContentText); } @@ -166,7 +156,7 @@ public class ExtractedContentViewer implements DataContentViewer { try { rawArtifactText = getRawArtifactText(nodeLookup); } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Error creating RawText for " + content, ex); //NON-NLS + logger.log(Level.SEVERE, "Error creating RawText for " + content, ex); //NON-NLS } if (rawArtifactText != null) { @@ -289,6 +279,11 @@ public class ExtractedContentViewer implements DataContentViewer { return false; } + AdHocQueryResult adHocQueryResult = node.getLookup().lookup(AdHocQueryResult.class); + if (adHocQueryResult != null) { + return true; + } + /* * Is there a credit card or keyword hit artifact in the lookup */ @@ -296,26 +291,63 @@ public class ExtractedContentViewer implements DataContentViewer { if (artifacts != null) { for (BlackboardArtifact art : artifacts) { final int artifactTypeID = art.getArtifactTypeID(); - if (artifactTypeID == TSK_ACCOUNT.getTypeID()) { + if (artifactTypeID == TSK_KEYWORD_HIT.getTypeID()) { + return true; + } else if (artifactTypeID == TSK_ACCOUNT.getTypeID()) { try { BlackboardAttribute attribute = art.getAttribute(TSK_ACCOUNT_TYPE); if (attribute != null && Account.Type.CREDIT_CARD.getTypeName().equals(attribute.getValueString())) { return true; } } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Error getting TSK_ACCOUNT_TYPE attribute from artifact " + art.getArtifactID(), ex); + logger.log(Level.SEVERE, "Error getting TSK_ACCOUNT_TYPE attribute from artifact " + art.getArtifactID(), ex); + return true; } - } else if (artifactTypeID == TSK_KEYWORD_HIT.getTypeID()) { - return true; } } } + /** + * If the node is a Blackboard artifact node for anything other than a + * keyword hit, the document ID for the text extracted from the artifact + * (the concatenation of its attributes) is the artifact ID, a large, + * negative integer. If it is a keyword hit, see if there is an + * associated artifact. If there is, get the associated artifact's ID + * and return it. + */ + long documentID = INVALID_DOCUMENT_ID; + + BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class); + if (null != artifact) { + if (artifact.getArtifactTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { + documentID = artifact.getArtifactID(); + } else { + try { + // Get the associated artifact attribute and return its value as the ID + BlackboardAttribute blackboardAttribute = artifact.getAttribute(TSK_ASSOCIATED_ARTIFACT_TYPE); + if (blackboardAttribute != null) { + documentID = blackboardAttribute.getValueLong(); + } + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Error getting associated artifact attributes", ex); //NON-NLS + } + } + } + + /* + * For keyword search hit artifact nodes and all other nodes, the + * document ID for the extracted text is the ID of the associated + * content, if any, unless there is an associated artifact, which is + * handled above. + */ + Content content = node.getLookup().lookup(Content.class); + if (content != null) { + documentID = content.getId(); + } /* * No highlighted text for a keyword hit, so is there any indexed text * at all for this node? */ - long documentID = getDocumentId(node); if (INVALID_DOCUMENT_ID == documentID) { return false; } @@ -367,69 +399,11 @@ public class ExtractedContentViewer implements DataContentViewer { try { return solrServer.queryIsIndexed(objectId); } catch (NoOpenCoreException | KeywordSearchModuleException ex) { - LOGGER.log(Level.SEVERE, "Error querying Solr server", ex); //NON-NLS + logger.log(Level.SEVERE, "Error querying Solr server", ex); //NON-NLS return false; } } - /** - * Gets the object ID to use as the document ID for accessing any indexed - * text for the given node. - * - * @param node The node. - * - * @return The document ID or zero, which is an invalid document ID. - */ - private Long getDocumentId(Node node) { - /** - * If the node is a Blackboard artifact node for anything other than a - * keyword hit, the document ID for the text extracted from the artifact - * (the concatenation of its attributes) is the artifact ID, a large, - * negative integer. If it is a keyword hit, see if there is an - * associated artifact. If there is, get the associated artifact's ID - * and return it. - */ - BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class); - if (null != artifact) { - if (artifact.getArtifactTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { - return artifact.getArtifactID(); - } else { - try { - // Get the associated artifact attribute and return its value as the ID - BlackboardAttribute blackboardAttribute = artifact.getAttribute(TSK_ASSOCIATED_ARTIFACT_TYPE); - if (blackboardAttribute != null) { - return blackboardAttribute.getValueLong(); - } - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Error getting associated artifact attributes", ex); //NON-NLS - } - } - } - - /* - * For keyword search hit artifact nodes and all other nodes, the - * document ID for the extracted text is the ID of the associated - * content, if any, unless there is an associated artifact, which is - * handled above. - */ - Content content = node.getLookup().lookup(Content.class); - if (content == null) { - QueryContent queryContent = node.getLookup().lookup(QueryContent.class); - if (queryContent != null) { - content = queryContent.getContent(); - } - } - - if (content != null) { - return content.getId(); - } - - /* - * No extracted text, return an invalid docuemnt ID. - */ - return 0L; - } - private class NextFindActionListener implements ActionListener { @Override diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedText.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedText.java index 9bcbdd7b2a..2fa4bbf999 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedText.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedText.java @@ -54,7 +54,7 @@ import org.sleuthkit.datamodel.TskCoreException; */ class HighlightedText implements IndexedText { - private static final Logger LOGGER = Logger.getLogger(HighlightedText.class.getName()); + private static final Logger logger = Logger.getLogger(HighlightedText.class.getName()); private static final boolean DEBUG = (Version.getBuildType() == Version.Type.DEVELOPMENT); @@ -400,7 +400,7 @@ class HighlightedText implements IndexedText { // either be a single chunk containing hits or we narrow our // query down to the current page/chunk. if (response.getResults().size() > 1) { - LOGGER.log(Level.WARNING, "Unexpected number of results for Solr highlighting query: {0}", q); //NON-NLS + logger.log(Level.WARNING, "Unexpected number of results for Solr highlighting query: {0}", q); //NON-NLS } String highlightedContent; Map>> responseHighlight = response.getHighlighting(); @@ -426,7 +426,7 @@ class HighlightedText implements IndexedText { return "
" + highlightedContent + "
"; //NON-NLS } catch (TskCoreException | KeywordSearchModuleException | NoOpenCoreException ex) { - LOGGER.log(Level.SEVERE, "Error getting highlighted text for Solr doc id " + solrObjectId + ", chunkID " + chunkID + ", highlight query: " + highlightField, ex); //NON-NLS + logger.log(Level.SEVERE, "Error getting highlighted text for Solr doc id " + solrObjectId + ", chunkID " + chunkID + ", highlight query: " + highlightField, ex); //NON-NLS return NbBundle.getMessage(this.getClass(), "HighlightedMatchesSource.getMarkup.queryFailedMsg"); } } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java index b848892691..58876870e5 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java @@ -39,7 +39,7 @@ import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.keywordsearch.KeywordSearchResultFactory.QueryContent; +import org.sleuthkit.autopsy.keywordsearch.KeywordSearchResultFactory.AdHocQueryResult; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentVisitor; @@ -60,11 +60,11 @@ class KeywordSearchFilterNode extends FilterNode { /** * Instantiate a KeywordSearchFilterNode. * - * @param queryContent The query content. - * @param original The original source node. + * @param adHocQueryResult The query content. + * @param original The original source node. */ - KeywordSearchFilterNode(QueryContent queryContent, Node original) { - super(original, null, new ProxyLookup(Lookups.singleton(queryContent), original.getLookup())); + KeywordSearchFilterNode(AdHocQueryResult adHocQueryResult, Node original) { + super(original, null, new ProxyLookup(Lookups.singleton(adHocQueryResult), original.getLookup())); } @Override diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java index c8c1c07b15..fb37a84e59 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java @@ -66,7 +66,7 @@ import org.sleuthkit.datamodel.TskCoreException; */ class KeywordSearchResultFactory extends ChildFactory { - private static final Logger LOGGER = Logger.getLogger(KeywordSearchResultFactory.class.getName()); + private static final Logger logger = Logger.getLogger(KeywordSearchResultFactory.class.getName()); //common properties (superset of all Node properties) to be displayed as columns static final List COMMON_PROPERTIES @@ -140,7 +140,7 @@ class KeywordSearchResultFactory extends ChildFactory { try { queryResults = queryRequest.performQuery(); } catch (KeywordSearchModuleException | NoOpenCoreException ex) { - LOGGER.log(Level.SEVERE, "Could not perform the query " + queryRequest.getQueryString(), ex); //NON-NLS + logger.log(Level.SEVERE, "Could not perform the query " + queryRequest.getQueryString(), ex); //NON-NLS MessageNotifyUtil.Notify.error(Bundle.KeywordSearchResultFactory_query_exception_msg() + queryRequest.getQueryString(), ex.getCause().getMessage()); return false; } @@ -148,7 +148,7 @@ class KeywordSearchResultFactory extends ChildFactory { try { tskCase = Case.getCurrentCase().getSleuthkitCase(); } catch (IllegalStateException ex) { - LOGGER.log(Level.SEVERE, "There was no case open.", ex); //NON-NLS + logger.log(Level.SEVERE, "There was no case open.", ex); //NON-NLS return false; } @@ -165,11 +165,11 @@ class KeywordSearchResultFactory extends ChildFactory { try { content = tskCase.getContentById(hit.getContentID()); if (content == null) { - LOGGER.log(Level.SEVERE, "There was a error getting content by id."); //NON-NLS + logger.log(Level.SEVERE, "There was a error getting content by id."); //NON-NLS return false; } } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "There was a error getting content by id.", ex); //NON-NLS + logger.log(Level.SEVERE, "There was a error getting content by id.", ex); //NON-NLS return false; } @@ -192,7 +192,7 @@ class KeywordSearchResultFactory extends ChildFactory { try { hitName = tskCase.getBlackboardArtifact(hit.getArtifactID().get()).getDisplayName() + " Artifact"; //NON-NLS } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Error getting blckboard artifact by id", ex); + logger.log(Level.SEVERE, "Error getting blckboard artifact by id", ex); return false; } } else { @@ -250,12 +250,12 @@ class KeywordSearchResultFactory extends ChildFactory { Node resultNode; if (key instanceof KeyValueQueryContent) { - QueryContent queryContent = new QueryContent((KeyValueQueryContent) key); + AdHocQueryResult adHocQueryResult = new AdHocQueryResult((KeyValueQueryContent) key); - Node kvNode = new KeyValueNode(key, Children.LEAF, Lookups.singleton(queryContent)); + Node kvNode = new KeyValueNode(key, Children.LEAF); //wrap in KeywordSearchFilterNode for the markup content, might need to override FilterNode for more customization - resultNode = new KeywordSearchFilterNode(queryContent, kvNode); + resultNode = new KeywordSearchFilterNode(adHocQueryResult, kvNode); } else { resultNode = new EmptyNode("This Node Is Empty"); resultNode.setDisplayName(NbBundle.getMessage(this.getClass(), "KeywordSearchResultFactory.createNodeForKey.noResultsFound.text")); @@ -269,19 +269,19 @@ class KeywordSearchResultFactory extends ChildFactory { * This class encapsulates content, query results, and an associated Solr * object ID for storing in the Lookup to be read later. */ - class QueryContent { + final class AdHocQueryResult { private final long solrObjectId; private final Content content; private final QueryResults results; /** - * Instantiate a QueryContent object. + * Instantiate a AdHocQueryResult object. * * @param solrObjectId The Solr object ID associated with the content. * @param content The content for the query result. * @param results The query results. */ - QueryContent(KeyValueQueryContent key) { + AdHocQueryResult(KeyValueQueryContent key) { this.solrObjectId = key.getSolrObjectId(); this.content = key.getContent(); this.results = key.getHits(); @@ -407,9 +407,9 @@ class KeywordSearchResultFactory extends ChildFactory { try { get(); } catch (InterruptedException | CancellationException ex) { - LOGGER.log(Level.WARNING, "User cancelled writing of ad hoc search query results for '{0}' to the blackboard", query.getQueryString()); //NON-NLS + logger.log(Level.WARNING, "User cancelled writing of ad hoc search query results for '{0}' to the blackboard", query.getQueryString()); //NON-NLS } catch (ExecutionException ex) { - LOGGER.log(Level.SEVERE, "Error writing of ad hoc search query results for " + query.getQueryString() + " to the blackboard", ex); //NON-NLS + logger.log(Level.SEVERE, "Error writing of ad hoc search query results for " + query.getQueryString() + " to the blackboard", ex); //NON-NLS } } From ebc8d5b73c29af3504cb4355b4c448ac0bac76bc Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 9 Feb 2018 15:15:20 -0500 Subject: [PATCH 5/8] Minor changes to 'setNode()'. --- .../keywordsearch/ExtractedContentViewer.java | 31 ++++++++----------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java index b8fef30f01..4647892cdc 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java @@ -27,7 +27,6 @@ import java.util.Collection; import java.util.List; import java.util.logging.Level; import org.openide.nodes.Node; -import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; @@ -108,6 +107,10 @@ public class ExtractedContentViewer implements DataContentViewer { BlackboardArtifact artifact = nodeLookup.lookup(BlackboardArtifact.class); AbstractFile content = nodeLookup.lookup(AbstractFile.class); + /* + * Add the highlighted text, if any, for any artifact associated with the + * node. + */ if (adHocQueryResult != null) { highlightedHitText = new HighlightedText(adHocQueryResult.getSolrObjectId(), adHocQueryResult.getResults()); } else if (artifact != null) { @@ -115,27 +118,16 @@ public class ExtractedContentViewer implements DataContentViewer { try { highlightedHitText = new HighlightedText(artifact); } catch (TskCoreException ex) { - Exceptions.printStackTrace(ex); + logger.log(Level.SEVERE, "Failed to create HighlightedText for " + artifact, ex); //NON-NLS } } else if (artifact.getArtifactTypeID() == TSK_ACCOUNT.getTypeID() && content != null) { try { highlightedHitText = getAccountsText(content, nodeLookup); } catch (TskCoreException ex) { - Exceptions.printStackTrace(ex); + logger.log(Level.SEVERE, "Failed to create AccountsText for " + content, ex); //NON-NLS } } } - - if (content != null) { - rawContentText = new RawText(content, content.getId()); - } else if (artifact != null) { - try { - rawContentText = getRawArtifactText(nodeLookup); - } catch (TskCoreException ex) { - Exceptions.printStackTrace(ex); - } - } - if (highlightedHitText != null) { sources.add(highlightedHitText); } @@ -144,7 +136,9 @@ public class ExtractedContentViewer implements DataContentViewer { * Next, add the "raw" (not highlighted) text, if any, for any content * associated with the node. */ - if (rawContentText != null) { + + if (content != null) { + rawContentText = new RawText(content, content.getId()); sources.add(rawContentText); } @@ -155,13 +149,14 @@ public class ExtractedContentViewer implements DataContentViewer { IndexedText rawArtifactText = null; try { rawArtifactText = getRawArtifactText(nodeLookup); + + if (rawArtifactText != null) { + sources.add(rawArtifactText); + } } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error creating RawText for " + content, ex); //NON-NLS } - if (rawArtifactText != null) { - sources.add(rawArtifactText); - } // Now set the default source to be displayed. if (null != highlightedHitText) { From b28694743d56fa8089fba96f81a76ecd3804babb Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 9 Feb 2018 23:23:52 -0500 Subject: [PATCH 6/8] Fixes. --- .../keywordsearch/ExtractedContentViewer.java | 148 +++++++++--------- 1 file changed, 72 insertions(+), 76 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java index 4647892cdc..d66617edd2 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java @@ -53,7 +53,6 @@ public class ExtractedContentViewer implements DataContentViewer { private static final Logger logger = Logger.getLogger(ExtractedContentViewer.class.getName()); - private static final long INVALID_DOCUMENT_ID = 0L; private static final BlackboardAttribute.Type TSK_ASSOCIATED_ARTIFACT_TYPE = new BlackboardAttribute.Type(TSK_ASSOCIATED_ARTIFACT); public static final BlackboardAttribute.Type TSK_ACCOUNT_TYPE = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE); @@ -98,33 +97,42 @@ public class ExtractedContentViewer implements DataContentViewer { * node. */ List sources = new ArrayList<>(); - IndexedText highlightedHitText = null; - IndexedText rawContentText = null; - Lookup nodeLookup = node.getLookup(); - AdHocQueryResult adHocQueryResult = nodeLookup.lookup(AdHocQueryResult.class); BlackboardArtifact artifact = nodeLookup.lookup(BlackboardArtifact.class); - AbstractFile content = nodeLookup.lookup(AbstractFile.class); + AbstractFile file = nodeLookup.lookup(AbstractFile.class); /* - * Add the highlighted text, if any, for any artifact associated with the - * node. + * First, get text with highlighted hits if this node is for a search + * result. */ + IndexedText highlightedHitText = null; if (adHocQueryResult != null) { + /* + * The node is an ad hoc search result node. + */ highlightedHitText = new HighlightedText(adHocQueryResult.getSolrObjectId(), adHocQueryResult.getResults()); } else if (artifact != null) { if (artifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID()) { + /* + * The node is a keyword hit artifact node. + */ try { highlightedHitText = new HighlightedText(artifact); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Failed to create HighlightedText for " + artifact, ex); //NON-NLS } - } else if (artifact.getArtifactTypeID() == TSK_ACCOUNT.getTypeID() && content != null) { + } else if (artifact.getArtifactTypeID() == TSK_ACCOUNT.getTypeID() && file != null) { try { - highlightedHitText = getAccountsText(content, nodeLookup); + BlackboardAttribute attribute = artifact.getAttribute(TSK_ACCOUNT_TYPE); + if (attribute != null && Account.Type.CREDIT_CARD.getTypeName().equals(attribute.getValueString())) { + /* + * The node is an credit card account node. + */ + highlightedHitText = getAccountsText(file, nodeLookup); + } } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to create AccountsText for " + content, ex); //NON-NLS + logger.log(Level.SEVERE, "Failed to create AccountsText for " + file, ex); //NON-NLS } } } @@ -133,12 +141,12 @@ public class ExtractedContentViewer implements DataContentViewer { } /* - * Next, add the "raw" (not highlighted) text, if any, for any content + * Next, add the "raw" (not highlighted) text, if any, for any file * associated with the node. */ - - if (content != null) { - rawContentText = new RawText(content, content.getId()); + IndexedText rawContentText = null; + if (file != null) { + rawContentText = new RawText(file, file.getId()); sources.add(rawContentText); } @@ -149,22 +157,20 @@ public class ExtractedContentViewer implements DataContentViewer { IndexedText rawArtifactText = null; try { rawArtifactText = getRawArtifactText(nodeLookup); - if (rawArtifactText != null) { sources.add(rawArtifactText); } } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error creating RawText for " + content, ex); //NON-NLS - + logger.log(Level.SEVERE, "Error creating RawText for " + file, ex); //NON-NLS } // Now set the default source to be displayed. - if (null != highlightedHitText) { + if (highlightedHitText != null) { currentSource = highlightedHitText; - } else if (null != rawContentText) { - currentSource = rawContentText; - } else { + } else if (rawArtifactText != null) { currentSource = rawArtifactText; + } else { + currentSource = rawContentText; } // Push the text sources into the panel. @@ -177,8 +183,8 @@ public class ExtractedContentViewer implements DataContentViewer { panel.updateControls(currentSource); String contentName = ""; - if (content != null) { - contentName = content.getName(); + if (file != null) { + contentName = file.getName(); } setPanel(contentName, sources); @@ -274,80 +280,70 @@ public class ExtractedContentViewer implements DataContentViewer { return false; } + /* + * If the lookup of the node contains an ad hoc search result object, + * then there must be indexed text that produced the hit. + */ AdHocQueryResult adHocQueryResult = node.getLookup().lookup(AdHocQueryResult.class); if (adHocQueryResult != null) { return true; } /* - * Is there a credit card or keyword hit artifact in the lookup + * If the lookup of the node contains either a keyword hit artifact or + * one to many credit card account artifacts from a credit card account + * numbers search, then there must be indexed text that produced the + * hit(s). */ - Collection artifacts = node.getLookup().lookupAll(BlackboardArtifact.class); - if (artifacts != null) { - for (BlackboardArtifact art : artifacts) { - final int artifactTypeID = art.getArtifactTypeID(); - if (artifactTypeID == TSK_KEYWORD_HIT.getTypeID()) { - return true; - } else if (artifactTypeID == TSK_ACCOUNT.getTypeID()) { - try { - BlackboardAttribute attribute = art.getAttribute(TSK_ACCOUNT_TYPE); - if (attribute != null && Account.Type.CREDIT_CARD.getTypeName().equals(attribute.getValueString())) { - return true; - } - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error getting TSK_ACCOUNT_TYPE attribute from artifact " + art.getArtifactID(), ex); + BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class); + if (artifact != null) { + final int artifactTypeID = artifact.getArtifactTypeID(); + if (artifactTypeID == TSK_KEYWORD_HIT.getTypeID()) { + return true; + } else if (artifactTypeID == TSK_ACCOUNT.getTypeID()) { + try { + BlackboardAttribute attribute = artifact.getAttribute(TSK_ACCOUNT_TYPE); + if (attribute != null && Account.Type.CREDIT_CARD.getTypeName().equals(attribute.getValueString())) { return true; } - } - } - } - /** - * If the node is a Blackboard artifact node for anything other than a - * keyword hit, the document ID for the text extracted from the artifact - * (the concatenation of its attributes) is the artifact ID, a large, - * negative integer. If it is a keyword hit, see if there is an - * associated artifact. If there is, get the associated artifact's ID - * and return it. - */ - long documentID = INVALID_DOCUMENT_ID; - - BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class); - if (null != artifact) { - if (artifact.getArtifactTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { - documentID = artifact.getArtifactID(); - } else { - try { - // Get the associated artifact attribute and return its value as the ID - BlackboardAttribute blackboardAttribute = artifact.getAttribute(TSK_ASSOCIATED_ARTIFACT_TYPE); - if (blackboardAttribute != null) { - documentID = blackboardAttribute.getValueLong(); - } } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error getting associated artifact attributes", ex); //NON-NLS + /* + * If there is an error, log it and return true. The reason + * for returning true is so that the user will have an + * opportunity to see an error message in the panel when + * this query fails again when setNode is called, instead of + * having an unexpectedly disabled content viewer with no + * other feedback. + */ + logger.log(Level.SEVERE, "Error getting TSK_ACCOUNT_TYPE attribute from artifact " + artifact.getArtifactID(), ex); + return true; } } } /* - * For keyword search hit artifact nodes and all other nodes, the - * document ID for the extracted text is the ID of the associated - * content, if any, unless there is an associated artifact, which is - * handled above. + * If the lookup of the node contains an artifact that is neither a + * keyword hit artifact nor a credit card account artifact, check to see + * if there is indexed text for the artifact. */ - Content content = node.getLookup().lookup(Content.class); - if (content != null) { - documentID = content.getId(); + if (artifact != null) { + return solrHasContent(artifact.getArtifactID()); } /* - * No highlighted text for a keyword hit, so is there any indexed text - * at all for this node? + * If the lookup of the node contains no artifacts but does contain a + * file, check to see if there is indexed text for the file. */ - if (INVALID_DOCUMENT_ID == documentID) { - return false; + AbstractFile file = node.getLookup().lookup(AbstractFile.class); + if (file != null) { + return solrHasContent(file.getId()); } - return solrHasContent(documentID); + /* + * If the lookup of the node contains neither ad hoc search results, nor + * artifacts, nor a file, there is no indexed text. + */ + return false; } @Override From eb3987f8006f9d012d18f96e22397e98109de141 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Mon, 12 Feb 2018 13:19:18 -0500 Subject: [PATCH 7/8] Fixed bugs; cleanup. --- .../keywordsearch/ExtractedContentViewer.java | 22 +++-- .../KeywordSearchFilterNode.java | 2 +- .../KeywordSearchResultFactory.java | 86 ++++++++++++------- 3 files changed, 73 insertions(+), 37 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java index d66617edd2..97066a61c8 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java @@ -98,9 +98,22 @@ public class ExtractedContentViewer implements DataContentViewer { */ List sources = new ArrayList<>(); Lookup nodeLookup = node.getLookup(); + AdHocQueryResult adHocQueryResult = nodeLookup.lookup(AdHocQueryResult.class); - BlackboardArtifact artifact = nodeLookup.lookup(BlackboardArtifact.class); - AbstractFile file = nodeLookup.lookup(AbstractFile.class); + AbstractFile file; + BlackboardArtifact artifact; + + /* + * If we have an ad hoc query result, pull the file and artifact objects + * from that. Otherwise, pull them from the lookup. + */ + if (adHocQueryResult != null) { + artifact = adHocQueryResult.getArtifact(); + file = adHocQueryResult.getFile(); + } else { + artifact = nodeLookup.lookup(BlackboardArtifact.class); + file = nodeLookup.lookup(AbstractFile.class); + } /* * First, get text with highlighted hits if this node is for a search @@ -156,7 +169,7 @@ public class ExtractedContentViewer implements DataContentViewer { */ IndexedText rawArtifactText = null; try { - rawArtifactText = getRawArtifactText(nodeLookup); + rawArtifactText = getRawArtifactText(artifact); if (rawArtifactText != null) { sources.add(rawArtifactText); } @@ -190,9 +203,8 @@ public class ExtractedContentViewer implements DataContentViewer { } - static private IndexedText getRawArtifactText(Lookup nodeLookup) throws TskCoreException { + static private IndexedText getRawArtifactText(BlackboardArtifact artifact) throws TskCoreException { IndexedText rawArtifactText = null; - BlackboardArtifact artifact = nodeLookup.lookup(BlackboardArtifact.class); if (null != artifact) { /* * For keyword hit artifacts, add the text of the artifact that hit, diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java index 58876870e5..98c7ca0969 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java @@ -53,7 +53,7 @@ import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.VirtualDirectory; /** - * FilterNode containing data pertaining to keyword search. + * FilterNode containing properties and actions for keyword search. */ class KeywordSearchFilterNode extends FilterNode { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java index fb37a84e59..6725c647cc 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java @@ -37,7 +37,6 @@ import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.util.NbBundle; -import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; @@ -49,6 +48,7 @@ import org.sleuthkit.autopsy.datamodel.KeyValue; import org.sleuthkit.autopsy.datamodel.KeyValueNode; import org.sleuthkit.autopsy.keywordsearch.KeywordSearchResultFactory.KeyValueQueryContent; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW; @@ -75,10 +75,10 @@ class KeywordSearchResultFactory extends ChildFactory { TSK_KEYWORD, TSK_KEYWORD_REGEXP, TSK_KEYWORD_PREVIEW) - .map(BlackboardAttribute.ATTRIBUTE_TYPE::getDisplayName), + .map(BlackboardAttribute.ATTRIBUTE_TYPE::getDisplayName), Arrays.stream(AbstractAbstractFileNode.AbstractFilePropertyType.values()) - .map(Object::toString)) - .collect(Collectors.toList()); + .map(Object::toString)) + .collect(Collectors.toList()); private final Collection queryRequests; @@ -188,9 +188,11 @@ class KeywordSearchResultFactory extends ChildFactory { } String hitName; + BlackboardArtifact artifact = null; if (hit.isArtifactHit()) { try { - hitName = tskCase.getBlackboardArtifact(hit.getArtifactID().get()).getDisplayName() + " Artifact"; //NON-NLS + artifact = tskCase.getBlackboardArtifact(hit.getArtifactID().get()); + hitName = artifact.getDisplayName() + " Artifact"; //NON-NLS } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error getting blckboard artifact by id", ex); return false; @@ -199,7 +201,7 @@ class KeywordSearchResultFactory extends ChildFactory { hitName = contentName; } hitNumber++; - tempList.add(new KeyValueQueryContent(hitName, properties, hitNumber, hit.getSolrObjectId(), content, queryRequest, queryResults)); + tempList.add(new KeyValueQueryContent(hitName, properties, hitNumber, hit.getSolrObjectId(), (AbstractFile) content, artifact, queryRequest, queryResults)); } @@ -264,50 +266,65 @@ class KeywordSearchResultFactory extends ChildFactory { return resultNode; } - + /** * This class encapsulates content, query results, and an associated Solr * object ID for storing in the Lookup to be read later. */ final class AdHocQueryResult { + private final long solrObjectId; - private final Content content; + private final AbstractFile file; + private final BlackboardArtifact artifact; private final QueryResults results; - + /** * Instantiate a AdHocQueryResult object. - * - * @param solrObjectId The Solr object ID associated with the content. - * @param content The content for the query result. - * @param results The query results. + * + * @param solrObjectId The Solr object ID associated with the object in + * which the hit was found. + * @param file The file for the query result. + * @param artifact The artifact associated with the query result. + * @param results The query results. */ AdHocQueryResult(KeyValueQueryContent key) { this.solrObjectId = key.getSolrObjectId(); - this.content = key.getContent(); + this.file = key.getFile(); + this.artifact = key.getArtifact(); this.results = key.getHits(); } - + /** - * Get the Solr object ID associated with the content. - * + * Get the Solr object ID associated with the object in which the hit + * was found. This could be a file or an artifact. + * * @return The Solr object ID. */ long getSolrObjectId() { return solrObjectId; } - + /** - * Get the content for the query result. - * + * Get the file for the query result. + * * @return The content. */ - Content getContent() { - return content; + AbstractFile getFile() { + return file; } - + + /** + * Get the artifact for the query result. + * + * @return The artifact. + */ + BlackboardArtifact getArtifact() { + return artifact; + } + /** * Get the query results. - * + * * @return The query results. */ QueryResults getResults() { @@ -323,7 +340,8 @@ class KeywordSearchResultFactory extends ChildFactory { private final long solrObjectId; - private final Content content; + private final AbstractFile file; + private final BlackboardArtifact artifact; private final QueryResults hits; private final KeywordSearchQuery query; @@ -335,22 +353,28 @@ class KeywordSearchResultFactory extends ChildFactory { * @param map Contains content metadata, snippets, etc. * (property map) * @param id User incremented ID - * @param solrObjectId - * @param content File that had the hit. + * @param solrObjectId The ID of the object. + * @param file File that had the hit. + * @param artifact The blackboard artifact. * @param query Query used in search * @param hits Full set of search results (for all files! @@@) */ - KeyValueQueryContent(String name, Map map, int id, long solrObjectId, Content content, KeywordSearchQuery query, QueryResults hits) { + KeyValueQueryContent(String name, Map map, int id, long solrObjectId, AbstractFile file, BlackboardArtifact artifact, KeywordSearchQuery query, QueryResults hits) { super(name, map, id); this.solrObjectId = solrObjectId; - this.content = content; + this.file = file; + this.artifact = artifact; this.hits = hits; this.query = query; } - Content getContent() { - return content; + AbstractFile getFile() { + return file; + } + + BlackboardArtifact getArtifact() { + return artifact; } long getSolrObjectId() { From d8be685908b28e29143e389efa3762a2c01eb3f1 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Mon, 12 Feb 2018 15:31:38 -0500 Subject: [PATCH 8/8] Changed AbstractFile to Content to account for data sources. --- .../keywordsearch/ExtractedContentViewer.java | 7 ++-- .../KeywordSearchResultFactory.java | 32 +++++++++++-------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java index 97066a61c8..0f05f3df99 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java @@ -100,7 +100,7 @@ public class ExtractedContentViewer implements DataContentViewer { Lookup nodeLookup = node.getLookup(); AdHocQueryResult adHocQueryResult = nodeLookup.lookup(AdHocQueryResult.class); - AbstractFile file; + AbstractFile file = null; BlackboardArtifact artifact; /* @@ -109,7 +109,10 @@ public class ExtractedContentViewer implements DataContentViewer { */ if (adHocQueryResult != null) { artifact = adHocQueryResult.getArtifact(); - file = adHocQueryResult.getFile(); + Content content = adHocQueryResult.getContent(); + if (content instanceof AbstractFile) { + file = (AbstractFile) content; + } } else { artifact = nodeLookup.lookup(BlackboardArtifact.class); file = nodeLookup.lookup(AbstractFile.class); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java index 6725c647cc..fbeb4268b7 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java @@ -201,7 +201,7 @@ class KeywordSearchResultFactory extends ChildFactory { hitName = contentName; } hitNumber++; - tempList.add(new KeyValueQueryContent(hitName, properties, hitNumber, hit.getSolrObjectId(), (AbstractFile) content, artifact, queryRequest, queryResults)); + tempList.add(new KeyValueQueryContent(hitName, properties, hitNumber, hit.getSolrObjectId(), content, artifact, queryRequest, queryResults)); } @@ -274,7 +274,7 @@ class KeywordSearchResultFactory extends ChildFactory { final class AdHocQueryResult { private final long solrObjectId; - private final AbstractFile file; + private final Content content; private final BlackboardArtifact artifact; private final QueryResults results; @@ -283,13 +283,13 @@ class KeywordSearchResultFactory extends ChildFactory { * * @param solrObjectId The Solr object ID associated with the object in * which the hit was found. - * @param file The file for the query result. + * @param content The content for the query result. * @param artifact The artifact associated with the query result. * @param results The query results. */ AdHocQueryResult(KeyValueQueryContent key) { this.solrObjectId = key.getSolrObjectId(); - this.file = key.getFile(); + this.content = key.getContent(); this.artifact = key.getArtifact(); this.results = key.getHits(); } @@ -305,12 +305,16 @@ class KeywordSearchResultFactory extends ChildFactory { } /** - * Get the file for the query result. + * Get the content for the query result. This can be either a file or a + * data source, and it may or may not be the content in which the hit + * occurred. If the hit is in a file, the Content object represents that + * file. But if the hit is in an artifact, the Content object represents + * the source file or data source of the artifact. * - * @return The content. + * @return The content object. */ - AbstractFile getFile() { - return file; + Content getContent() { + return content; } /** @@ -340,7 +344,7 @@ class KeywordSearchResultFactory extends ChildFactory { private final long solrObjectId; - private final AbstractFile file; + private final Content content; private final BlackboardArtifact artifact; private final QueryResults hits; private final KeywordSearchQuery query; @@ -354,23 +358,23 @@ class KeywordSearchResultFactory extends ChildFactory { * (property map) * @param id User incremented ID * @param solrObjectId The ID of the object. - * @param file File that had the hit. + * @param content The content object. * @param artifact The blackboard artifact. * @param query Query used in search * @param hits Full set of search results (for all files! @@@) */ - KeyValueQueryContent(String name, Map map, int id, long solrObjectId, AbstractFile file, BlackboardArtifact artifact, KeywordSearchQuery query, QueryResults hits) { + KeyValueQueryContent(String name, Map map, int id, long solrObjectId, Content content, BlackboardArtifact artifact, KeywordSearchQuery query, QueryResults hits) { super(name, map, id); this.solrObjectId = solrObjectId; - this.file = file; + this.content = content; this.artifact = artifact; this.hits = hits; this.query = query; } - AbstractFile getFile() { - return file; + Content getContent() { + return content; } BlackboardArtifact getArtifact() {