diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index f5e68aa082..310a109c7b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -503,6 +503,12 @@ public class KeywordHits implements AutopsyVisitableItem { return n; } + // It is possible to get a keyword hit on artifacts generated + // for the underlying image in which case MAC times are not + // available/applicable/useful. + if (file == null) + return n; + n.addNodeProperty(new NodeProperty<>( NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.modTime.name"), NbBundle.getMessage(this.getClass(), diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java index df85183246..618f722842 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.keywordsearch; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; @@ -36,7 +37,7 @@ class KeywordHit { private final long solrObjectId; private final int chunkId; private final String snippet; - private final AbstractFile file; + private final Content content; private final BlackboardArtifact artifact; KeywordHit(String solrDocumentId, String snippet) throws TskCoreException { @@ -47,10 +48,10 @@ class KeywordHit { /** * Parse the Solr document id to get the Solr object id and chunk id. - * For a file hit, the Solr object id is the file's obj_id from the case - * database. For an artifact hit, the Solr object id is the artifact_id - * from the case database summed with a magic number to set the highest - * order bit. For every object (file or artifact) there will at least + * The Solr object id will either be a file id or an artifact id from + * the case database. + * + * For every object (file or artifact) there will at least * two Solr documents. One contains object metadata (chunk #1) and the * second and subsequent documents contain chunks of the text. */ @@ -77,7 +78,7 @@ class KeywordHit { this.artifact = null; fileId = this.solrObjectId; } - this.file = caseDb.getAbstractFileById(fileId); + this.content = caseDb.getContentById(fileId); /** * Store the text snippet. @@ -109,8 +110,8 @@ class KeywordHit { return this.snippet; } - AbstractFile getFile() { - return this.file; + Content getContent() { + return this.content; } boolean isArtifactHit() { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java index 3496859a40..841accb4af 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java @@ -171,9 +171,14 @@ class KeywordSearchResultFactory extends ChildFactory { * Get file properties. */ Map properties = new LinkedHashMap<>(); - AbstractFile file = hit.getFile(); - AbstractFsContentNode.fillPropertyMap(properties, file); - + Content file = hit.getContent(); + if (file instanceof AbstractFile) { + AbstractFsContentNode.fillPropertyMap(properties, (AbstractFile)file); + } + else { + properties.put(AbstractAbstractFileNode.AbstractFilePropertyType.LOCATION.toString(), file.getName()); + } + /** * Add a snippet property, if available. */ @@ -231,7 +236,7 @@ class KeywordSearchResultFactory extends ChildFactory { * @param file * @return */ - private String getHighlightQuery(KeywordSearchQuery query, boolean literal_query, QueryResults queryResults, AbstractFile file) { + private String getHighlightQuery(KeywordSearchQuery query, boolean literal_query, QueryResults queryResults, Content content) { String highlightQueryEscaped; if (literal_query) { //literal, treat as non-regex, non-term component query @@ -250,7 +255,7 @@ class KeywordSearchResultFactory extends ChildFactory { List hitTerms = new ArrayList<>(); for (Keyword keyword : queryResults.getKeywords()) { for (KeywordHit hit : queryResults.getResults(keyword)) { - if (hit.getFile().equals(file)) { + if (hit.getContent().equals(content)) { hitTerms.add(keyword.toString()); break; //go to next term } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java index f66230834a..0034138904 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java @@ -148,7 +148,7 @@ class LuceneQuery implements KeywordSearchQuery { BlackboardArtifact bba; KeywordCachedArtifact writeResult; try { - bba = hit.getFile().newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT); + bba = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT); writeResult = new KeywordCachedArtifact(bba); } catch (Exception e) { logger.log(Level.WARNING, "Error adding bb artifact for keyword hit", e); //NON-NLS diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java index 5c1c93e548..55e19676aa 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java @@ -38,6 +38,7 @@ import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.Content; /** * Stores the results from running a Solr query (which could contain multiple @@ -148,10 +149,10 @@ class QueryResults { if (writeResult != null) { newArtifacts.add(writeResult.getArtifact()); if (notifyInbox) { - writeSingleFileInboxMessage(writeResult, hit.getFile()); // RJCTODO: Consider rewriting this message post code + writeSingleFileInboxMessage(writeResult, hit.getContent()); // RJCTODO: Consider rewriting this message post code } } else { - logger.log(Level.WARNING, "BB artifact for keyword hit not written, file: {0}, hit: {1}", new Object[]{hit.getFile(), keyword.toString()}); //NON-NLS + logger.log(Level.WARNING, "BB artifact for keyword hit not written, file: {0}, hit: {1}", new Object[]{hit.getContent(), keyword.toString()}); //NON-NLS } } } @@ -185,7 +186,7 @@ class QueryResults { * @param written * @param hitFile */ - private void writeSingleFileInboxMessage(KeywordCachedArtifact written, AbstractFile hitFile) { + private void writeSingleFileInboxMessage(KeywordCachedArtifact written, Content hitContent) { StringBuilder subjectSb = new StringBuilder(); StringBuilder detailsSb = new StringBuilder(); @@ -222,7 +223,13 @@ class QueryResults { //file detailsSb.append(""); //NON-NLS detailsSb.append(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.fileThLbl")); - detailsSb.append("").append(hitFile.getParentPath()).append(hitFile.getName()).append(""); //NON-NLS + if (hitContent instanceof AbstractFile) { + AbstractFile hitFile = (AbstractFile)hitContent; + detailsSb.append("").append(hitFile.getParentPath()).append(hitFile.getName()).append(""); //NON-NLS + } + else { + detailsSb.append("").append(hitContent.getName()).append(""); //NON-NLS + } detailsSb.append(""); //NON-NLS //list diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java index de62e368e1..eca676ec3a 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java @@ -43,6 +43,13 @@ public class SolrSearchService implements KeywordSearchService { if (artifact == null) return; + // We only support artifact indexing for Autopsy versions that use + // the negative range for artifact ids. + long artifactId = artifact.getArtifactID(); + + if (artifactId > 0) + return; + Case currentCase = Case.getCurrentCase(); if (currentCase == null) return; @@ -51,21 +58,16 @@ public class SolrSearchService implements KeywordSearchService { if (sleuthkitCase == null) return; + Content dataSource; AbstractFile abstractFile = sleuthkitCase.getAbstractFileById(artifact.getObjectID()); - if (abstractFile == null) - return; + if (abstractFile != null) + dataSource = abstractFile.getDataSource(); + else + dataSource = sleuthkitCase.getContentById(artifact.getObjectID()); - Content dataSource = abstractFile.getDataSource(); if (dataSource == null) return; - long artifactId = artifact.getArtifactID(); - - // We only support artifact indexing for Autopsy versions that use - // the negative range for artifact ids. - if (artifactId > 0) - return; - // Concatenate the string values of all attributes into a single // "content" string to be indexed. StringBuilder artifactContents = new StringBuilder(); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java index cc43c1de65..837da8ea51 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java @@ -174,7 +174,7 @@ class TermComponentQuery implements KeywordSearchQuery { KeywordCachedArtifact writeResult; Collection attributes = new ArrayList<>(); try { - bba = hit.getFile().newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT); + bba = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT); writeResult = new KeywordCachedArtifact(bba); } catch (Exception e) { logger.log(Level.WARNING, "Error adding bb artifact for keyword hit", e); //NON-NLS