diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java index 1dad86dd90..cd9e03c9aa 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java @@ -42,7 +42,6 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeIns import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; -import org.sleuthkit.autopsy.centralrepository.datamodel.PersonaAccount; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -57,15 +56,12 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CORRELATION_TYPE; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CORRELATION_VALUE; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_OTHER_CASES; -import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME; -import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT; import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisEvent; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; -import org.sleuthkit.autopsy.centralrepository.datamodel.Persona; import org.sleuthkit.datamodel.Score; import org.sleuthkit.datamodel.TskData; @@ -318,77 +314,7 @@ public class IngestEventsListener { value)); makeAndPostArtifact(BlackboardArtifact.Type.TSK_PREVIOUSLY_UNSEEN, originalArtifact, attributesForNewArtifact, "", Score.SCORE_LIKELY_NOTABLE, "This application has not been previously seen before"); - } - - /** - * *TEMPORARY* Create a "matching persona" hit for an artifact with an account identifier - * associated with a persona - * - * @param originalArtifact the artifact to create the "previously unseen" item - * for - */ - static private void makeAndPostMatchingPersonaArtifact(BlackboardArtifact originalArtifact, Persona persona, - List caseDisplayNames, CorrelationAttributeInstance.Type aType, String value) { - String prevCases = caseDisplayNames.stream().distinct().collect(Collectors.joining(",")); - Collection attributesForNewArtifact = Arrays.asList( - new BlackboardAttribute( - TSK_NAME, MODULE_NAME, - persona.getName()), - new BlackboardAttribute( - TSK_COMMENT, MODULE_NAME, - persona.getComment()), - new BlackboardAttribute( - TSK_CORRELATION_TYPE, MODULE_NAME, - aType.getDisplayName()), - new BlackboardAttribute( - TSK_CORRELATION_VALUE, MODULE_NAME, - value), - new BlackboardAttribute( - TSK_OTHER_CASES, MODULE_NAME, - prevCases) - ); - makeAndPostPersonaArtifact(BlackboardArtifact.Type.TSK_MATCHING_PERSONA, originalArtifact, attributesForNewArtifact, "", - Score.SCORE_LIKELY_NOTABLE, "This account is associated with a persona"); - } - - /** - * *TEMPORARY* Hack to get all the flagged personas associated with the same file to prevent - * duplicates (associate with source file not the account instance artifact). - * Make an artifact to flag the passed in content. - * - * @param originalArtifact Artifact in current case we want to flag - * @param attributesForNewArtifact Attributes to assign to the new artifact - * @param configuration The configuration to be specified for the new artifact hit - * @param score sleuthkit.datamodel.Score to be assigned to this artifact - * @param justification Justification string - */ - private static void makeAndPostPersonaArtifact(BlackboardArtifact.Type newArtifactType, BlackboardArtifact originalArtifact, Collection attributesForNewArtifact, String configuration, - Score score, String justification) { - try { - SleuthkitCase tskCase = originalArtifact.getSleuthkitCase(); - Content originalContent = originalArtifact.getParent(); // Associate artifact with file instead of artifact - Blackboard blackboard = tskCase.getBlackboard(); - // Create artifact if it doesn't already exist. - BlackboardArtifact.ARTIFACT_TYPE type = BlackboardArtifact.ARTIFACT_TYPE.fromID(newArtifactType.getTypeID()); - if (!blackboard.artifactExists(originalContent, type, attributesForNewArtifact)) { - BlackboardArtifact newArtifact = originalContent.newAnalysisResult( - newArtifactType, score, - null, configuration, justification, attributesForNewArtifact) - .getAnalysisResult(); - - try { - // index the artifact for keyword search - blackboard.postArtifact(newArtifact, MODULE_NAME); - } catch (Blackboard.BlackboardException ex) { - LOGGER.log(Level.SEVERE, "Unable to index blackboard artifact " + newArtifact.getArtifactID(), ex); //NON-NLS - } - } - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to create BlackboardArtifact.", ex); // NON-NLS - } catch (IllegalStateException ex) { - LOGGER.log(Level.SEVERE, "Failed to create BlackboardAttribute.", ex); // NON-NLS - } - } + } /** * Make an artifact to flag the passed in artifact. @@ -669,28 +595,6 @@ public class IngestEventsListener { makeAndPostPreviousSeenArtifact(bbArtifact, caseDisplayNames, eamArtifact.getCorrelationType(), eamArtifact.getCorrelationValue()); } - // *TEMPORARY* If we have a field that could be associated with a persona, check whether it is - // and make an artifact if so. Applicable types should be expanded later. - if (flagPreviousItemsEnabled && - ((eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.EMAIL_TYPE_ID) - || eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.PHONE_TYPE_ID)) { - String accountId = eamArtifact.getCorrelationValue(); - Collection personaMatches = Persona.getPersonaByAccountIdentifierLike(accountId); - for (Persona persona : personaMatches) { - // Make sure at least one account is an exact match. - boolean foundExactMatch = false; - for (PersonaAccount personaAccount : persona.getPersonaAccounts()) { - if (accountId.equalsIgnoreCase(personaAccount.getAccount().getIdentifier())) { - foundExactMatch = true; - } - } - if (foundExactMatch) { - List caseDisplayNames = persona.getCases().stream().map(p -> p.getDisplayName()).collect(Collectors.toList()); - makeAndPostMatchingPersonaArtifact(bbArtifact, persona, caseDisplayNames, eamArtifact.getCorrelationType(), eamArtifact.getCorrelationValue()); - } - } - } - // flag previously unseen apps and domains if (flagUniqueItemsEnabled && (eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties index 156fb6b343..b00d4d5540 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties @@ -2,4 +2,4 @@ IngestSettingsPanel.ingestSettingsLabel.text=Ingest Settings IngestSettingsPanel.flagTaggedNotableItemsCheckbox.text=Flag items previously tagged as notable IngestSettingsPanel.flagPreviouslySeenDevicesCheckbox.text=Flag devices and users previously seen in other cases IngestSettingsPanel.createCorrelationPropertiesCheckbox.text=Save items to the Central Repository -IngestSettingsPanel.flagUniqueAppsCheckbox.text=Flag unique apps and domains unseen in other cases +IngestSettingsPanel.flagUniqueAppsCheckbox.text=Flag apps and domains not seen in other cases diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties-MERGED index 839209f091..d15eb90cb2 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties-MERGED @@ -13,4 +13,4 @@ IngestSettingsPanel.ingestSettingsLabel.text=Ingest Settings IngestSettingsPanel.flagTaggedNotableItemsCheckbox.text=Flag items previously tagged as notable IngestSettingsPanel.flagPreviouslySeenDevicesCheckbox.text=Flag devices and users previously seen in other cases IngestSettingsPanel.createCorrelationPropertiesCheckbox.text=Save items to the Central Repository -IngestSettingsPanel.flagUniqueAppsCheckbox.text=Flag unique apps and domains unseen in other cases +IngestSettingsPanel.flagUniqueAppsCheckbox.text=Flag apps and domains not seen in other cases diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/textcontentviewer/TextContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/textcontentviewer/TextContentViewer.java index d7f853caab..426163ef80 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/textcontentviewer/TextContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/textcontentviewer/TextContentViewer.java @@ -24,6 +24,7 @@ import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; /** * A DataContentViewer that displays text with the TextViewers available. @@ -91,14 +92,10 @@ public class TextContentViewer implements DataContentViewer { if (node == null) { return false; } + // get the node's File, if it has one AbstractFile file = node.getLookup().lookup(AbstractFile.class); - if (file == null) { - return false; - } - - // disable the text content viewer for directories and empty files - if (file.isDir() || file.getSize() == 0) { + if (file != null && (file.isDir() || file.getSize() == 0)) { return false; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java index cd0b03fd98..3f08b3f0bb 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java @@ -250,18 +250,16 @@ public class Artifacts { KeywordHits.RootNode keywordsNode = new KeywordHits(skCase, dsObjId).new RootNode(); return new TypeNodeKey(keywordsNode, TSK_KEYWORD_HIT); - } else if (TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == typeId - || TSK_INTERESTING_FILE_HIT.getTypeID() == typeId) { - - InterestingHits.RootNode interestingHitsNode = new InterestingHits(skCase, dsObjId).new RootNode(); - return new TypeNodeKey(interestingHitsNode, - TSK_INTERESTING_ARTIFACT_HIT, - TSK_INTERESTING_FILE_HIT); - + } else if (TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == typeId) { + InterestingHits.RootNode interestingHitsNode = new InterestingHits(skCase, TSK_INTERESTING_ARTIFACT_HIT, dsObjId).new RootNode(); + return new TypeNodeKey(interestingHitsNode, TSK_INTERESTING_ARTIFACT_HIT); + } else if (TSK_INTERESTING_FILE_HIT.getTypeID() == typeId) { + InterestingHits.RootNode interestingHitsNode = new InterestingHits(skCase, TSK_INTERESTING_FILE_HIT, dsObjId).new RootNode(); + return new TypeNodeKey(interestingHitsNode, TSK_INTERESTING_FILE_HIT); } else if (TSK_HASHSET_HIT.getTypeID() == typeId) { HashsetHits.RootNode hashsetHits = new HashsetHits(skCase, dsObjId).new RootNode(); return new TypeNodeKey(hashsetHits, TSK_HASHSET_HIT); - + } else { return new TypeNodeKey(type, dsObjId); } @@ -278,7 +276,7 @@ public class Artifacts { */ private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); private final Category category; - + private final PropertyChangeListener weakPcl; /** @@ -293,7 +291,7 @@ public class Artifacts { super(); this.filteringDSObjId = filteringDSObjId; this.category = category; - + PropertyChangeListener pcl = (PropertyChangeEvent evt) -> { String eventType = evt.getPropertyName(); if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { @@ -322,9 +320,9 @@ public class Artifacts { weakPcl = WeakListeners.propertyChange(pcl, null); } - + @Override - protected void addNotify() { + protected void addNotify() { super.addNotify(); refreshThrottler.registerForIngestModuleEvents(); IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl); @@ -632,7 +630,7 @@ public class Artifacts { } } }; - + private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null); @Override @@ -643,7 +641,7 @@ public class Artifacts { @Override protected void onRemove() { - if(refreshThrottler != null) { + if (refreshThrottler != null) { refreshThrottler.unregisterEventListener(); } IngestManager.getInstance().removeIngestJobEventListener(weakPcl); @@ -663,14 +661,14 @@ public class Artifacts { case ANALYSIS_RESULT: arts = (filteringDSObjId > 0) - ? blackboard.getAnalysisResultsByType(type.getTypeID(), filteringDSObjId) - : blackboard.getAnalysisResultsByType(type.getTypeID()); + ? blackboard.getAnalysisResultsByType(type.getTypeID(), filteringDSObjId) + : blackboard.getAnalysisResultsByType(type.getTypeID()); break; case DATA_ARTIFACT: default: arts = (filteringDSObjId > 0) - ? blackboard.getDataArtifacts(type.getTypeID(), filteringDSObjId) - : blackboard.getDataArtifacts(type.getTypeID()); + ? blackboard.getDataArtifacts(type.getTypeID(), filteringDSObjId) + : blackboard.getDataArtifacts(type.getTypeID()); break; } @@ -679,9 +677,9 @@ public class Artifacts { //See JIRA-5969 art.getAttributes(); } - + @SuppressWarnings("unchecked") - List toRet = (List)(List)arts; + List toRet = (List) (List) arts; return toRet; } catch (NoCurrentCaseException ex) { logger.log(Level.WARNING, "Trying to access case when no case is open.", ex); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index 47db7732ea..1acce2bb7e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -181,15 +181,13 @@ public interface DisplayableItemNodeVisitor { T visit(EmptyNode.MessageNode emptyNode); - T visit(InterestingHits.InterestingItemTypeNode aThis); - /* * Attachments */ T visit(AttachmentNode node); - + T visit(OsAccounts.OsAccountNode node); - + T visit(OsAccounts.OsAccountListNode node); T visit(PersonNode node); @@ -197,12 +195,12 @@ public interface DisplayableItemNodeVisitor { T visit(HostNode node); T visit(DataSourcesNode node); - + /* * Unsupported node */ T visit(UnsupportedContentNode ucn); - + T visit(LocalFilesDataSourceNode lfdsn); /** @@ -332,11 +330,6 @@ public interface DisplayableItemNodeVisitor { return defaultVisit(ftByMimeTypeEmptyNode); } - @Override - public T visit(InterestingHits.InterestingItemTypeNode interestingItemTypeNode) { - return defaultVisit(interestingItemTypeNode); - } - @Override public T visit(DeletedContentNode dcn) { return defaultVisit(dcn); @@ -546,12 +539,12 @@ public interface DisplayableItemNodeVisitor { public T visit(AttachmentNode node) { return defaultVisit(node); } - + @Override public T visit(OsAccounts.OsAccountNode node) { return defaultVisit(node); } - + @Override public T visit(OsAccounts.OsAccountListNode node) { return defaultVisit(node); @@ -571,12 +564,12 @@ public interface DisplayableItemNodeVisitor { public T visit(PersonNode node) { return defaultVisit(node); } - + @Override public T visit(UnsupportedContentNode node) { return defaultVisit(node); } - + @Override public T visit(LocalFilesDataSourceNode node) { return defaultVisit(node); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index f636264082..c22d095726 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -51,70 +51,95 @@ import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; import org.sleuthkit.datamodel.AnalysisResult; +import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; public class InterestingHits implements AutopsyVisitableItem { - private static final String INTERESTING_ITEMS = NbBundle - .getMessage(InterestingHits.class, "InterestingHits.interestingItems.text"); - private static final String DISPLAY_NAME = NbBundle.getMessage(InterestingHits.class, "InterestingHits.displayName.text"); private static final Logger logger = Logger.getLogger(InterestingHits.class.getName()); private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED); private static final Set INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED); + private SleuthkitCase skCase; private final InterestingResults interestingResults = new InterestingResults(); private final long filteringDSObjId; // 0 if not filtering/grouping by data source + private final BlackboardArtifact.Type artifactType; /** * Constructor * - * @param skCase Case DB + * @param skCase Case DB + * @param artifactType The artifact type (either interesting file or + * artifact). * */ - public InterestingHits(SleuthkitCase skCase) { - this(skCase, 0); + public InterestingHits(SleuthkitCase skCase, BlackboardArtifact.Type artifactType) { + this(skCase, artifactType, 0); } /** * Constructor * - * @param skCase Case DB - * @param objId Object id of the data source + * @param skCase Case DB + * @param artifactType The artifact type (either interesting file or + * artifact). + * @param objId Object id of the data source * */ - public InterestingHits(SleuthkitCase skCase, long objId) { + public InterestingHits(SleuthkitCase skCase, BlackboardArtifact.Type artifactType, long objId) { this.skCase = skCase; + this.artifactType = artifactType; this.filteringDSObjId = objId; interestingResults.update(); } + /** + * Cache of result ids mapped by artifact type -> set name -> artifact id. + */ private class InterestingResults extends Observable { // NOTE: the map can be accessed by multiple worker threads and needs to be synchronized - private final Map>> interestingItemsMap = new LinkedHashMap<>(); + private final Map> interestingItemsMap = new LinkedHashMap<>(); - public List getSetNames() { + /** + * Returns all the set names for a given interesting item type. + * + * @param type The interesting item type. + * + * @return The set names. + */ + List getSetNames() { List setNames; synchronized (interestingItemsMap) { setNames = new ArrayList<>(interestingItemsMap.keySet()); } - Collections.sort(setNames); + Collections.sort(setNames, (a, b) -> a.compareToIgnoreCase(b)); return setNames; } - public Set getArtifactIds(String setName, String typeName) { + /** + * Returns all artifact ids belonging to the specified interesting item + * type and set name. + * + * @param type The interesting item type. + * @param setName The set name. + * + * @return The artifact ids in that set name and type. + */ + Set getArtifactIds(String setName) { synchronized (interestingItemsMap) { - return interestingItemsMap.get(setName).get(typeName); + return new HashSet<>(interestingItemsMap.getOrDefault(setName, Collections.emptySet())); } } - public void update() { + /** + * Triggers a fetch from the database to update this cache. + */ + void update() { synchronized (interestingItemsMap) { interestingItemsMap.clear(); } - loadArtifacts(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT); - loadArtifacts(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT); + loadArtifacts(); setChanged(); notifyObservers(); } @@ -124,18 +149,18 @@ public class InterestingHits implements AutopsyVisitableItem { * the interestingItemsMap */ @SuppressWarnings("deprecation") - private void loadArtifacts(BlackboardArtifact.Type artType) { + private void loadArtifacts() { if (skCase == null) { return; } int setNameId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(); - int artId = artType.getTypeID(); - String query = "SELECT value_text,blackboard_artifacts.artifact_obj_id,attribute_type_id " //NON-NLS + + String query = "SELECT value_text, blackboard_artifacts.artifact_obj_id " //NON-NLS + "FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS + "attribute_type_id=" + setNameId //NON-NLS + " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS - + " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS + + " AND blackboard_artifacts.artifact_type_id = " + artifactType.getTypeID(); //NON-NLS if (filteringDSObjId > 0) { query += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId; } @@ -146,12 +171,9 @@ public class InterestingHits implements AutopsyVisitableItem { while (resultSet.next()) { String value = resultSet.getString("value_text"); //NON-NLS long artifactObjId = resultSet.getLong("artifact_obj_id"); //NON-NLS - if (!interestingItemsMap.containsKey(value)) { - interestingItemsMap.put(value, new LinkedHashMap<>()); - interestingItemsMap.get(value).put(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getDisplayName(), new HashSet<>()); - interestingItemsMap.get(value).put(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName(), new HashSet<>()); - } - interestingItemsMap.get(value).get(artType.getDisplayName()).add(artifactObjId); + interestingItemsMap + .computeIfAbsent(value, (k) -> new HashSet<>()) + .add(artifactObjId); } } } catch (TskCoreException | SQLException ex) { @@ -166,54 +188,8 @@ public class InterestingHits implements AutopsyVisitableItem { } /** - * Node for the interesting items + * Creates nodes for all sets for a specified interesting item type. */ - public class RootNode extends UpdatableCountTypeNode { - - public RootNode() { - super(Children.create(new SetNameFactory(), true), - Lookups.singleton(DISPLAY_NAME), - DISPLAY_NAME, - filteringDSObjId, - BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT, - BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT); - super.setName(INTERESTING_ITEMS); - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS - } - - @Override - public boolean isLeafTypeNode() { - return false; - } - - @Override - public T accept(DisplayableItemNodeVisitor visitor) { - return visitor.visit(this); - } - - @Override - protected Sheet createSheet() { - Sheet sheet = super.createSheet(); - Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES); - if (sheetSet == null) { - sheetSet = Sheet.createPropertiesSet(); - sheet.put(sheetSet); - } - - sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"), - NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.displayName"), - NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.desc"), - getName())); - - return sheet; - } - - @Override - public String getItemType() { - return getClass().getName(); - } - } - private class SetNameFactory extends ChildFactory.Detachable implements Observer { /* @@ -239,8 +215,7 @@ public class InterestingHits implements AutopsyVisitableItem { * event to have a null oldValue. */ ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); - if (null != eventData && (eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() - || eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID())) { + if (null != eventData && (eventData.getBlackboardArtifactType().getTypeID() == artifactType.getTypeID())) { interestingResults.update(); } } catch (NoCurrentCaseException notUsed) { @@ -272,26 +247,8 @@ public class InterestingHits implements AutopsyVisitableItem { } } }; - - private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null); - - @Override - protected void addNotify() { - IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl); - IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, weakPcl); - Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl); - interestingResults.update(); - interestingResults.addObserver(this); - } - @Override - protected void finalize() throws Throwable { - super.finalize(); - IngestManager.getInstance().removeIngestJobEventListener(weakPcl); - IngestManager.getInstance().removeIngestModuleEventListener(weakPcl); - Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl); - interestingResults.deleteObserver(this); - } + private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null); @Override protected boolean createKeys(List list) { @@ -308,14 +265,35 @@ public class InterestingHits implements AutopsyVisitableItem { public void update(Observable o, Object arg) { refresh(true); } + + @Override + protected void addNotify() { + IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl); + IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, weakPcl); + Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl); + interestingResults.addObserver(this); + interestingResults.update(); + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + IngestManager.getInstance().removeIngestJobEventListener(weakPcl); + IngestManager.getInstance().removeIngestModuleEventListener(weakPcl); + Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl); + interestingResults.deleteObserver(this); + } } + /** + * A node for a set to be displayed in the tree. + */ public class SetNameNode extends DisplayableItemNode implements Observer { private final String setName; public SetNameNode(String setName) {//, Set children) { - super(Children.create(new HitTypeFactory(setName), true), Lookups.singleton(setName)); + super(Children.create(new HitFactory(setName), true), Lookups.singleton(setName)); this.setName = setName; super.setName(setName); updateDisplayName(); @@ -324,111 +302,81 @@ public class InterestingHits implements AutopsyVisitableItem { } private void updateDisplayName() { - int sizeOfSet = interestingResults.getArtifactIds(setName, BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName()).size() - + interestingResults.getArtifactIds(setName, BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getDisplayName()).size(); + int sizeOfSet = interestingResults.getArtifactIds(setName).size(); super.setDisplayName(setName + " (" + sizeOfSet + ")"); } + @Override + public boolean isLeafTypeNode() { + return true; + } + + @Override + protected Sheet createSheet() { + Sheet sheet = super.createSheet(); + Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES); + if (sheetSet == null) { + sheetSet = Sheet.createPropertiesSet(); + sheet.put(sheetSet); + } + + sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"), + NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"), + NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.desc"), + getName())); + + return sheet; + } + + @Override + public T accept(DisplayableItemNodeVisitor visitor) { + return visitor.visit(this); + } + + @Override + public void update(Observable o, Object arg) { + updateDisplayName(); + } + + @Override + public String getItemType() { + /** + * For custom settings for each rule set, return + * getClass().getName() + setName instead. + */ + return getClass().getName(); + } + } + + /** + * Parent node for interesting item type that shows child set nodes. + */ + public class RootNode extends UpdatableCountTypeNode { + + /** + * Main constructor. + */ + public RootNode() { + super(Children.create(new SetNameFactory(), true), + Lookups.singleton(artifactType), + artifactType.getDisplayName(), + filteringDSObjId, + artifactType); + + /** + * We use the combination of setName and typeName as the name of the + * node to ensure that nodes have a unique name. This comes into + * play when associating paging state with the node. + */ + setName(artifactType.getDisplayName()); + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS + } + @Override public boolean isLeafTypeNode() { return false; } - @Override - protected Sheet createSheet() { - Sheet sheet = super.createSheet(); - Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES); - if (sheetSet == null) { - sheetSet = Sheet.createPropertiesSet(); - sheet.put(sheetSet); - } - - sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"), - NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"), - NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.desc"), - getName())); - - return sheet; - } - - @Override - public T accept(DisplayableItemNodeVisitor visitor) { - return visitor.visit(this); - } - - @Override - public void update(Observable o, Object arg) { - updateDisplayName(); - } - - @Override - public String getItemType() { - /** - * For custom settings for each rule set, return - * getClass().getName() + setName instead. - */ - return getClass().getName(); - } - } - - private class HitTypeFactory extends ChildFactory implements Observer { - - private final String setName; - private final Map artifactHits = new HashMap<>(); - - private HitTypeFactory(String setName) { - super(); - this.setName = setName; - interestingResults.addObserver(this); - } - - @Override - protected boolean createKeys(List list) { - list.add(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getDisplayName()); - list.add(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName()); - return true; - } - - @Override - protected Node createNodeForKey(String key) { - return new InterestingItemTypeNode(setName, key); - } - - @Override - public void update(Observable o, Object arg) { - refresh(true); - } - } - - public class InterestingItemTypeNode extends DisplayableItemNode implements Observer { - - private final String typeName; - private final String setName; - - private InterestingItemTypeNode(String setName, String typeName) { - super(Children.create(new HitFactory(setName, typeName), true), Lookups.singleton(setName)); - this.typeName = typeName; - this.setName = setName; - /** - * We use the combination of setName and typeName as the name of the - * node to ensure that nodes have a unique name. This comes into - * play when associating paging state with the node. - */ - super.setName(setName + "_" + typeName); - updateDisplayName(); - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS - interestingResults.addObserver(this); - } - - private void updateDisplayName() { - super.setDisplayName(typeName + " (" + interestingResults.getArtifactIds(setName, typeName).size() + ")"); - } - - @Override - public boolean isLeafTypeNode() { - return true; - } - @Override protected Sheet createSheet() { Sheet sheet = super.createSheet(); @@ -449,11 +397,6 @@ public class InterestingHits implements AutopsyVisitableItem { return visitor.visit(this); } - @Override - public void update(Observable o, Object arg) { - updateDisplayName(); - } - @Override public String getItemType() { /** @@ -464,21 +407,27 @@ public class InterestingHits implements AutopsyVisitableItem { } } + /** + * Factory for creating individual interesting item BlackboardArtifactNodes. + */ private class HitFactory extends BaseChildFactory implements Observer { private final String setName; - private final String typeName; private final Map artifactHits = new HashMap<>(); - private HitFactory(String setName, String typeName) { + /** + * Main constructor. + * + * @param setName The set name of artifacts to be displayed. + */ + private HitFactory(String setName) { /** * The node name passed to the parent constructor must be the same * as the name set in the InterestingItemTypeNode constructor, i.e. * setName underscore typeName */ - super(setName + "_" + typeName); + super(setName); this.setName = setName; - this.typeName = typeName; interestingResults.addObserver(this); } @@ -486,7 +435,7 @@ public class InterestingHits implements AutopsyVisitableItem { protected List makeKeys() { if (skCase != null) { - interestingResults.getArtifactIds(setName, typeName).forEach((id) -> { + interestingResults.getArtifactIds(setName).forEach((id) -> { try { if (!artifactHits.containsKey(id)) { AnalysisResult art = skCase.getBlackboard().getAnalysisResultById(id); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index bf7ee1caba..9c84b85bfe 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -1481,7 +1481,7 @@ final public class Accounts implements AutopsyVisitableItem { } } - final private class CreditCardNumberFactory extends ObservingChildren { + final private class CreditCardNumberFactory extends ObservingChildren { private final BinResult bin; @@ -1502,10 +1502,10 @@ final public class Accounts implements AutopsyVisitableItem { } @Override - protected boolean createKeys(List list) { + protected boolean createKeys(List list) { String query - = "SELECT blackboard_artifacts.artifact_id " //NON-NLS + = "SELECT blackboard_artifacts.artifact_obj_id " //NON-NLS + " FROM blackboard_artifacts " //NON-NLS + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS @@ -1517,7 +1517,7 @@ final public class Accounts implements AutopsyVisitableItem { try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); ResultSet rs = results.getResultSet();) { while (rs.next()) { - list.add(rs.getLong("artifact_id")); //NON-NLS + list.add(skCase.getBlackboard().getDataArtifactById(rs.getLong("artifact_obj_id"))); //NON-NLS } } catch (TskCoreException | SQLException ex) { LOGGER.log(Level.SEVERE, "Error querying for account artifacts.", ex); //NON-NLS @@ -1527,18 +1527,8 @@ final public class Accounts implements AutopsyVisitableItem { } @Override - protected Node[] createNodesForKey(Long artifactID) { - if (skCase == null) { - return new Node[0]; - } - - try { - DataArtifact art = skCase.getBlackboard().getDataArtifactById(artifactID); - return new Node[]{new AccountArtifactNode(art)}; - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Error creating BlackboardArtifactNode for artifact with ID " + artifactID, ex); //NON-NLS - return new Node[0]; - } + protected Node[] createNodesForKey(DataArtifact artifact) { + return new Node[]{new AccountArtifactNode(artifact)}; } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 975a659aa7..70c70fe45b 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -1271,9 +1271,10 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat treeNode = getHashsetNode(typesChildren, art); } else if (typeID == BlackboardArtifact.Type.TSK_KEYWORD_HIT.getTypeID()) { treeNode = getKeywordHitNode(typesChildren, art); - } else if (typeID == BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID() - || typeID == BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) { - treeNode = getInterestingItemNode(typesChildren, art); + } else if (typeID == BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID()) { + treeNode = getInterestingItemNode(typesChildren, BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT, art); + } else if (typeID == BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) { + treeNode = getInterestingItemNode(typesChildren, BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT, art); } else if (typeID == BlackboardArtifact.Type.TSK_EMAIL_MSG.getTypeID()) { treeNode = getEmailNode(typesChildren, art); } else if (typeID == BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID()) { @@ -1401,42 +1402,46 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat * * @param typesChildren The children object of the same category as * interesting item. + * @param artifactType The type of the artifact (interesting hit or + * artifact). * @param art The artifact. * * @return The interesting item artifact's parent node or null if cannot be * found. */ - private Node getInterestingItemNode(Children typesChildren, BlackboardArtifact art) { - Node interestingItemsRootNode = typesChildren.findChild(NbBundle - .getMessage(InterestingHits.class, "InterestingHits.interestingItems.text")); - Children interestingItemsRootChildren = interestingItemsRootNode.getChildren(); + private Node getInterestingItemNode(Children typesChildren, BlackboardArtifact.Type artifactType, BlackboardArtifact art) { + Node interestingItemsRootNode = typesChildren.findChild(artifactType.getDisplayName()); + Children setNodeChildren = (interestingItemsRootNode == null) ? null : interestingItemsRootNode.getChildren(); + + // set node children for type could not be found, so return null. + if (setNodeChildren == null) { + return null; + } + + String setName = null; try { - String setName = null; - List attributes = art.getAttributes(); - for (BlackboardAttribute att : attributes) { - int typeId = att.getAttributeType().getTypeID(); - if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) { - setName = att.getValueString(); - } - } - Node setNode = interestingItemsRootChildren.findChild(setName); - if (setNode == null) { - return null; - } + setName = art.getAttributes().stream() + .filter(attr -> attr.getAttributeType().getTypeID() == BlackboardAttribute.Type.TSK_SET_NAME.getTypeID()) + .map(attr -> attr.getValueString()) + .findFirst() + .orElse(null); - Children fileArtifactChildren = setNode.getChildren(); - Node[] fileArtifactNodes = fileArtifactChildren == null ? null : fileArtifactChildren.getNodes(); - if (fileArtifactNodes == null || fileArtifactNodes.length != 2) { - return null; - } - - return (art.getArtifactTypeID() == BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID()) - ? fileArtifactNodes[0] - : fileArtifactNodes[1]; } catch (TskCoreException ex) { LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS return null; } + + // if no set name, no set node will be identified. + if (setName == null) { + return null; + } + + // make sure data is fully loaded + final String finalSetName = setName; + return Stream.of(setNodeChildren.getNodes(true)) + .filter(setNode -> finalSetName.equals(setNode.getLookup().lookup(String.class))) + .findFirst() + .orElse(null); } /** diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchAction.java index a3f64f1e13..348d3d5148 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchAction.java @@ -23,31 +23,28 @@ import javax.swing.AbstractAction; import org.openide.util.Lookup; /** - * - * @author dfickling + * The “File Search by Attributes” action for data sources in the tree. */ public class FileSearchAction extends AbstractAction { - private final Long dataSourceId; + private final long dataSourceId; + /** + * Main constructor. + * + * @param title The display name for the action. + * @param dataSourceID The data source id of the item that is selected in + * the tree. + */ public FileSearchAction(String title, long dataSourceID) { super(title); dataSourceId = dataSourceID; } - public FileSearchAction(String title) { - super(title); - dataSourceId = null; - } - @Override public void actionPerformed(ActionEvent e) { FileSearchProvider searcher = Lookup.getDefault().lookup(FileSearchProvider.class); - if (dataSourceId == null) { - searcher.showDialog(); - } else { - searcher.showDialog(dataSourceId); - } + searcher.showDialog(dataSourceId); } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/plaso/PlasoIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/plaso/PlasoIngestModule.java index 4d4bd63da6..f2b7e5942f 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/plaso/PlasoIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/plaso/PlasoIngestModule.java @@ -326,7 +326,7 @@ public class PlasoIngestModule implements DataSourceIngestModule { // If the description is empty use the event type display name // as the description. if (description == null || description.isEmpty()) { - if (eventType != TimelineEventType.OTHER) { + if (eventType != TimelineEventType.STANDARD_ARTIFACT_CATCH_ALL) { description = eventType.getDisplayName(); } else { continue; @@ -440,7 +440,7 @@ public class PlasoIngestModule implements DataSourceIngestModule { return TimelineEventType.REGISTRY; } default: - return TimelineEventType.OTHER; + return TimelineEventType.STANDARD_ARTIFACT_CATCH_ALL; } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Manifest.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Manifest.java index c2b7ae5259..a6edfb4415 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Manifest.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Manifest.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,30 +30,44 @@ import javax.annotation.concurrent.Immutable; public final class Manifest implements Serializable { private static final long serialVersionUID = 1L; - private final Path filePath; + + // NOTE: Path is not Serializable. That's why we have to have a String as well, + // for scenarios when we send Manifest via ActiveMQ to other nodes. + private transient Path filePath; + private final String filePathString; + private transient Path dataSourcePath; + private final String dataSourcePathString; + private final Date dateFileCreated; private final String caseName; private final String deviceId; - private final Path dataSourcePath; private final String dataSourceFileName; private final Map manifestProperties; public Manifest(Path manifestFilePath, Date dateFileCreated, String caseName, String deviceId, Path dataSourcePath, Map manifestProperties) { - this.filePath = Paths.get(manifestFilePath.toString()); + this.filePathString = manifestFilePath.toString(); + this.filePath = Paths.get(filePathString); + this.dateFileCreated = new Date(dateFileCreated.getTime()); this.caseName = caseName; this.deviceId = deviceId; if (null != dataSourcePath) { - this.dataSourcePath = Paths.get(dataSourcePath.toString()); + this.dataSourcePathString = dataSourcePath.toString(); + this.dataSourcePath = Paths.get(dataSourcePathString); dataSourceFileName = dataSourcePath.getFileName().toString(); } else { + this.dataSourcePathString = ""; this.dataSourcePath = Paths.get(""); dataSourceFileName = ""; } this.manifestProperties = new HashMap<>(manifestProperties); - } + } public Path getFilePath() { + // after potential deserialization Path will be null because it is transient + if (filePath == null) { + this.filePath = Paths.get(filePathString); + } return this.filePath; } @@ -70,6 +84,10 @@ public final class Manifest implements Serializable { } public Path getDataSourcePath() { + // after potential deserialization Path will be null because it is transient + if (dataSourcePath == null) { + this.dataSourcePath = Paths.get(dataSourcePathString); + } return dataSourcePath; }