mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-15 09:17:42 +00:00
Merge pull request #6949 from gdicristofaro/7561-treeHierarchy
7561 tree hierarchy
This commit is contained in:
commit
e39d8960ab
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2021 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.datamodel;
|
||||||
|
|
||||||
|
import org.openide.nodes.Children;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analysis Results node support.
|
||||||
|
*/
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"AnalysisResults_name=Analysis Results",})
|
||||||
|
public class AnalysisResults implements AutopsyVisitableItem {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of this node that is the key in the children object.
|
||||||
|
*
|
||||||
|
* @return The name of this node that is the key in the children object.
|
||||||
|
*/
|
||||||
|
public static String getName() {
|
||||||
|
return Bundle.AnalysisResults_name();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parent node of all analysis results.
|
||||||
|
*/
|
||||||
|
static class RootNode extends Artifacts.BaseArtifactNode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param filteringDSObjId The data source object id for which results
|
||||||
|
* should be filtered. If no filtering should
|
||||||
|
* occur, this number should be less than or
|
||||||
|
* equal to 0.
|
||||||
|
*/
|
||||||
|
RootNode(long filteringDSObjId) {
|
||||||
|
super(Children.create(new Artifacts.TypeFactory(BlackboardArtifact.Category.ANALYSIS_RESULT, filteringDSObjId), true),
|
||||||
|
"org/sleuthkit/autopsy/images/analysis_result.png",
|
||||||
|
AnalysisResults.getName(),
|
||||||
|
AnalysisResults.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final long datasourceObjId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*/
|
||||||
|
public AnalysisResults() {
|
||||||
|
this(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param dsObjId The data source object id.
|
||||||
|
*/
|
||||||
|
public AnalysisResults(long dsObjId) {
|
||||||
|
this.datasourceObjId = dsObjId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T accept(AutopsyItemVisitor<T> visitor) {
|
||||||
|
return visitor.visit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not there is a data source object for which results
|
||||||
|
* should be filtered.
|
||||||
|
*
|
||||||
|
* @return Whether or not there is a data source object for which results
|
||||||
|
* should be filtered.
|
||||||
|
*/
|
||||||
|
Long getFilteringDataSourceObjId() {
|
||||||
|
return datasourceObjId;
|
||||||
|
}
|
||||||
|
}
|
704
Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java
Normal file
704
Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java
Normal file
@ -0,0 +1,704 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2011-2020 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.datamodel;
|
||||||
|
|
||||||
|
import java.beans.PropertyChangeEvent;
|
||||||
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import org.openide.nodes.ChildFactory;
|
||||||
|
import org.openide.nodes.Children;
|
||||||
|
import org.openide.nodes.Node;
|
||||||
|
import org.openide.nodes.Sheet;
|
||||||
|
import org.openide.util.Lookup;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.lookup.Lookups;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.accounts.Accounts;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.utils.IconsUtil;
|
||||||
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
|
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
import org.sleuthkit.autopsy.guiutils.RefreshThrottler;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifact.Category;
|
||||||
|
import org.python.google.common.collect.Sets;
|
||||||
|
import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_ACCOUNT;
|
||||||
|
import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_DATA_SOURCE_USAGE;
|
||||||
|
import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_EMAIL_MSG;
|
||||||
|
import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_HASHSET_HIT;
|
||||||
|
import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT;
|
||||||
|
import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT;
|
||||||
|
import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_GEN_INFO;
|
||||||
|
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE;
|
||||||
|
import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_TL_EVENT;
|
||||||
|
import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_ASSOCIATED_OBJECT;
|
||||||
|
import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_KEYWORD_HIT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classes for creating nodes for BlackboardArtifacts.
|
||||||
|
*/
|
||||||
|
public class Artifacts {
|
||||||
|
|
||||||
|
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST
|
||||||
|
= EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for a parent node of artifacts.
|
||||||
|
*/
|
||||||
|
static class BaseArtifactNode extends DisplayableItemNode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param children The children of the node.
|
||||||
|
* @param icon The icon for the node.
|
||||||
|
* @param name The name identifier of the node.
|
||||||
|
* @param displayName The display name for the node.
|
||||||
|
*/
|
||||||
|
BaseArtifactNode(Children children, String icon, String name, String displayName) {
|
||||||
|
super(children, Lookups.singleton(name));
|
||||||
|
super.setName(name);
|
||||||
|
super.setDisplayName(displayName);
|
||||||
|
this.setIconBaseWithExtension(icon); //NON-NLS
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeafTypeNode() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T accept(DisplayableItemNodeVisitor<T> 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(), "ExtractedContentNode.createSheet.name.name"),
|
||||||
|
NbBundle.getMessage(this.getClass(), "ExtractedContentNode.createSheet.name.displayName"),
|
||||||
|
NbBundle.getMessage(this.getClass(), "ExtractedContentNode.createSheet.name.desc"),
|
||||||
|
super.getDisplayName()));
|
||||||
|
return sheet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getItemType() {
|
||||||
|
return getClass().getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A key to be used with the type factory.
|
||||||
|
*/
|
||||||
|
private static class TypeNodeKey {
|
||||||
|
|
||||||
|
private final UpdatableCountTypeNode node;
|
||||||
|
private final Set<BlackboardArtifact.Type> applicableTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor generating a generic TypeNode for a given artifact type.
|
||||||
|
*
|
||||||
|
* @param type The type for the key.
|
||||||
|
* @param dsObjId The data source object id if filtering should occur.
|
||||||
|
* If no filtering should occur, this number should be
|
||||||
|
* less than or equal to 0.
|
||||||
|
*/
|
||||||
|
TypeNodeKey(BlackboardArtifact.Type type, long dsObjId) {
|
||||||
|
this(new TypeNode(type, dsObjId), type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for any UpdatableCountTypeNode.
|
||||||
|
*
|
||||||
|
* @param typeNode The UpdatableCountTypeNode.
|
||||||
|
* @param types The blackboard artifact types corresponding to this
|
||||||
|
* node.
|
||||||
|
*/
|
||||||
|
TypeNodeKey(UpdatableCountTypeNode typeNode, BlackboardArtifact.Type... types) {
|
||||||
|
this.node = typeNode;
|
||||||
|
this.applicableTypes = Stream.of(types)
|
||||||
|
.filter(t -> t != null)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the node associated with this key.
|
||||||
|
*
|
||||||
|
* @return The node associated with this key.
|
||||||
|
*/
|
||||||
|
UpdatableCountTypeNode getNode() {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the blackboard artifact types associated with this key.
|
||||||
|
*
|
||||||
|
* @return The blackboard artifact types associated with this key.
|
||||||
|
*/
|
||||||
|
Set<BlackboardArtifact.Type> getApplicableTypes() {
|
||||||
|
return applicableTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int hash = 3;
|
||||||
|
hash = 61 * hash + Objects.hashCode(this.applicableTypes);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final TypeNodeKey other = (TypeNodeKey) obj;
|
||||||
|
if (!Objects.equals(this.applicableTypes, other.applicableTypes)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory for showing a list of artifact types (i.e. all the data artifact
|
||||||
|
* types).
|
||||||
|
*/
|
||||||
|
static class TypeFactory extends ChildFactory.Detachable<TypeNodeKey> implements RefreshThrottler.Refresher {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(TypeNode.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Types that should not be shown in the tree.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
private static final Set<BlackboardArtifact.Type> IGNORED_TYPES = Sets.newHashSet(
|
||||||
|
// these are shown in other parts of the UI (and different node types)
|
||||||
|
TSK_DATA_SOURCE_USAGE,
|
||||||
|
TSK_GEN_INFO,
|
||||||
|
new BlackboardArtifact.Type(TSK_DOWNLOAD_SOURCE),
|
||||||
|
TSK_TL_EVENT,
|
||||||
|
//This is not meant to be shown in the UI at all. It is more of a meta artifact.
|
||||||
|
TSK_ASSOCIATED_OBJECT
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a Children key to be use for a particular artifact type.
|
||||||
|
*
|
||||||
|
* @param type The artifact type.
|
||||||
|
* @param skCase The relevant Sleuthkit case in order to create the
|
||||||
|
* node.
|
||||||
|
* @param dsObjId The data source object id to use for filtering. If id
|
||||||
|
* is less than or equal to 0, no filtering will occur.
|
||||||
|
*
|
||||||
|
* @return The generated key.
|
||||||
|
*/
|
||||||
|
private static TypeNodeKey getTypeKey(BlackboardArtifact.Type type, SleuthkitCase skCase, long dsObjId) {
|
||||||
|
int typeId = type.getTypeID();
|
||||||
|
if (TSK_EMAIL_MSG.getTypeID() == typeId) {
|
||||||
|
EmailExtracted.RootNode emailNode = new EmailExtracted(skCase, dsObjId).new RootNode();
|
||||||
|
return new TypeNodeKey(emailNode, TSK_EMAIL_MSG);
|
||||||
|
|
||||||
|
} else if (TSK_ACCOUNT.getTypeID() == typeId) {
|
||||||
|
Accounts.AccountsRootNode accountsNode = new Accounts(skCase, dsObjId).new AccountsRootNode();
|
||||||
|
return new TypeNodeKey(accountsNode, TSK_ACCOUNT);
|
||||||
|
|
||||||
|
} else if (TSK_KEYWORD_HIT.getTypeID() == typeId) {
|
||||||
|
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_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// maps the artifact type to its child node
|
||||||
|
private final Map<BlackboardArtifact.Type, TypeNodeKey> typeNodeMap = new HashMap<>();
|
||||||
|
private final long filteringDSObjId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RefreshThrottler is used to limit the number of refreshes performed
|
||||||
|
* when CONTENT_CHANGED and DATA_ADDED ingest module events are
|
||||||
|
* received.
|
||||||
|
*/
|
||||||
|
private final RefreshThrottler refreshThrottler = new RefreshThrottler(this);
|
||||||
|
private final Category category;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param category The category of types to be displayed.
|
||||||
|
* @param filteringDSObjId The data source object id to use for
|
||||||
|
* filtering. If id is less than or equal to 0,
|
||||||
|
* no filtering will occur.
|
||||||
|
*/
|
||||||
|
TypeFactory(Category category, long filteringDSObjId) {
|
||||||
|
super();
|
||||||
|
this.filteringDSObjId = filteringDSObjId;
|
||||||
|
this.category = category;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
|
||||||
|
String eventType = evt.getPropertyName();
|
||||||
|
if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
|
||||||
|
// case was closed. Remove listeners so that we don't get called with a stale case handle
|
||||||
|
if (evt.getNewValue() == null) {
|
||||||
|
removeNotify();
|
||||||
|
}
|
||||||
|
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|
||||||
|
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
|
||||||
|
/**
|
||||||
|
* This is a stop gap measure until a different way of handling
|
||||||
|
* the closing of cases is worked out. Currently, remote events
|
||||||
|
* may be received for a case that is already closed.
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
Case.getCurrentCaseThrows();
|
||||||
|
refresh(false);
|
||||||
|
} catch (NoCurrentCaseException notUsed) {
|
||||||
|
/**
|
||||||
|
* Case is closed, do nothing.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addNotify() {
|
||||||
|
refreshThrottler.registerForIngestModuleEvents();
|
||||||
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
||||||
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void removeNotify() {
|
||||||
|
refreshThrottler.unregisterEventListener();
|
||||||
|
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||||
|
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
|
typeNodeMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean createKeys(List<TypeNodeKey> list) {
|
||||||
|
try {
|
||||||
|
// Get all types in use
|
||||||
|
SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
|
||||||
|
List<BlackboardArtifact.Type> types = (this.filteringDSObjId > 0)
|
||||||
|
? skCase.getBlackboard().getArtifactTypesInUse(this.filteringDSObjId)
|
||||||
|
: skCase.getArtifactTypesInUse();
|
||||||
|
|
||||||
|
List<TypeNodeKey> allKeysSorted = types.stream()
|
||||||
|
// filter types by category and ensure they are not in the list of ignored types
|
||||||
|
.filter(tp -> category.equals(tp.getCategory()) && !IGNORED_TYPES.contains(tp))
|
||||||
|
.map(tp -> {
|
||||||
|
// if typeNodeMap already contains key, update the relevant node and return the node
|
||||||
|
if (typeNodeMap.containsKey(tp)) {
|
||||||
|
TypeNodeKey typeKey = typeNodeMap.get(tp);
|
||||||
|
typeKey.getNode().updateDisplayName();
|
||||||
|
return typeKey;
|
||||||
|
} else {
|
||||||
|
// if key is not in map, create the type key and add to map
|
||||||
|
TypeNodeKey newTypeKey = getTypeKey(tp, skCase, filteringDSObjId);
|
||||||
|
for (BlackboardArtifact.Type recordType : newTypeKey.getApplicableTypes()) {
|
||||||
|
typeNodeMap.put(recordType, newTypeKey);
|
||||||
|
}
|
||||||
|
return newTypeKey;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// ensure record is returned
|
||||||
|
.filter(record -> record != null)
|
||||||
|
// there are potentially multiple types that apply to the same node (i.e. Interesting Files / Artifacts)
|
||||||
|
// ensure the keys are distinct
|
||||||
|
.distinct()
|
||||||
|
// sort by display name
|
||||||
|
.sorted((a, b) -> {
|
||||||
|
String aSafe = (a.getNode() == null || a.getNode().getDisplayName() == null) ? "" : a.getNode().getDisplayName();
|
||||||
|
String bSafe = (b.getNode() == null || b.getNode().getDisplayName() == null) ? "" : b.getNode().getDisplayName();
|
||||||
|
return aSafe.compareToIgnoreCase(bSafe);
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
list.addAll(allKeysSorted);
|
||||||
|
|
||||||
|
} catch (NoCurrentCaseException ex) {
|
||||||
|
logger.log(Level.WARNING, "Trying to access case when no case is open.", ex); //NON-NLS
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Error getting list of artifacts in use: " + ex.getLocalizedMessage()); //NON-NLS
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Node createNodeForKey(TypeNodeKey key) {
|
||||||
|
return key.getNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refresh() {
|
||||||
|
refresh(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRefreshRequired(PropertyChangeEvent evt) {
|
||||||
|
String eventType = evt.getPropertyName();
|
||||||
|
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
|
||||||
|
/**
|
||||||
|
* This is a stop gap measure until a different way of handling
|
||||||
|
* the closing of cases is worked out. Currently, remote events
|
||||||
|
* may be received for a case that is already closed.
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
Case.getCurrentCaseThrows();
|
||||||
|
/**
|
||||||
|
* Due to some unresolved issues with how cases are closed,
|
||||||
|
* it is possible for the event to have a null oldValue if
|
||||||
|
* the event is a remote event.
|
||||||
|
*/
|
||||||
|
final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue();
|
||||||
|
if (null != event && category.equals(event.getBlackboardArtifactType().getCategory())
|
||||||
|
&& !(IGNORED_TYPES.contains(event.getBlackboardArtifactType()))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (NoCurrentCaseException notUsed) {
|
||||||
|
/**
|
||||||
|
* Case is closed, do nothing.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class for type(s) nodes. This class allows for displaying a
|
||||||
|
* count artifacts with the type(s) associated with this node.
|
||||||
|
*/
|
||||||
|
public static abstract class UpdatableCountTypeNode extends DisplayableItemNode {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(UpdatableCountTypeNode.class.getName());
|
||||||
|
|
||||||
|
private final Set<BlackboardArtifact.Type> types;
|
||||||
|
private final long filteringDSObjId;
|
||||||
|
private long childCount = 0;
|
||||||
|
private final String baseName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param children The Children to associated with this node.
|
||||||
|
* @param lookup The Lookup to use with this name.
|
||||||
|
* @param baseName The display name. The Node.displayName will
|
||||||
|
* be of format "[baseName] ([count])".
|
||||||
|
* @param filteringDSObjId The data source object id to use for
|
||||||
|
* filtering. If id is less than or equal to 0,
|
||||||
|
* no filtering will occur.
|
||||||
|
* @param types The types associated with this type node.
|
||||||
|
*/
|
||||||
|
public UpdatableCountTypeNode(Children children, Lookup lookup, String baseName,
|
||||||
|
long filteringDSObjId, BlackboardArtifact.Type... types) {
|
||||||
|
|
||||||
|
super(children, lookup);
|
||||||
|
this.types = Stream.of(types).collect(Collectors.toSet());
|
||||||
|
this.filteringDSObjId = filteringDSObjId;
|
||||||
|
this.baseName = baseName;
|
||||||
|
updateDisplayName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the count of artifacts associated with these type(s).
|
||||||
|
*
|
||||||
|
* @return The count of artifacts associated with these type(s).
|
||||||
|
*/
|
||||||
|
protected long getChildCount() {
|
||||||
|
return this.childCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the count to be displayed from the case.
|
||||||
|
*
|
||||||
|
* @param skCase The relevant SleuthkitCase.
|
||||||
|
*
|
||||||
|
* @return The count to be displayed.
|
||||||
|
*
|
||||||
|
* @throws TskCoreException
|
||||||
|
*/
|
||||||
|
protected long fetchChildCount(SleuthkitCase skCase) throws TskCoreException {
|
||||||
|
int count = 0;
|
||||||
|
for (BlackboardArtifact.Type type : this.types) {
|
||||||
|
if (filteringDSObjId > 0) {
|
||||||
|
count += skCase.getBlackboard().getArtifactsCount(type.getTypeID(), filteringDSObjId);
|
||||||
|
} else {
|
||||||
|
count += skCase.getBlackboardArtifactsTypeCount(type.getTypeID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When this method is called, the count to be displayed will be
|
||||||
|
* updated.
|
||||||
|
*/
|
||||||
|
void updateDisplayName() {
|
||||||
|
try {
|
||||||
|
SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
|
||||||
|
this.childCount = fetchChildCount(skCase);
|
||||||
|
} catch (NoCurrentCaseException ex) {
|
||||||
|
logger.log(Level.WARNING, "Error fetching data when case closed.", ex);
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
logger.log(Level.WARNING, "Error getting child count", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
super.setDisplayName(this.baseName + " \u200E(\u200E" + this.childCount + ")\u200E");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default node encapsulating a blackboard artifact type. This is used on
|
||||||
|
* the left-hand navigation side of the Autopsy UI as the parent node for
|
||||||
|
* all of the artifacts of a given type. Its children will be
|
||||||
|
* BlackboardArtifactNode objects.
|
||||||
|
*/
|
||||||
|
static class TypeNode extends UpdatableCountTypeNode {
|
||||||
|
|
||||||
|
private final BlackboardArtifact.Type type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param type The blackboard artifact type for this node.
|
||||||
|
* @param filteringDSObjId The data source object id to use for
|
||||||
|
* filtering. If id is less than or equal to 0,
|
||||||
|
* no filtering will occur.
|
||||||
|
*/
|
||||||
|
TypeNode(BlackboardArtifact.Type type, long filteringDSObjId) {
|
||||||
|
super(Children.create(new ArtifactFactory(type, filteringDSObjId), true),
|
||||||
|
Lookups.singleton(type.getDisplayName()),
|
||||||
|
type.getDisplayName(),
|
||||||
|
filteringDSObjId,
|
||||||
|
type);
|
||||||
|
|
||||||
|
super.setName(type.getTypeName());
|
||||||
|
this.type = type;
|
||||||
|
String iconPath = IconsUtil.getIconFilePath(type.getTypeID());
|
||||||
|
setIconBaseWithExtension(iconPath != null && iconPath.charAt(0) == '/' ? iconPath.substring(1) : iconPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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(), "ArtifactTypeNode.createSheet.artType.name"),
|
||||||
|
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.artType.displayName"),
|
||||||
|
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.artType.desc"),
|
||||||
|
type.getDisplayName()));
|
||||||
|
|
||||||
|
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.childCnt.name"),
|
||||||
|
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.childCnt.displayName"),
|
||||||
|
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.childCnt.desc"),
|
||||||
|
getChildCount()));
|
||||||
|
|
||||||
|
return sheet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
|
||||||
|
return visitor.visit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeafTypeNode() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getItemType() {
|
||||||
|
return getClass().getName() + type.getDisplayName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates children for a given artifact type
|
||||||
|
*/
|
||||||
|
private static class ArtifactFactory extends BaseChildFactory<BlackboardArtifact> implements RefreshThrottler.Refresher {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(ArtifactFactory.class.getName());
|
||||||
|
private final BlackboardArtifact.Type type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RefreshThrottler is used to limit the number of refreshes performed
|
||||||
|
* when CONTENT_CHANGED and DATA_ADDED ingest module events are
|
||||||
|
* received.
|
||||||
|
*/
|
||||||
|
private final RefreshThrottler refreshThrottler = new RefreshThrottler(this);
|
||||||
|
private final long filteringDSObjId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param type The blackboard artifact type for this node.
|
||||||
|
* @param filteringDSObjId The data source object id to use for
|
||||||
|
* filtering. If id is less than or equal to 0,
|
||||||
|
* no filtering will occur.
|
||||||
|
*/
|
||||||
|
ArtifactFactory(BlackboardArtifact.Type type, long filteringDSObjId) {
|
||||||
|
super(type.getTypeName());
|
||||||
|
this.type = type;
|
||||||
|
this.filteringDSObjId = filteringDSObjId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
|
||||||
|
String eventType = evt.getPropertyName();
|
||||||
|
if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|
||||||
|
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
|
||||||
|
/**
|
||||||
|
* Checking for a current case is a stop gap measure until a
|
||||||
|
* different way of handling the closing of cases is worked out.
|
||||||
|
* Currently, remote events may be received for a case that is
|
||||||
|
* already closed.
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
Case.getCurrentCaseThrows();
|
||||||
|
refresh(false);
|
||||||
|
} catch (NoCurrentCaseException notUsed) {
|
||||||
|
/**
|
||||||
|
* Case is closed, do nothing.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onAdd() {
|
||||||
|
refreshThrottler.registerForIngestModuleEvents();
|
||||||
|
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRemove() {
|
||||||
|
refreshThrottler.unregisterEventListener();
|
||||||
|
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Node createNodeForKey(BlackboardArtifact key) {
|
||||||
|
return new BlackboardArtifactNode(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<BlackboardArtifact> makeKeys() {
|
||||||
|
try {
|
||||||
|
List<BlackboardArtifact> arts;
|
||||||
|
arts = (filteringDSObjId > 0)
|
||||||
|
? Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifacts(type.getTypeID(), filteringDSObjId)
|
||||||
|
: Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifacts(type.getTypeID());
|
||||||
|
|
||||||
|
for (BlackboardArtifact art : arts) {
|
||||||
|
//Cache attributes while we are off the EDT.
|
||||||
|
//See JIRA-5969
|
||||||
|
art.getAttributes();
|
||||||
|
}
|
||||||
|
return arts;
|
||||||
|
} catch (NoCurrentCaseException ex) {
|
||||||
|
logger.log(Level.WARNING, "Trying to access case when no case is open.", ex); //NON-NLS
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Couldn't get blackboard artifacts from database", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refresh() {
|
||||||
|
refresh(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRefreshRequired(PropertyChangeEvent evt) {
|
||||||
|
String eventType = evt.getPropertyName();
|
||||||
|
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checking for a current case is a stop gap measure until a
|
||||||
|
* different way of handling the closing of cases is worked out.
|
||||||
|
* Currently, remote events may be received for a case that is
|
||||||
|
* already closed.
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
Case.getCurrentCaseThrows();
|
||||||
|
/**
|
||||||
|
* Even with the check above, it is still possible that the
|
||||||
|
* case will be closed in a different thread before this
|
||||||
|
* code executes. If that happens, it is possible for the
|
||||||
|
* event to have a null oldValue.
|
||||||
|
*/
|
||||||
|
final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue();
|
||||||
|
if (null != event && event.getBlackboardArtifactType().equals(type)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (NoCurrentCaseException notUsed) {
|
||||||
|
/**
|
||||||
|
* Case is closed, do nothing.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -53,8 +53,6 @@ public interface AutopsyItemVisitor<T> {
|
|||||||
|
|
||||||
T visit(FileSize.FileSizeFilter fsf);
|
T visit(FileSize.FileSizeFilter fsf);
|
||||||
|
|
||||||
T visit(ExtractedContent ec);
|
|
||||||
|
|
||||||
T visit(KeywordHits kh);
|
T visit(KeywordHits kh);
|
||||||
|
|
||||||
T visit(HashsetHits hh);
|
T visit(HashsetHits hh);
|
||||||
@ -63,8 +61,6 @@ public interface AutopsyItemVisitor<T> {
|
|||||||
|
|
||||||
T visit(InterestingHits ih);
|
T visit(InterestingHits ih);
|
||||||
|
|
||||||
T visit(Results r);
|
|
||||||
|
|
||||||
T visit(Tags tagsNodeKey);
|
T visit(Tags tagsNodeKey);
|
||||||
|
|
||||||
T visit(Reports reportsItem);
|
T visit(Reports reportsItem);
|
||||||
@ -85,15 +81,15 @@ public interface AutopsyItemVisitor<T> {
|
|||||||
|
|
||||||
T visit(DataSourcesByType aThis);
|
T visit(DataSourcesByType aThis);
|
||||||
|
|
||||||
|
T visit(AnalysisResults aThis);
|
||||||
|
|
||||||
|
T visit(DataArtifacts aThis);
|
||||||
|
|
||||||
|
|
||||||
static abstract public class Default<T> implements AutopsyItemVisitor<T> {
|
static abstract public class Default<T> implements AutopsyItemVisitor<T> {
|
||||||
|
|
||||||
protected abstract T defaultVisit(AutopsyVisitableItem ec);
|
protected abstract T defaultVisit(AutopsyVisitableItem ec);
|
||||||
|
|
||||||
@Override
|
|
||||||
public T visit(ExtractedContent ec) {
|
|
||||||
return defaultVisit(ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T visit(FileTypesByExtension sf) {
|
public T visit(FileTypesByExtension sf) {
|
||||||
return defaultVisit(sf);
|
return defaultVisit(sf);
|
||||||
@ -199,11 +195,6 @@ public interface AutopsyItemVisitor<T> {
|
|||||||
return defaultVisit(personGrouping);
|
return defaultVisit(personGrouping);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public T visit(Results r) {
|
|
||||||
return defaultVisit(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T visit(FileTypes ft) {
|
public T visit(FileTypes ft) {
|
||||||
return defaultVisit(ft);
|
return defaultVisit(ft);
|
||||||
@ -233,5 +224,15 @@ public interface AutopsyItemVisitor<T> {
|
|||||||
public T visit(DataSourcesByType dataSourceHosts) {
|
public T visit(DataSourcesByType dataSourceHosts) {
|
||||||
return defaultVisit(dataSourceHosts);
|
return defaultVisit(dataSourceHosts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T visit(DataArtifacts aThis) {
|
||||||
|
return defaultVisit(aThis);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T visit(AnalysisResults aThis) {
|
||||||
|
return defaultVisit(aThis);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,24 +111,27 @@ public final class AutopsyTreeChildFactory extends ChildFactory.Detachable<Objec
|
|||||||
if (CollectionUtils.isNotEmpty(personManager.getHostsForPerson(null))) {
|
if (CollectionUtils.isNotEmpty(personManager.getHostsForPerson(null))) {
|
||||||
list.add(new PersonGrouping(null));
|
list.add(new PersonGrouping(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
} else {
|
} else {
|
||||||
// otherwise, just show host level
|
// otherwise, just show host level
|
||||||
tskCase.getHostManager().getAllHosts().stream()
|
tskCase.getHostManager().getAllHosts().stream()
|
||||||
.map(HostGrouping::new)
|
.map(HostGrouping::new)
|
||||||
.sorted()
|
.sorted()
|
||||||
.forEach(list::add);
|
.forEach(list::add);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
list.add(new Reports());
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
// data source by type view
|
// data source by type view
|
||||||
List<AutopsyVisitableItem> keys = new ArrayList<>(Arrays.asList(
|
List<AutopsyVisitableItem> keys = new ArrayList<>(Arrays.asList(
|
||||||
new DataSourcesByType(),
|
new DataSourcesByType(),
|
||||||
new Views(tskCase),
|
new Views(Case.getCurrentCaseThrows().getSleuthkitCase()),
|
||||||
new Results(tskCase),
|
new DataArtifacts(),
|
||||||
|
new AnalysisResults(),
|
||||||
|
new OsAccounts(Case.getCurrentCaseThrows().getSleuthkitCase()),
|
||||||
new Tags(),
|
new Tags(),
|
||||||
new Reports()));
|
new Reports()
|
||||||
|
));
|
||||||
|
|
||||||
list.addAll(keys);
|
list.addAll(keys);
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,7 @@ TagNameNode.createSheet.name.displayName=Name
|
|||||||
TagsNode.displayName.text=Tags
|
TagsNode.displayName.text=Tags
|
||||||
TagsNode.createSheet.name.name=Name
|
TagsNode.createSheet.name.name=Name
|
||||||
TagsNode.createSheet.name.displayName=Name
|
TagsNode.createSheet.name.displayName=Name
|
||||||
ViewsNode.name.text=Views
|
ViewsNode.name.text=File Views
|
||||||
ViewsNode.createSheet.name.name=Name
|
ViewsNode.createSheet.name.name=Name
|
||||||
ViewsNode.createSheet.name.displayName=Name
|
ViewsNode.createSheet.name.displayName=Name
|
||||||
ViewsNode.createSheet.name.desc=no description
|
ViewsNode.createSheet.name.desc=no description
|
||||||
|
@ -39,6 +39,7 @@ AbstractAbstractFileNode.useridColLbl=UserID
|
|||||||
AbstractContentNode.nodescription=no description
|
AbstractContentNode.nodescription=no description
|
||||||
AbstractContentNode.valueLoading=value loading
|
AbstractContentNode.valueLoading=value loading
|
||||||
AbstractFsContentNode.noDesc.text=no description
|
AbstractFsContentNode.noDesc.text=no description
|
||||||
|
AnalysisResults_name=Analysis Results
|
||||||
ArtifactStringContent.attrsTableHeader.sources=Source(s)
|
ArtifactStringContent.attrsTableHeader.sources=Source(s)
|
||||||
ArtifactStringContent.attrsTableHeader.type=Type
|
ArtifactStringContent.attrsTableHeader.type=Type
|
||||||
ArtifactStringContent.attrsTableHeader.value=Value
|
ArtifactStringContent.attrsTableHeader.value=Value
|
||||||
@ -93,6 +94,7 @@ ContentTagNode.createSheet.artifactMD5.displayName=MD5 Hash
|
|||||||
ContentTagNode.createSheet.artifactMD5.name=MD5 Hash
|
ContentTagNode.createSheet.artifactMD5.name=MD5 Hash
|
||||||
ContentTagNode.createSheet.origFileName=Original Name
|
ContentTagNode.createSheet.origFileName=Original Name
|
||||||
ContentTagNode.createSheet.userName.text=User Name
|
ContentTagNode.createSheet.userName.text=User Name
|
||||||
|
DataArtifacts_name=Data Artifacts
|
||||||
DataSourcesHostsNode_name=Data Sources
|
DataSourcesHostsNode_name=Data Sources
|
||||||
DeletedContent.allDelFilter.text=All
|
DeletedContent.allDelFilter.text=All
|
||||||
DeletedContent.createSheet.filterType.desc=no description
|
DeletedContent.createSheet.filterType.desc=no description
|
||||||
@ -358,10 +360,6 @@ ReportNode.reportNameProperty.name=Report Name
|
|||||||
ReportNode.reportNameProperty.displayName=Report Name
|
ReportNode.reportNameProperty.displayName=Report Name
|
||||||
ReportNode.reportNameProperty.desc=Name of the report
|
ReportNode.reportNameProperty.desc=Name of the report
|
||||||
ReportsListNode.displayName=Reports
|
ReportsListNode.displayName=Reports
|
||||||
ResultsNode.createSheet.name.desc=no description
|
|
||||||
ResultsNode.createSheet.name.displayName=Name
|
|
||||||
ResultsNode.createSheet.name.name=Name
|
|
||||||
ResultsNode.name.text=Results
|
|
||||||
SlackFileNode.getActions.viewInNewWin.text=View in New Window
|
SlackFileNode.getActions.viewInNewWin.text=View in New Window
|
||||||
SlackFileNode.getActions.viewFileInDir.text=View File in Directory
|
SlackFileNode.getActions.viewFileInDir.text=View File in Directory
|
||||||
SpecialDirectoryNode.getActions.viewInNewWin.text=View in New Window
|
SpecialDirectoryNode.getActions.viewInNewWin.text=View in New Window
|
||||||
@ -380,7 +378,7 @@ UnsupportedContentNode.createSheet.name.desc=no description
|
|||||||
UnsupportedContentNode.createSheet.name.displayName=Name
|
UnsupportedContentNode.createSheet.name.displayName=Name
|
||||||
UnsupportedContentNode.createSheet.name.name=Name
|
UnsupportedContentNode.createSheet.name.name=Name
|
||||||
UnsupportedContentNode.displayName=Unsupported Content
|
UnsupportedContentNode.displayName=Unsupported Content
|
||||||
ViewsNode.name.text=Views
|
ViewsNode.name.text=File Views
|
||||||
ViewsNode.createSheet.name.name=Name
|
ViewsNode.createSheet.name.name=Name
|
||||||
ViewsNode.createSheet.name.displayName=Name
|
ViewsNode.createSheet.name.displayName=Name
|
||||||
ViewsNode.createSheet.name.desc=no description
|
ViewsNode.createSheet.name.desc=no description
|
||||||
|
95
Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java
Normal file
95
Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2021 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.datamodel;
|
||||||
|
|
||||||
|
import org.openide.nodes.Children;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analysis Results node support.
|
||||||
|
*/
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"DataArtifacts_name=Data Artifacts",})
|
||||||
|
public class DataArtifacts implements AutopsyVisitableItem {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of this node that is the key in the children object.
|
||||||
|
*
|
||||||
|
* @return The name of this node that is the key in the children object.
|
||||||
|
*/
|
||||||
|
public static String getName() {
|
||||||
|
return Bundle.DataArtifacts_name();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parent node of all data artifacts.
|
||||||
|
*/
|
||||||
|
static class RootNode extends Artifacts.BaseArtifactNode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param filteringDSObjId The data source object id for which results
|
||||||
|
* should be filtered. If no filtering should
|
||||||
|
* occur, this number should be less than or
|
||||||
|
* equal to 0.
|
||||||
|
*/
|
||||||
|
RootNode(long filteringDSObjId) {
|
||||||
|
super(Children.create(new Artifacts.TypeFactory(BlackboardArtifact.Category.DATA_ARTIFACT, filteringDSObjId), true),
|
||||||
|
"org/sleuthkit/autopsy/images/extracted_content.png",
|
||||||
|
DataArtifacts.getName(),
|
||||||
|
DataArtifacts.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final long datasourceObjId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*/
|
||||||
|
public DataArtifacts() {
|
||||||
|
this(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main constructor.
|
||||||
|
*
|
||||||
|
* @param dsObjId The data source object id.
|
||||||
|
*/
|
||||||
|
public DataArtifacts(long dsObjId) {
|
||||||
|
this.datasourceObjId = dsObjId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T accept(AutopsyItemVisitor<T> visitor) {
|
||||||
|
return visitor.visit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not there is a data source object for which results
|
||||||
|
* should be filtered.
|
||||||
|
*
|
||||||
|
* @return Whether or not there is a data source object for which results
|
||||||
|
* should be filtered.
|
||||||
|
*/
|
||||||
|
Long getFilteringDataSourceObjId() {
|
||||||
|
return datasourceObjId;
|
||||||
|
}
|
||||||
|
}
|
@ -30,24 +30,23 @@ import org.sleuthkit.datamodel.DataSource;
|
|||||||
import org.sleuthkit.datamodel.Image;
|
import org.sleuthkit.datamodel.Image;
|
||||||
import org.sleuthkit.datamodel.LocalFilesDataSource;
|
import org.sleuthkit.datamodel.LocalFilesDataSource;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data source grouping node - an optional grouping node in the data tree view
|
* Data source grouping node - an optional grouping node in the data tree view
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class DataSourceGroupingNode extends DisplayableItemNode {
|
class DataSourceGroupingNode extends DisplayableItemNode {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(DataSourceGroupingNode.class.getName());
|
private static final Logger logger = Logger.getLogger(DataSourceGroupingNode.class.getName());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a data source grouping node for the given data source.
|
* Creates a data source grouping node for the given data source.
|
||||||
*
|
*
|
||||||
* @param dataSource specifies the data source
|
* @param dataSource specifies the data source
|
||||||
*/
|
*/
|
||||||
DataSourceGroupingNode(DataSource dataSource) {
|
DataSourceGroupingNode(DataSource dataSource) {
|
||||||
|
|
||||||
super (Optional.ofNullable(createDSGroupingNodeChildren(dataSource))
|
super(Optional.ofNullable(createDSGroupingNodeChildren(dataSource))
|
||||||
.orElse(new RootContentChildren(Arrays.asList(Collections.EMPTY_LIST))),
|
.orElse(new RootContentChildren(Arrays.asList(Collections.EMPTY_LIST))),
|
||||||
Lookups.singleton(dataSource));
|
Lookups.singleton(dataSource));
|
||||||
|
|
||||||
if (dataSource instanceof Image) {
|
if (dataSource instanceof Image) {
|
||||||
@ -70,7 +69,7 @@ class DataSourceGroupingNode extends DisplayableItemNode {
|
|||||||
public boolean isLeafTypeNode() {
|
public boolean isLeafTypeNode() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RootContentChildren createDSGroupingNodeChildren(DataSource dataSource) {
|
private static RootContentChildren createDSGroupingNodeChildren(DataSource dataSource) {
|
||||||
|
|
||||||
long dsObjId = dataSource.getId();
|
long dsObjId = dataSource.getId();
|
||||||
@ -78,11 +77,13 @@ class DataSourceGroupingNode extends DisplayableItemNode {
|
|||||||
return new RootContentChildren(Arrays.asList(
|
return new RootContentChildren(Arrays.asList(
|
||||||
new DataSources(dsObjId),
|
new DataSources(dsObjId),
|
||||||
new Views(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId),
|
new Views(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId),
|
||||||
new Results(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId),
|
new DataArtifacts(dsObjId),
|
||||||
new Tags(dsObjId) )
|
new AnalysisResults(dsObjId),
|
||||||
|
new OsAccounts(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId),
|
||||||
);
|
new Tags(dsObjId),
|
||||||
|
new Reports()
|
||||||
|
));
|
||||||
|
|
||||||
} catch (NoCurrentCaseException ex) {
|
} catch (NoCurrentCaseException ex) {
|
||||||
logger.log(Level.SEVERE, "Error getting open case.", ex); //NON-NLS
|
logger.log(Level.SEVERE, "Error getting open case.", ex); //NON-NLS
|
||||||
return null;
|
return null;
|
||||||
|
@ -88,16 +88,11 @@ public interface DisplayableItemNodeVisitor<T> {
|
|||||||
|
|
||||||
T visit(RecentFilesFilterNode rffn);
|
T visit(RecentFilesFilterNode rffn);
|
||||||
|
|
||||||
/*
|
|
||||||
* Extracted Results Area
|
|
||||||
*/
|
|
||||||
T visit(ResultsNode rn);
|
|
||||||
|
|
||||||
T visit(BlackboardArtifactNode ban);
|
T visit(BlackboardArtifactNode ban);
|
||||||
|
|
||||||
T visit(ExtractedContent.TypeNode atn);
|
T visit(Artifacts.TypeNode atn);
|
||||||
|
|
||||||
T visit(ExtractedContent.RootNode ecn);
|
T visit(Artifacts.BaseArtifactNode ecn);
|
||||||
|
|
||||||
T visit(KeywordHits.RootNode khrn);
|
T visit(KeywordHits.RootNode khrn);
|
||||||
|
|
||||||
@ -301,12 +296,12 @@ public interface DisplayableItemNodeVisitor<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T visit(ExtractedContent.TypeNode atn) {
|
public T visit(Artifacts.TypeNode atn) {
|
||||||
return defaultVisit(atn);
|
return defaultVisit(atn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T visit(ExtractedContent.RootNode ecn) {
|
public T visit(Artifacts.BaseArtifactNode ecn) {
|
||||||
return defaultVisit(ecn);
|
return defaultVisit(ecn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,11 +400,6 @@ public interface DisplayableItemNodeVisitor<T> {
|
|||||||
return defaultVisit(dataSourceGroupingNode);
|
return defaultVisit(dataSourceGroupingNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public T visit(ResultsNode rn) {
|
|
||||||
return defaultVisit(rn);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T visit(FileTypesNode ft) {
|
public T visit(FileTypesNode ft) {
|
||||||
return defaultVisit(ft);
|
return defaultVisit(ft);
|
||||||
|
@ -32,7 +32,6 @@ import java.util.Observable;
|
|||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
|
||||||
import org.openide.nodes.ChildFactory;
|
import org.openide.nodes.ChildFactory;
|
||||||
import org.openide.nodes.Children;
|
import org.openide.nodes.Children;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
@ -45,10 +44,12 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
|||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
|
import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_EMAIL_MSG;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
|
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Support for TSK_EMAIL_MSG nodes and displaying emails in the directory tree.
|
* Support for TSK_EMAIL_MSG nodes and displaying emails in the directory tree.
|
||||||
@ -58,8 +59,7 @@ import org.sleuthkit.datamodel.TskCoreException;
|
|||||||
*/
|
*/
|
||||||
public class EmailExtracted implements AutopsyVisitableItem {
|
public class EmailExtracted implements AutopsyVisitableItem {
|
||||||
|
|
||||||
private static final String LABEL_NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getLabel();
|
private static final String LABEL_NAME = BlackboardArtifact.Type.TSK_EMAIL_MSG.getTypeName();
|
||||||
private static final String DISPLAY_NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getDisplayName();
|
|
||||||
private static final Logger logger = Logger.getLogger(EmailExtracted.class.getName());
|
private static final Logger logger = Logger.getLogger(EmailExtracted.class.getName());
|
||||||
private static final String MAIL_ACCOUNT = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailAccount.text");
|
private static final String MAIL_ACCOUNT = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailAccount.text");
|
||||||
private static final String MAIL_FOLDER = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailFolder.text");
|
private static final String MAIL_FOLDER = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailFolder.text");
|
||||||
@ -147,7 +147,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public void update() {
|
public void update() {
|
||||||
// clear cache if no case
|
// clear cache if no case
|
||||||
if (skCase == null) {
|
if (skCase == null) {
|
||||||
synchronized (accounts) {
|
synchronized (accounts) {
|
||||||
@ -157,22 +157,22 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get artifact id and path (if present) of all email artifacts
|
// get artifact id and path (if present) of all email artifacts
|
||||||
int emailArtifactId = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID();
|
int emailArtifactId = BlackboardArtifact.Type.TSK_EMAIL_MSG.getTypeID();
|
||||||
int pathAttrId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID();
|
int pathAttrId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID();
|
||||||
|
|
||||||
String query = "SELECT \n" +
|
String query = "SELECT \n"
|
||||||
" art.artifact_id AS artifact_id,\n" +
|
+ " art.artifact_id AS artifact_id,\n"
|
||||||
" (SELECT value_text FROM blackboard_attributes attr\n" +
|
+ " (SELECT value_text FROM blackboard_attributes attr\n"
|
||||||
" WHERE attr.artifact_id = art.artifact_id AND attr.attribute_type_id = " + pathAttrId + "\n" +
|
+ " WHERE attr.artifact_id = art.artifact_id AND attr.attribute_type_id = " + pathAttrId + "\n"
|
||||||
" LIMIT 1) AS value_text\n" +
|
+ " LIMIT 1) AS value_text\n"
|
||||||
"FROM \n" +
|
+ "FROM \n"
|
||||||
" blackboard_artifacts art\n" +
|
+ " blackboard_artifacts art\n"
|
||||||
" WHERE art.artifact_type_id = " + emailArtifactId + "\n" +
|
+ " WHERE art.artifact_type_id = " + emailArtifactId + "\n"
|
||||||
((filteringDSObjId > 0) ? " AND art.data_source_obj_id = " + filteringDSObjId : "");
|
+ ((filteringDSObjId > 0) ? " AND art.data_source_obj_id = " + filteringDSObjId : "");
|
||||||
|
|
||||||
// form hierarchy of account -> folder -> account id
|
// form hierarchy of account -> folder -> account id
|
||||||
Map<String, Map<String, List<Long>>> newMapping = new HashMap<>();
|
Map<String, Map<String, List<Long>>> newMapping = new HashMap<>();
|
||||||
|
|
||||||
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
|
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
|
||||||
ResultSet resultSet = dbQuery.getResultSet();
|
ResultSet resultSet = dbQuery.getResultSet();
|
||||||
while (resultSet.next()) {
|
while (resultSet.next()) {
|
||||||
@ -180,7 +180,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
|||||||
Map<String, String> accountFolderMap = parsePath(resultSet.getString("value_text"));
|
Map<String, String> accountFolderMap = parsePath(resultSet.getString("value_text"));
|
||||||
String account = accountFolderMap.get(MAIL_ACCOUNT);
|
String account = accountFolderMap.get(MAIL_ACCOUNT);
|
||||||
String folder = accountFolderMap.get(MAIL_FOLDER);
|
String folder = accountFolderMap.get(MAIL_FOLDER);
|
||||||
|
|
||||||
Map<String, List<Long>> folders = newMapping.computeIfAbsent(account, (str) -> new LinkedHashMap<>());
|
Map<String, List<Long>> folders = newMapping.computeIfAbsent(account, (str) -> new LinkedHashMap<>());
|
||||||
List<Long> messages = folders.computeIfAbsent(folder, (str) -> new ArrayList<>());
|
List<Long> messages = folders.computeIfAbsent(folder, (str) -> new ArrayList<>());
|
||||||
messages.add(artifactId);
|
messages.add(artifactId);
|
||||||
@ -188,29 +188,31 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
|||||||
} catch (TskCoreException | SQLException ex) {
|
} catch (TskCoreException | SQLException ex) {
|
||||||
logger.log(Level.WARNING, "Cannot initialize email extraction: ", ex); //NON-NLS
|
logger.log(Level.WARNING, "Cannot initialize email extraction: ", ex); //NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
synchronized (accounts) {
|
synchronized (accounts) {
|
||||||
accounts.clear();
|
accounts.clear();
|
||||||
accounts.putAll(newMapping);
|
accounts.putAll(newMapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
setChanged();
|
setChanged();
|
||||||
notifyObservers();
|
notifyObservers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mail root node grouping all mail accounts, supports account-> folder
|
* Mail root node grouping all mail accounts, supports account-> folder
|
||||||
* structure
|
* structure
|
||||||
*/
|
*/
|
||||||
public class RootNode extends DisplayableItemNode {
|
public class RootNode extends UpdatableCountTypeNode {
|
||||||
|
|
||||||
public RootNode() {
|
public RootNode() {
|
||||||
super(Children.create(new AccountFactory(), true), Lookups.singleton(DISPLAY_NAME));
|
super(Children.create(new AccountFactory(), true),
|
||||||
|
Lookups.singleton(TSK_EMAIL_MSG.getDisplayName()),
|
||||||
|
TSK_EMAIL_MSG.getDisplayName(),
|
||||||
|
filteringDSObjId,
|
||||||
|
TSK_EMAIL_MSG);
|
||||||
|
//super(Children.create(new AccountFactory(), true), Lookups.singleton(DISPLAY_NAME));
|
||||||
super.setName(LABEL_NAME);
|
super.setName(LABEL_NAME);
|
||||||
super.setDisplayName(DISPLAY_NAME);
|
|
||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/mail-icon-16.png"); //NON-NLS
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/mail-icon-16.png"); //NON-NLS
|
||||||
emailResults.update();
|
emailResults.update();
|
||||||
}
|
}
|
||||||
@ -277,7 +279,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
|||||||
* for the event to have a null oldValue.
|
* for the event to have a null oldValue.
|
||||||
*/
|
*/
|
||||||
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
||||||
if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) {
|
if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.Type.TSK_EMAIL_MSG.getTypeID()) {
|
||||||
emailResults.update();
|
emailResults.update();
|
||||||
}
|
}
|
||||||
} catch (NoCurrentCaseException notUsed) {
|
} catch (NoCurrentCaseException notUsed) {
|
||||||
|
@ -1,492 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2011-2020 Basis Technology Corp.
|
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.sleuthkit.autopsy.datamodel;
|
|
||||||
|
|
||||||
import java.beans.PropertyChangeEvent;
|
|
||||||
import java.beans.PropertyChangeListener;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import org.openide.nodes.ChildFactory;
|
|
||||||
import org.openide.nodes.Children;
|
|
||||||
import org.openide.nodes.Node;
|
|
||||||
import org.openide.nodes.Sheet;
|
|
||||||
import org.openide.util.NbBundle;
|
|
||||||
import org.openide.util.lookup.Lookups;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.utils.IconsUtil;
|
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
|
||||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
|
||||||
import org.sleuthkit.datamodel.Blackboard;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
|
||||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT;
|
|
||||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT;
|
|
||||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_TL_EVENT;
|
|
||||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_DATA_SOURCE_USAGE;
|
|
||||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG;
|
|
||||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO;
|
|
||||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT;
|
|
||||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT;
|
|
||||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT;
|
|
||||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT;
|
|
||||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE;
|
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
|
||||||
import org.sleuthkit.autopsy.guiutils.RefreshThrottler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parent of the "extracted content" artifacts to be displayed in the tree.
|
|
||||||
* Other artifacts are displayed under other more specific parents.
|
|
||||||
*/
|
|
||||||
public class ExtractedContent implements AutopsyVisitableItem {
|
|
||||||
|
|
||||||
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
|
|
||||||
public static final String NAME = NbBundle.getMessage(RootNode.class, "ExtractedContentNode.name.text");
|
|
||||||
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
|
|
||||||
private SleuthkitCase skCase; // set to null after case has been closed
|
|
||||||
private Blackboard blackboard;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs extracted content object
|
|
||||||
*
|
|
||||||
* @param skCase Case DB
|
|
||||||
*/
|
|
||||||
public ExtractedContent(SleuthkitCase skCase) {
|
|
||||||
this(skCase, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs extracted content object
|
|
||||||
*
|
|
||||||
* @param skCase Case DB
|
|
||||||
* @param objId Object id of the parent datasource
|
|
||||||
*/
|
|
||||||
public ExtractedContent(SleuthkitCase skCase, long objId) {
|
|
||||||
this.skCase = skCase;
|
|
||||||
this.filteringDSObjId = objId;
|
|
||||||
this.blackboard = skCase.getBlackboard();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T accept(AutopsyItemVisitor<T> visitor) {
|
|
||||||
return visitor.visit(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SleuthkitCase getSleuthkitCase() {
|
|
||||||
return skCase;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class RootNode extends DisplayableItemNode {
|
|
||||||
|
|
||||||
public RootNode(SleuthkitCase skCase) {
|
|
||||||
super(Children.create(new TypeFactory(), true), Lookups.singleton(NAME));
|
|
||||||
super.setName(NAME);
|
|
||||||
super.setDisplayName(NAME);
|
|
||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/extracted_content.png"); //NON-NLS
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLeafTypeNode() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T accept(DisplayableItemNodeVisitor<T> 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(), "ExtractedContentNode.createSheet.name.name"),
|
|
||||||
NbBundle.getMessage(this.getClass(), "ExtractedContentNode.createSheet.name.displayName"),
|
|
||||||
NbBundle.getMessage(this.getClass(), "ExtractedContentNode.createSheet.name.desc"),
|
|
||||||
NAME));
|
|
||||||
return sheet;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getItemType() {
|
|
||||||
return getClass().getName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the children for the ExtractedContent area of the results tree.
|
|
||||||
* This area has all of the blackboard artifacts that are not displayed in a
|
|
||||||
* more specific form elsewhere in the tree.
|
|
||||||
*/
|
|
||||||
private class TypeFactory extends ChildFactory.Detachable<BlackboardArtifact.Type> implements RefreshThrottler.Refresher {
|
|
||||||
|
|
||||||
private final ArrayList<BlackboardArtifact.Type> doNotShow = new ArrayList<>();
|
|
||||||
// maps the artifact type to its child node
|
|
||||||
private final HashMap<BlackboardArtifact.Type, TypeNode> typeNodeList = new HashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RefreshThrottler is used to limit the number of refreshes performed
|
|
||||||
* when CONTENT_CHANGED and DATA_ADDED ingest module events are
|
|
||||||
* received.
|
|
||||||
*/
|
|
||||||
private final RefreshThrottler refreshThrottler = new RefreshThrottler(this);
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
TypeFactory() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
// these are shown in other parts of the UI
|
|
||||||
doNotShow.add(new BlackboardArtifact.Type(TSK_GEN_INFO));
|
|
||||||
doNotShow.add(new BlackboardArtifact.Type(TSK_EMAIL_MSG));
|
|
||||||
doNotShow.add(new BlackboardArtifact.Type(TSK_HASHSET_HIT));
|
|
||||||
doNotShow.add(new BlackboardArtifact.Type(TSK_KEYWORD_HIT));
|
|
||||||
doNotShow.add(new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT));
|
|
||||||
doNotShow.add(new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT));
|
|
||||||
doNotShow.add(new BlackboardArtifact.Type(TSK_ACCOUNT));
|
|
||||||
doNotShow.add(new BlackboardArtifact.Type(TSK_DATA_SOURCE_USAGE));
|
|
||||||
doNotShow.add(new BlackboardArtifact.Type(TSK_DOWNLOAD_SOURCE));
|
|
||||||
doNotShow.add(new BlackboardArtifact.Type(TSK_TL_EVENT));
|
|
||||||
|
|
||||||
//This is not meant to be shown in the UI at all. It is more of a meta artifact.
|
|
||||||
doNotShow.add(new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT));
|
|
||||||
}
|
|
||||||
|
|
||||||
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
|
|
||||||
String eventType = evt.getPropertyName();
|
|
||||||
if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
|
|
||||||
// case was closed. Remove listeners so that we don't get called with a stale case handle
|
|
||||||
if (evt.getNewValue() == null) {
|
|
||||||
removeNotify();
|
|
||||||
skCase = null;
|
|
||||||
}
|
|
||||||
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|
|
||||||
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
|
|
||||||
/**
|
|
||||||
* This is a stop gap measure until a different way of handling
|
|
||||||
* the closing of cases is worked out. Currently, remote events
|
|
||||||
* may be received for a case that is already closed.
|
|
||||||
*/
|
|
||||||
try {
|
|
||||||
Case.getCurrentCaseThrows();
|
|
||||||
refresh(false);
|
|
||||||
} catch (NoCurrentCaseException notUsed) {
|
|
||||||
/**
|
|
||||||
* Case is closed, do nothing.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void addNotify() {
|
|
||||||
refreshThrottler.registerForIngestModuleEvents();
|
|
||||||
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
|
||||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void removeNotify() {
|
|
||||||
refreshThrottler.unregisterEventListener();
|
|
||||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
|
||||||
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
|
||||||
typeNodeList.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean createKeys(List<BlackboardArtifact.Type> list) {
|
|
||||||
if (skCase != null) {
|
|
||||||
try {
|
|
||||||
List<BlackboardArtifact.Type> types = (filteringDSObjId > 0)
|
|
||||||
? blackboard.getArtifactTypesInUse(filteringDSObjId)
|
|
||||||
: skCase.getArtifactTypesInUse();
|
|
||||||
|
|
||||||
types.removeAll(doNotShow);
|
|
||||||
Collections.sort(types,
|
|
||||||
new Comparator<BlackboardArtifact.Type>() {
|
|
||||||
@Override
|
|
||||||
public int compare(BlackboardArtifact.Type a, BlackboardArtifact.Type b) {
|
|
||||||
return a.getDisplayName().compareTo(b.getDisplayName());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
list.addAll(types);
|
|
||||||
|
|
||||||
// the create node method will get called only for new types
|
|
||||||
// refresh the counts if we already created them from a previous update
|
|
||||||
for (BlackboardArtifact.Type art : types) {
|
|
||||||
TypeNode node = typeNodeList.get(art);
|
|
||||||
if (node != null) {
|
|
||||||
node.updateDisplayName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
Logger.getLogger(TypeFactory.class.getName()).log(Level.SEVERE, "Error getting list of artifacts in use: " + ex.getLocalizedMessage()); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Node createNodeForKey(BlackboardArtifact.Type key) {
|
|
||||||
TypeNode node = new TypeNode(key);
|
|
||||||
typeNodeList.put(key, node);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void refresh() {
|
|
||||||
refresh(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRefreshRequired(PropertyChangeEvent evt) {
|
|
||||||
String eventType = evt.getPropertyName();
|
|
||||||
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
|
|
||||||
/**
|
|
||||||
* This is a stop gap measure until a different way of handling
|
|
||||||
* the closing of cases is worked out. Currently, remote events
|
|
||||||
* may be received for a case that is already closed.
|
|
||||||
*/
|
|
||||||
try {
|
|
||||||
Case.getCurrentCaseThrows();
|
|
||||||
/**
|
|
||||||
* Due to some unresolved issues with how cases are closed,
|
|
||||||
* it is possible for the event to have a null oldValue if
|
|
||||||
* the event is a remote event.
|
|
||||||
*/
|
|
||||||
final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue();
|
|
||||||
if (null != event && !(this.doNotShow.contains(event.getBlackboardArtifactType()))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (NoCurrentCaseException notUsed) {
|
|
||||||
/**
|
|
||||||
* Case is closed, do nothing.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Node encapsulating blackboard artifact type. This is used on the
|
|
||||||
* left-hand navigation side of the Autopsy UI as the parent node for all of
|
|
||||||
* the artifacts of a given type. Its children will be
|
|
||||||
* BlackboardArtifactNode objects.
|
|
||||||
*/
|
|
||||||
public class TypeNode extends DisplayableItemNode {
|
|
||||||
|
|
||||||
private final BlackboardArtifact.Type type;
|
|
||||||
private long childCount = 0;
|
|
||||||
|
|
||||||
TypeNode(BlackboardArtifact.Type type) {
|
|
||||||
super(Children.create(new ArtifactFactory(type), true), Lookups.singleton(type.getDisplayName()));
|
|
||||||
super.setName(type.getTypeName());
|
|
||||||
this.type = type;
|
|
||||||
String iconPath = IconsUtil.getIconFilePath(type.getTypeID());
|
|
||||||
setIconBaseWithExtension(iconPath != null && iconPath.charAt(0) == '/' ? iconPath.substring(1) : iconPath);
|
|
||||||
updateDisplayName();
|
|
||||||
}
|
|
||||||
|
|
||||||
final void updateDisplayName() {
|
|
||||||
if (skCase == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: This completely destroys our lazy-loading ideal
|
|
||||||
// a performance increase might be had by adding a
|
|
||||||
// "getBlackboardArtifactCount()" method to skCase
|
|
||||||
try {
|
|
||||||
this.childCount = (filteringDSObjId > 0)
|
|
||||||
? blackboard.getArtifactsCount(type.getTypeID(), filteringDSObjId)
|
|
||||||
: skCase.getBlackboardArtifactsTypeCount(type.getTypeID());
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
Logger.getLogger(TypeNode.class.getName())
|
|
||||||
.log(Level.WARNING, "Error getting child count", ex); //NON-NLS
|
|
||||||
}
|
|
||||||
super.setDisplayName(type.getDisplayName() + " \u200E(\u200E" + childCount + ")\u200E");
|
|
||||||
}
|
|
||||||
|
|
||||||
@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(), "ArtifactTypeNode.createSheet.artType.name"),
|
|
||||||
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.artType.displayName"),
|
|
||||||
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.artType.desc"),
|
|
||||||
type.getDisplayName()));
|
|
||||||
|
|
||||||
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.childCnt.name"),
|
|
||||||
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.childCnt.displayName"),
|
|
||||||
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.childCnt.desc"),
|
|
||||||
childCount));
|
|
||||||
|
|
||||||
return sheet;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
|
|
||||||
return visitor.visit(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLeafTypeNode() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getItemType() {
|
|
||||||
return getClass().getName() + type.getDisplayName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates children for a given artifact type
|
|
||||||
*/
|
|
||||||
private class ArtifactFactory extends BaseChildFactory<BlackboardArtifact> implements RefreshThrottler.Refresher {
|
|
||||||
|
|
||||||
private final BlackboardArtifact.Type type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RefreshThrottler is used to limit the number of refreshes performed
|
|
||||||
* when CONTENT_CHANGED and DATA_ADDED ingest module events are
|
|
||||||
* received.
|
|
||||||
*/
|
|
||||||
private final RefreshThrottler refreshThrottler = new RefreshThrottler(this);
|
|
||||||
|
|
||||||
ArtifactFactory(BlackboardArtifact.Type type) {
|
|
||||||
super(type.getTypeName());
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
|
|
||||||
String eventType = evt.getPropertyName();
|
|
||||||
if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|
|
||||||
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
|
|
||||||
/**
|
|
||||||
* Checking for a current case is a stop gap measure until a
|
|
||||||
* different way of handling the closing of cases is worked out.
|
|
||||||
* Currently, remote events may be received for a case that is
|
|
||||||
* already closed.
|
|
||||||
*/
|
|
||||||
try {
|
|
||||||
Case.getCurrentCaseThrows();
|
|
||||||
refresh(false);
|
|
||||||
} catch (NoCurrentCaseException notUsed) {
|
|
||||||
/**
|
|
||||||
* Case is closed, do nothing.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onAdd() {
|
|
||||||
refreshThrottler.registerForIngestModuleEvents();
|
|
||||||
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onRemove() {
|
|
||||||
refreshThrottler.unregisterEventListener();
|
|
||||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Node createNodeForKey(BlackboardArtifact key) {
|
|
||||||
return new BlackboardArtifactNode(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<BlackboardArtifact> makeKeys() {
|
|
||||||
if (skCase != null) {
|
|
||||||
try {
|
|
||||||
List<BlackboardArtifact> arts;
|
|
||||||
if (filteringDSObjId > 0) {
|
|
||||||
arts = blackboard.getArtifacts(type.getTypeID(), filteringDSObjId);
|
|
||||||
} else {
|
|
||||||
arts = skCase.getBlackboardArtifacts(type.getTypeID());
|
|
||||||
}
|
|
||||||
for (BlackboardArtifact art : arts) {
|
|
||||||
//Cache attributes while we are off the EDT.
|
|
||||||
//See JIRA-5969
|
|
||||||
art.getAttributes();
|
|
||||||
}
|
|
||||||
return arts;
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
Logger.getLogger(ArtifactFactory.class.getName()).log(Level.SEVERE, "Couldn't get blackboard artifacts from database", ex); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void refresh() {
|
|
||||||
refresh(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRefreshRequired(PropertyChangeEvent evt) {
|
|
||||||
String eventType = evt.getPropertyName();
|
|
||||||
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checking for a current case is a stop gap measure until a
|
|
||||||
* different way of handling the closing of cases is worked out.
|
|
||||||
* Currently, remote events may be received for a case that is
|
|
||||||
* already closed.
|
|
||||||
*/
|
|
||||||
try {
|
|
||||||
Case.getCurrentCaseThrows();
|
|
||||||
/**
|
|
||||||
* Even with the check above, it is still possible that the
|
|
||||||
* case will be closed in a different thread before this
|
|
||||||
* code executes. If that happens, it is possible for the
|
|
||||||
* event to have a null oldValue.
|
|
||||||
*/
|
|
||||||
final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue();
|
|
||||||
if (null != event && event.getBlackboardArtifactType().equals(type)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (NoCurrentCaseException notUsed) {
|
|
||||||
/**
|
|
||||||
* Case is closed, do nothing.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -46,19 +46,20 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
|||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_HASHSET_HIT;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
|
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hash set hits node support. Inner classes have all of the nodes in the tree.
|
* Hash set hits node support. Inner classes have all of the nodes in the tree.
|
||||||
*/
|
*/
|
||||||
public class HashsetHits implements AutopsyVisitableItem {
|
public class HashsetHits implements AutopsyVisitableItem {
|
||||||
|
|
||||||
private static final String HASHSET_HITS = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getLabel();
|
private static final String HASHSET_HITS = BlackboardArtifact.Type.TSK_HASHSET_HIT.getTypeName();
|
||||||
private static final String DISPLAY_NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName();
|
private static final String DISPLAY_NAME = BlackboardArtifact.Type.TSK_HASHSET_HIT.getDisplayName();
|
||||||
private static final Logger logger = Logger.getLogger(HashsetHits.class.getName());
|
private static final Logger logger = Logger.getLogger(HashsetHits.class.getName());
|
||||||
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
|
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
|
||||||
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED);
|
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED);
|
||||||
@ -134,7 +135,7 @@ public class HashsetHits implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int setNameId = ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID();
|
int setNameId = ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID();
|
||||||
int artId = ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID();
|
int artId = TSK_HASHSET_HIT.getTypeID();
|
||||||
String query = "SELECT value_text,blackboard_attributes.artifact_id,attribute_type_id " //NON-NLS
|
String query = "SELECT value_text,blackboard_attributes.artifact_id,attribute_type_id " //NON-NLS
|
||||||
+ "FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS
|
+ "FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS
|
||||||
+ "attribute_type_id=" + setNameId //NON-NLS
|
+ "attribute_type_id=" + setNameId //NON-NLS
|
||||||
@ -168,10 +169,15 @@ public class HashsetHits implements AutopsyVisitableItem {
|
|||||||
/**
|
/**
|
||||||
* Top-level node for all hash sets
|
* Top-level node for all hash sets
|
||||||
*/
|
*/
|
||||||
public class RootNode extends DisplayableItemNode {
|
public class RootNode extends UpdatableCountTypeNode {
|
||||||
|
|
||||||
public RootNode() {
|
public RootNode() {
|
||||||
super(Children.create(new HashsetNameFactory(), true), Lookups.singleton(DISPLAY_NAME));
|
super(Children.create(new HashsetNameFactory(), true),
|
||||||
|
Lookups.singleton(DISPLAY_NAME),
|
||||||
|
DISPLAY_NAME,
|
||||||
|
filteringDSObjId,
|
||||||
|
TSK_HASHSET_HIT);
|
||||||
|
|
||||||
super.setName(HASHSET_HITS);
|
super.setName(HASHSET_HITS);
|
||||||
super.setDisplayName(DISPLAY_NAME);
|
super.setDisplayName(DISPLAY_NAME);
|
||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png"); //NON-NLS
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png"); //NON-NLS
|
||||||
@ -239,7 +245,7 @@ public class HashsetHits implements AutopsyVisitableItem {
|
|||||||
* oldValue if the event is a remote event.
|
* oldValue if the event is a remote event.
|
||||||
*/
|
*/
|
||||||
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
||||||
if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) {
|
if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == TSK_HASHSET_HIT.getTypeID()) {
|
||||||
hashsetResults.update();
|
hashsetResults.update();
|
||||||
}
|
}
|
||||||
} catch (NoCurrentCaseException notUsed) {
|
} catch (NoCurrentCaseException notUsed) {
|
||||||
|
@ -50,6 +50,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute;
|
|||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
|
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode;
|
||||||
|
|
||||||
public class InterestingHits implements AutopsyVisitableItem {
|
public class InterestingHits implements AutopsyVisitableItem {
|
||||||
|
|
||||||
@ -110,8 +111,8 @@ public class InterestingHits implements AutopsyVisitableItem {
|
|||||||
synchronized (interestingItemsMap) {
|
synchronized (interestingItemsMap) {
|
||||||
interestingItemsMap.clear();
|
interestingItemsMap.clear();
|
||||||
}
|
}
|
||||||
loadArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
|
loadArtifacts(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT);
|
||||||
loadArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT);
|
loadArtifacts(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT);
|
||||||
setChanged();
|
setChanged();
|
||||||
notifyObservers();
|
notifyObservers();
|
||||||
}
|
}
|
||||||
@ -121,7 +122,7 @@ public class InterestingHits implements AutopsyVisitableItem {
|
|||||||
* the interestingItemsMap
|
* the interestingItemsMap
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
private void loadArtifacts(BlackboardArtifact.ARTIFACT_TYPE artType) {
|
private void loadArtifacts(BlackboardArtifact.Type artType) {
|
||||||
if (skCase == null) {
|
if (skCase == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -145,8 +146,8 @@ public class InterestingHits implements AutopsyVisitableItem {
|
|||||||
long artifactId = resultSet.getLong("artifact_id"); //NON-NLS
|
long artifactId = resultSet.getLong("artifact_id"); //NON-NLS
|
||||||
if (!interestingItemsMap.containsKey(value)) {
|
if (!interestingItemsMap.containsKey(value)) {
|
||||||
interestingItemsMap.put(value, new LinkedHashMap<>());
|
interestingItemsMap.put(value, new LinkedHashMap<>());
|
||||||
interestingItemsMap.get(value).put(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getDisplayName(), new HashSet<>());
|
interestingItemsMap.get(value).put(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getDisplayName(), new HashSet<>());
|
||||||
interestingItemsMap.get(value).put(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName(), new HashSet<>());
|
interestingItemsMap.get(value).put(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName(), new HashSet<>());
|
||||||
}
|
}
|
||||||
interestingItemsMap.get(value).get(artType.getDisplayName()).add(artifactId);
|
interestingItemsMap.get(value).get(artType.getDisplayName()).add(artifactId);
|
||||||
}
|
}
|
||||||
@ -165,12 +166,16 @@ public class InterestingHits implements AutopsyVisitableItem {
|
|||||||
/**
|
/**
|
||||||
* Node for the interesting items
|
* Node for the interesting items
|
||||||
*/
|
*/
|
||||||
public class RootNode extends DisplayableItemNode {
|
public class RootNode extends UpdatableCountTypeNode {
|
||||||
|
|
||||||
public RootNode() {
|
public RootNode() {
|
||||||
super(Children.create(new SetNameFactory(), true), Lookups.singleton(DISPLAY_NAME));
|
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);
|
super.setName(INTERESTING_ITEMS);
|
||||||
super.setDisplayName(DISPLAY_NAME);
|
|
||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,8 +237,8 @@ public class InterestingHits implements AutopsyVisitableItem {
|
|||||||
* event to have a null oldValue.
|
* event to have a null oldValue.
|
||||||
*/
|
*/
|
||||||
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
||||||
if (null != eventData && (eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()
|
if (null != eventData && (eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()
|
||||||
|| eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID())) {
|
|| eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID())) {
|
||||||
interestingResults.update();
|
interestingResults.update();
|
||||||
}
|
}
|
||||||
} catch (NoCurrentCaseException notUsed) {
|
} catch (NoCurrentCaseException notUsed) {
|
||||||
@ -314,8 +319,8 @@ public class InterestingHits implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateDisplayName() {
|
private void updateDisplayName() {
|
||||||
int sizeOfSet = interestingResults.getArtifactIds(setName, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName()).size()
|
int sizeOfSet = interestingResults.getArtifactIds(setName, BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName()).size()
|
||||||
+ interestingResults.getArtifactIds(setName, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getDisplayName()).size();
|
+ interestingResults.getArtifactIds(setName, BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getDisplayName()).size();
|
||||||
super.setDisplayName(setName + " (" + sizeOfSet + ")");
|
super.setDisplayName(setName + " (" + sizeOfSet + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,8 +379,8 @@ public class InterestingHits implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean createKeys(List<String> list) {
|
protected boolean createKeys(List<String> list) {
|
||||||
list.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getDisplayName());
|
list.add(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getDisplayName());
|
||||||
list.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName());
|
list.add(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,8 +405,8 @@ public class InterestingHits implements AutopsyVisitableItem {
|
|||||||
this.typeName = typeName;
|
this.typeName = typeName;
|
||||||
this.setName = setName;
|
this.setName = setName;
|
||||||
/**
|
/**
|
||||||
* We use the combination of setName and typeName as the name of
|
* We use the combination of setName and typeName as the name of the
|
||||||
* the node to ensure that nodes have a unique name. This comes into
|
* node to ensure that nodes have a unique name. This comes into
|
||||||
* play when associating paging state with the node.
|
* play when associating paging state with the node.
|
||||||
*/
|
*/
|
||||||
super.setName(setName + "_" + typeName);
|
super.setName(setName + "_" + typeName);
|
||||||
@ -462,9 +467,9 @@ public class InterestingHits implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
private HitFactory(String setName, String typeName) {
|
private HitFactory(String setName, String typeName) {
|
||||||
/**
|
/**
|
||||||
* The node name passed to the parent constructor must be the
|
* The node name passed to the parent constructor must be the same
|
||||||
* same as the name set in the InterestingItemTypeNode constructor,
|
* as the name set in the InterestingItemTypeNode constructor, i.e.
|
||||||
* i.e. setName underscore typeName
|
* setName underscore typeName
|
||||||
*/
|
*/
|
||||||
super(setName + "_" + typeName);
|
super(setName + "_" + typeName);
|
||||||
this.setName = setName;
|
this.setName = setName;
|
||||||
|
@ -55,6 +55,8 @@ import org.sleuthkit.datamodel.BlackboardAttribute;
|
|||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
|
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_KEYWORD_HIT;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keyword hits node support
|
* Keyword hits node support
|
||||||
@ -71,7 +73,7 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
@NbBundle.Messages("KeywordHits.singleRegexSearch.text=Single Regular Expression Search")
|
@NbBundle.Messages("KeywordHits.singleRegexSearch.text=Single Regular Expression Search")
|
||||||
private static final String SIMPLE_REGEX_SEARCH = KeywordHits_singleRegexSearch_text();
|
private static final String SIMPLE_REGEX_SEARCH = KeywordHits_singleRegexSearch_text();
|
||||||
|
|
||||||
public static final String NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getLabel();
|
public static final String NAME = BlackboardArtifact.Type.TSK_KEYWORD_HIT.getTypeName();
|
||||||
|
|
||||||
private SleuthkitCase skCase;
|
private SleuthkitCase skCase;
|
||||||
private final KeywordResults keywordResults;
|
private final KeywordResults keywordResults;
|
||||||
@ -93,7 +95,7 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
+ "blackboard_attributes.attribute_type_id "//NON-NLS
|
+ "blackboard_attributes.attribute_type_id "//NON-NLS
|
||||||
+ "FROM blackboard_attributes, blackboard_artifacts "//NON-NLS
|
+ "FROM blackboard_attributes, blackboard_artifacts "//NON-NLS
|
||||||
+ "WHERE blackboard_attributes.artifact_id = blackboard_artifacts.artifact_id "//NON-NLS
|
+ "WHERE blackboard_attributes.artifact_id = blackboard_artifacts.artifact_id "//NON-NLS
|
||||||
+ " AND blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() //NON-NLS
|
+ " AND blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_KEYWORD_HIT.getTypeID() //NON-NLS
|
||||||
+ " AND (attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()//NON-NLS
|
+ " AND (attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()//NON-NLS
|
||||||
+ " OR attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()//NON-NLS
|
+ " OR attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()//NON-NLS
|
||||||
+ " OR attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE.getTypeID()//NON-NLS
|
+ " OR attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE.getTypeID()//NON-NLS
|
||||||
@ -375,12 +377,16 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Created by CreateAutopsyNodeVisitor
|
// Created by CreateAutopsyNodeVisitor
|
||||||
public class RootNode extends DisplayableItemNode {
|
public class RootNode extends UpdatableCountTypeNode {
|
||||||
|
|
||||||
public RootNode() {
|
public RootNode() {
|
||||||
super(Children.create(new ListFactory(), true), Lookups.singleton(KEYWORD_HITS));
|
super(Children.create(new ListFactory(), true),
|
||||||
|
Lookups.singleton(KEYWORD_HITS),
|
||||||
|
KEYWORD_HITS,
|
||||||
|
filteringDSObjId,
|
||||||
|
TSK_KEYWORD_HIT);
|
||||||
|
|
||||||
super.setName(NAME);
|
super.setName(NAME);
|
||||||
super.setDisplayName(KEYWORD_HITS);
|
|
||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -464,7 +470,7 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
* for the event to have a null oldValue.
|
* for the event to have a null oldValue.
|
||||||
*/
|
*/
|
||||||
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
||||||
if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
|
if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.Type.TSK_KEYWORD_HIT.getTypeID()) {
|
||||||
keywordResults.update();
|
keywordResults.update();
|
||||||
}
|
}
|
||||||
} catch (NoCurrentCaseException notUsed) {
|
} catch (NoCurrentCaseException notUsed) {
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2011 Basis Technology Corp.
|
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.sleuthkit.autopsy.datamodel;
|
|
||||||
|
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Results node support
|
|
||||||
*/
|
|
||||||
public class Results implements AutopsyVisitableItem {
|
|
||||||
|
|
||||||
private SleuthkitCase skCase;
|
|
||||||
private final long datasourceObjId;
|
|
||||||
|
|
||||||
public Results(SleuthkitCase skCase) {
|
|
||||||
this(skCase, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Results(SleuthkitCase skCase, long dsObjId) {
|
|
||||||
this.skCase = skCase;
|
|
||||||
this.datasourceObjId = dsObjId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T accept(AutopsyItemVisitor<T> visitor) {
|
|
||||||
return visitor.visit(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SleuthkitCase getSleuthkitCase() {
|
|
||||||
return skCase;
|
|
||||||
}
|
|
||||||
|
|
||||||
long filteringDataSourceObjId() {
|
|
||||||
return datasourceObjId;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,97 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.sleuthkit.autopsy.datamodel;
|
|
||||||
|
|
||||||
import org.sleuthkit.autopsy.datamodel.accounts.Accounts;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import org.openide.nodes.Sheet;
|
|
||||||
import org.openide.util.NbBundle;
|
|
||||||
import org.openide.util.lookup.Lookups;
|
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Node for the results section of the tree.
|
|
||||||
*/
|
|
||||||
public class ResultsNode extends DisplayableItemNode {
|
|
||||||
|
|
||||||
@NbBundle.Messages("ResultsNode.name.text=Results")
|
|
||||||
private static final String NAME = Bundle.ResultsNode_name_text();
|
|
||||||
|
|
||||||
public static String getNameIdentifier() {
|
|
||||||
return NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResultsNode(SleuthkitCase sleuthkitCase) {
|
|
||||||
this(sleuthkitCase, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResultsNode(SleuthkitCase sleuthkitCase, long dsObjId) {
|
|
||||||
super(
|
|
||||||
|
|
||||||
new RootContentChildren(Arrays.asList(
|
|
||||||
new ExtractedContent(sleuthkitCase, dsObjId ),
|
|
||||||
new KeywordHits(sleuthkitCase, dsObjId),
|
|
||||||
new HashsetHits(sleuthkitCase, dsObjId),
|
|
||||||
new EmailExtracted(sleuthkitCase, dsObjId),
|
|
||||||
new InterestingHits(sleuthkitCase, dsObjId ),
|
|
||||||
new Accounts(sleuthkitCase, dsObjId),
|
|
||||||
new OsAccounts(sleuthkitCase, dsObjId))
|
|
||||||
),
|
|
||||||
Lookups.singleton(NAME));
|
|
||||||
setName(NAME);
|
|
||||||
setDisplayName(NAME);
|
|
||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/results.png"); //NON-NLS
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLeafTypeNode() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
|
|
||||||
return visitor.visit(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@NbBundle.Messages({
|
|
||||||
"ResultsNode.createSheet.name.name=Name",
|
|
||||||
"ResultsNode.createSheet.name.displayName=Name",
|
|
||||||
"ResultsNode.createSheet.name.desc=no description"})
|
|
||||||
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<>(Bundle.ResultsNode_createSheet_name_name(),
|
|
||||||
Bundle.ResultsNode_createSheet_name_displayName(),
|
|
||||||
Bundle.ResultsNode_createSheet_name_desc(),
|
|
||||||
NAME
|
|
||||||
));
|
|
||||||
return sheet;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getItemType() {
|
|
||||||
return getClass().getName();
|
|
||||||
}
|
|
||||||
}
|
|
@ -83,11 +83,6 @@ public class RootContentChildren extends Children.Keys<Object> {
|
|||||||
*/
|
*/
|
||||||
static class CreateAutopsyNodeVisitor extends AutopsyItemVisitor.Default<AbstractNode> {
|
static class CreateAutopsyNodeVisitor extends AutopsyItemVisitor.Default<AbstractNode> {
|
||||||
|
|
||||||
@Override
|
|
||||||
public ExtractedContent.RootNode visit(ExtractedContent ec) {
|
|
||||||
return ec.new RootNode(ec.getSleuthkitCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AbstractNode visit(FileTypesByExtension sf) {
|
public AbstractNode visit(FileTypesByExtension sf) {
|
||||||
return sf.new FileTypesByExtNode(sf.getSleuthkitCase(), null);
|
return sf.new FileTypesByExtNode(sf.getSleuthkitCase(), null);
|
||||||
@ -148,11 +143,6 @@ public class RootContentChildren extends Children.Keys<Object> {
|
|||||||
return new ViewsNode(v.getSleuthkitCase(), v.filteringDataSourceObjId());
|
return new ViewsNode(v.getSleuthkitCase(), v.filteringDataSourceObjId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public AbstractNode visit(Results results) {
|
|
||||||
return new ResultsNode(results.getSleuthkitCase(), results.filteringDataSourceObjId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AbstractNode visit(FileTypes ft) {
|
public AbstractNode visit(FileTypes ft) {
|
||||||
return ft.new FileTypesNode();
|
return ft.new FileTypesNode();
|
||||||
@ -167,7 +157,7 @@ public class RootContentChildren extends Children.Keys<Object> {
|
|||||||
public AbstractNode visit(Accounts accountsItem) {
|
public AbstractNode visit(Accounts accountsItem) {
|
||||||
return accountsItem.new AccountsRootNode();
|
return accountsItem.new AccountsRootNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AbstractNode visit(OsAccounts osAccountsItem) {
|
public AbstractNode visit(OsAccounts osAccountsItem) {
|
||||||
return osAccountsItem.new OsAccountListNode();
|
return osAccountsItem.new OsAccountListNode();
|
||||||
@ -204,5 +194,17 @@ public class RootContentChildren extends Children.Keys<Object> {
|
|||||||
public AbstractNode visit(DataSourcesByType dataSourceHosts) {
|
public AbstractNode visit(DataSourcesByType dataSourceHosts) {
|
||||||
return new DataSourcesByTypeNode();
|
return new DataSourcesByTypeNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbstractNode visit(AnalysisResults analysisResults) {
|
||||||
|
return new AnalysisResults.RootNode(
|
||||||
|
analysisResults.getFilteringDataSourceObjId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbstractNode visit(DataArtifacts dataArtifacts) {
|
||||||
|
return new DataArtifacts.RootNode(
|
||||||
|
dataArtifacts.getFilteringDataSourceObjId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,7 @@ import org.sleuthkit.autopsy.datamodel.CreditCards;
|
|||||||
import org.sleuthkit.autopsy.datamodel.DataModelActionsFactory;
|
import org.sleuthkit.autopsy.datamodel.DataModelActionsFactory;
|
||||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||||
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
|
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
@ -76,7 +77,8 @@ import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
|||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.Account;
|
import org.sleuthkit.datamodel.Account;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
import org.sleuthkit.datamodel.BlackboardArtifact.Type;
|
||||||
|
import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_ACCOUNT;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
@ -93,7 +95,8 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
private static final String ICON_BASE_PATH = "/org/sleuthkit/autopsy/images/"; //NON-NLS
|
private static final String ICON_BASE_PATH = "/org/sleuthkit/autopsy/images/"; //NON-NLS
|
||||||
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
|
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
|
||||||
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED);
|
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED);
|
||||||
|
private static final String DISPLAY_NAME = Bundle.Accounts_RootNode_displayName();
|
||||||
|
|
||||||
@NbBundle.Messages("AccountsRootNode.name=Accounts")
|
@NbBundle.Messages("AccountsRootNode.name=Accounts")
|
||||||
final public static String NAME = Bundle.AccountsRootNode_name();
|
final public static String NAME = Bundle.AccountsRootNode_name();
|
||||||
|
|
||||||
@ -109,7 +112,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
private final RejectAccounts rejectActionInstance;
|
private final RejectAccounts rejectActionInstance;
|
||||||
private final ApproveAccounts approveActionInstance;
|
private final ApproveAccounts approveActionInstance;
|
||||||
|
|
||||||
// tracks the number of each account type found
|
// tracks the number of each account type found
|
||||||
private final AccountTypeResults accountTypeResults;
|
private final AccountTypeResults accountTypeResults;
|
||||||
|
|
||||||
@ -131,7 +134,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
public Accounts(SleuthkitCase skCase, long objId) {
|
public Accounts(SleuthkitCase skCase, long objId) {
|
||||||
this.skCase = skCase;
|
this.skCase = skCase;
|
||||||
this.filteringDSObjId = objId;
|
this.filteringDSObjId = objId;
|
||||||
|
|
||||||
this.rejectActionInstance = new RejectAccounts();
|
this.rejectActionInstance = new RejectAccounts();
|
||||||
this.approveActionInstance = new ApproveAccounts();
|
this.approveActionInstance = new ApproveAccounts();
|
||||||
this.accountTypeResults = new AccountTypeResults();
|
this.accountTypeResults = new AccountTypeResults();
|
||||||
@ -231,12 +234,16 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
* Top-level node for the accounts tree
|
* Top-level node for the accounts tree
|
||||||
*/
|
*/
|
||||||
@NbBundle.Messages({"Accounts.RootNode.displayName=Accounts"})
|
@NbBundle.Messages({"Accounts.RootNode.displayName=Accounts"})
|
||||||
final public class AccountsRootNode extends DisplayableItemNode {
|
final public class AccountsRootNode extends UpdatableCountTypeNode {
|
||||||
|
|
||||||
public AccountsRootNode() {
|
public AccountsRootNode() {
|
||||||
super(Children.create(new AccountTypeFactory(), true), Lookups.singleton(Accounts.this));
|
super(Children.create(new AccountTypeFactory(), true),
|
||||||
|
Lookups.singleton(Accounts.this),
|
||||||
|
DISPLAY_NAME,
|
||||||
|
filteringDSObjId,
|
||||||
|
TSK_ACCOUNT);
|
||||||
|
|
||||||
setName(Accounts.NAME);
|
setName(Accounts.NAME);
|
||||||
setDisplayName(Bundle.Accounts_RootNode_displayName());
|
|
||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/accounts.png"); //NON-NLS
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/accounts.png"); //NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,37 +261,71 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
public String getItemType() {
|
public String getItemType() {
|
||||||
return getClass().getName();
|
return getClass().getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected long fetchChildCount(SleuthkitCase skCase) throws TskCoreException {
|
||||||
|
long count = 0;
|
||||||
|
String dataSourceFilterClause = (filteringDSObjId > 0)
|
||||||
|
? " AND " + filteringDSObjId + " IN (SELECT art.data_source_obj_id FROM blackboard_artifacts art WHERE art.artifact_id = attr.artifact_id)"
|
||||||
|
: "";
|
||||||
|
|
||||||
|
String accountTypesInUseQuery
|
||||||
|
= "SELECT COUNT(attr.value_text) AS count"
|
||||||
|
+ " FROM blackboard_attributes attr"
|
||||||
|
+ " WHERE attr.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()
|
||||||
|
+ " AND attr.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID()
|
||||||
|
+ dataSourceFilterClause
|
||||||
|
+ " GROUP BY attr.value_text";
|
||||||
|
|
||||||
|
try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery(accountTypesInUseQuery);
|
||||||
|
ResultSet resultSet = executeQuery.getResultSet()) {
|
||||||
|
|
||||||
|
if (resultSet.next()) {
|
||||||
|
count = resultSet.getLong("count");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (TskCoreException | SQLException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Error querying for count of all account types", ex);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tracks the account types and the number of account types found.
|
* Tracks the account types and the number of account types found.
|
||||||
*/
|
*/
|
||||||
private class AccountTypeResults {
|
private class AccountTypeResults {
|
||||||
|
|
||||||
private final Map<String, Long> counts = new HashMap<>();
|
private final Map<String, Long> counts = new HashMap<>();
|
||||||
|
|
||||||
AccountTypeResults() {
|
AccountTypeResults() {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given the type name of the Account.Type, provides the count of those type.
|
* Given the type name of the Account.Type, provides the count of those
|
||||||
* @param accountType The type name of the Account.Type.
|
* type.
|
||||||
* @return The number of results found for the given account type.
|
*
|
||||||
|
* @param accountType The type name of the Account.Type.
|
||||||
|
*
|
||||||
|
* @return The number of results found for the given account type.
|
||||||
*/
|
*/
|
||||||
Long getCount(String accountType) {
|
Long getCount(String accountType) {
|
||||||
return counts.get(accountType);
|
return counts.get(accountType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves an alphabetically organized list of all the account types.
|
* Retrieves an alphabetically organized list of all the account types.
|
||||||
* @return An alphabetically organized list of all the account types.
|
*
|
||||||
|
* @return An alphabetically organized list of all the account types.
|
||||||
*/
|
*/
|
||||||
List<String> getTypes() {
|
List<String> getTypes() {
|
||||||
List<String> types = new ArrayList<>(counts.keySet());
|
List<String> types = new ArrayList<>(counts.keySet());
|
||||||
Collections.sort(types);
|
Collections.sort(types);
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queries the database and updates the counts for each account type.
|
* Queries the database and updates the counts for each account type.
|
||||||
*/
|
*/
|
||||||
@ -293,14 +334,14 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
= "SELECT blackboard_attributes.value_text as account_type, COUNT(*) as count "
|
= "SELECT blackboard_attributes.value_text as account_type, COUNT(*) as count "
|
||||||
+ " FROM blackboard_artifacts " //NON-NLS
|
+ " FROM blackboard_artifacts " //NON-NLS
|
||||||
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
|
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
|
||||||
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
|
+ " WHERE blackboard_artifacts.artifact_type_id = " + TSK_ACCOUNT.getTypeID() //NON-NLS
|
||||||
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS
|
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS
|
||||||
+ getFilterByDataSourceClause()
|
+ getFilterByDataSourceClause()
|
||||||
+ " GROUP BY blackboard_attributes.value_text ";
|
+ " GROUP BY blackboard_attributes.value_text ";
|
||||||
|
|
||||||
try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery(accountTypesInUseQuery);
|
try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery(accountTypesInUseQuery);
|
||||||
ResultSet resultSet = executeQuery.getResultSet()) {
|
ResultSet resultSet = executeQuery.getResultSet()) {
|
||||||
|
|
||||||
counts.clear();
|
counts.clear();
|
||||||
while (resultSet.next()) {
|
while (resultSet.next()) {
|
||||||
String accountType = resultSet.getString("account_type");
|
String accountType = resultSet.getString("account_type");
|
||||||
@ -317,7 +358,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
* Creates child nodes for each account type in the db.
|
* Creates child nodes for each account type in the db.
|
||||||
*/
|
*/
|
||||||
private class AccountTypeFactory extends ObservingChildren<String> {
|
private class AccountTypeFactory extends ObservingChildren<String> {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The pcl is in this class because it has the easiest mechanisms to add
|
* The pcl is in this class because it has the easiest mechanisms to add
|
||||||
* and remove itself during its life cycles.
|
* and remove itself during its life cycles.
|
||||||
@ -343,7 +384,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
*/
|
*/
|
||||||
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
||||||
if (null != eventData
|
if (null != eventData
|
||||||
&& eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
|
&& eventData.getBlackboardArtifactType().getTypeID() == Type.TSK_ACCOUNT.getTypeID()) {
|
||||||
accountTypeResults.update();
|
accountTypeResults.update();
|
||||||
reviewStatusBus.post(eventData);
|
reviewStatusBus.post(eventData);
|
||||||
}
|
}
|
||||||
@ -391,12 +432,14 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
list.addAll(accountTypeResults.getTypes());
|
list.addAll(accountTypeResults.getTypes());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers the given node with the reviewStatusBus and returns
|
* Registers the given node with the reviewStatusBus and returns the
|
||||||
* the node wrapped in an array.
|
* node wrapped in an array.
|
||||||
* @param node The node to be wrapped.
|
*
|
||||||
* @return The array containing this node.
|
* @param node The node to be wrapped.
|
||||||
|
*
|
||||||
|
* @return The array containing this node.
|
||||||
*/
|
*/
|
||||||
private Node[] getNodeArr(Node node) {
|
private Node[] getNodeArr(Node node) {
|
||||||
reviewStatusBus.register(node);
|
reviewStatusBus.register(node);
|
||||||
@ -476,7 +519,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
*/
|
*/
|
||||||
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
||||||
if (null != eventData
|
if (null != eventData
|
||||||
&& eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
|
&& eventData.getBlackboardArtifactType().getTypeID() == Type.TSK_ACCOUNT.getTypeID()) {
|
||||||
reviewStatusBus.post(eventData);
|
reviewStatusBus.post(eventData);
|
||||||
}
|
}
|
||||||
} catch (NoCurrentCaseException notUsed) {
|
} catch (NoCurrentCaseException notUsed) {
|
||||||
@ -529,7 +572,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
= "SELECT blackboard_artifacts.artifact_id " //NON-NLS
|
= "SELECT blackboard_artifacts.artifact_id " //NON-NLS
|
||||||
+ " FROM blackboard_artifacts " //NON-NLS
|
+ " FROM blackboard_artifacts " //NON-NLS
|
||||||
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
|
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
|
||||||
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
|
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS
|
||||||
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS
|
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS
|
||||||
+ " AND blackboard_attributes.value_text = '" + accountType.getTypeName() + "'" //NON-NLS
|
+ " AND blackboard_attributes.value_text = '" + accountType.getTypeName() + "'" //NON-NLS
|
||||||
+ getFilterByDataSourceClause()
|
+ getFilterByDataSourceClause()
|
||||||
@ -576,13 +619,15 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
* no special behavior.
|
* no special behavior.
|
||||||
*/
|
*/
|
||||||
final public class DefaultAccountTypeNode extends DisplayableItemNode {
|
final public class DefaultAccountTypeNode extends DisplayableItemNode {
|
||||||
|
|
||||||
private final Account.Type accountType;
|
private final Account.Type accountType;
|
||||||
|
|
||||||
private DefaultAccountTypeNode(Account.Type accountType) {
|
private DefaultAccountTypeNode(Account.Type accountType) {
|
||||||
super(Children.create(new DefaultAccountFactory(accountType), true), Lookups.singleton(accountType));
|
super(Children.create(new DefaultAccountFactory(accountType), true), Lookups.singleton(accountType));
|
||||||
this.accountType = accountType;
|
this.accountType = accountType;
|
||||||
String iconPath = getIconFilePath(accountType);
|
String iconPath = getIconFilePath(accountType);
|
||||||
this.setIconBaseWithExtension(iconPath != null && iconPath.charAt(0) == '/' ? iconPath.substring(1) : iconPath); //NON-NLS
|
this.setIconBaseWithExtension(iconPath != null && iconPath.charAt(0) == '/' ? iconPath.substring(1) : iconPath); //NON-NLS
|
||||||
|
setName(accountType.getTypeName());
|
||||||
updateName();
|
updateName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -600,8 +645,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
public String getItemType() {
|
public String getItemType() {
|
||||||
return getClass().getName();
|
return getClass().getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
void handleReviewStatusChange(ReviewStatusChangeEvent event) {
|
void handleReviewStatusChange(ReviewStatusChangeEvent event) {
|
||||||
updateName();
|
updateName();
|
||||||
@ -611,12 +655,13 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
void handleDataAdded(ModuleDataEvent event) {
|
void handleDataAdded(ModuleDataEvent event) {
|
||||||
updateName();
|
updateName();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the latest counts for the account type and then updates the name.
|
* Gets the latest counts for the account type and then updates the
|
||||||
|
* name.
|
||||||
*/
|
*/
|
||||||
public void updateName() {
|
public void updateName() {
|
||||||
setName(String.format("%s (%d)", accountType.getDisplayName(), accountTypeResults.getCount(accountType.getTypeName())));
|
setDisplayName(String.format("%s (%d)", accountType.getDisplayName(), accountTypeResults.getCount(accountType.getTypeName())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -651,7 +696,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
*/
|
*/
|
||||||
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
||||||
if (null != eventData
|
if (null != eventData
|
||||||
&& eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
|
&& eventData.getBlackboardArtifactType().getTypeID() == Type.TSK_ACCOUNT.getTypeID()) {
|
||||||
reviewStatusBus.post(eventData);
|
reviewStatusBus.post(eventData);
|
||||||
}
|
}
|
||||||
} catch (NoCurrentCaseException notUsed) {
|
} catch (NoCurrentCaseException notUsed) {
|
||||||
@ -747,14 +792,15 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
setName(Account.Type.CREDIT_CARD.getDisplayName());
|
setName(Account.Type.CREDIT_CARD.getDisplayName());
|
||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/credit-cards.png"); //NON-NLS
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/credit-cards.png"); //NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the latest counts for the account type and then updates the name.
|
* Gets the latest counts for the account type and then updates the
|
||||||
|
* name.
|
||||||
*/
|
*/
|
||||||
public void updateName() {
|
public void updateName() {
|
||||||
setName(String.format("%s (%d)", Account.Type.CREDIT_CARD.getDisplayName(), accountTypeResults.getCount(Account.Type.CREDIT_CARD.getTypeName())));
|
setName(String.format("%s (%d)", Account.Type.CREDIT_CARD.getDisplayName(), accountTypeResults.getCount(Account.Type.CREDIT_CARD.getTypeName())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
void handleReviewStatusChange(ReviewStatusChangeEvent event) {
|
void handleReviewStatusChange(ReviewStatusChangeEvent event) {
|
||||||
updateName();
|
updateName();
|
||||||
@ -804,7 +850,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
*/
|
*/
|
||||||
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
||||||
if (null != eventData
|
if (null != eventData
|
||||||
&& eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
|
&& eventData.getBlackboardArtifactType().getTypeID() == Type.TSK_ACCOUNT.getTypeID()) {
|
||||||
reviewStatusBus.post(eventData);
|
reviewStatusBus.post(eventData);
|
||||||
}
|
}
|
||||||
} catch (NoCurrentCaseException notUsed) {
|
} catch (NoCurrentCaseException notUsed) {
|
||||||
@ -882,7 +928,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
+ " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS
|
+ " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS
|
||||||
+ " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS
|
+ " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS
|
||||||
+ " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.getTypeName() + "'" //NON-NLS
|
+ " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.getTypeName() + "'" //NON-NLS
|
||||||
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
|
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS
|
||||||
+ getFilterByDataSourceClause()
|
+ getFilterByDataSourceClause()
|
||||||
+ getRejectedArtifactFilterClause()
|
+ getRejectedArtifactFilterClause()
|
||||||
+ " GROUP BY blackboard_artifacts.obj_id, solr_document_id " //NON-NLS
|
+ " GROUP BY blackboard_artifacts.obj_id, solr_document_id " //NON-NLS
|
||||||
@ -951,7 +997,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
+ " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS
|
+ " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS
|
||||||
+ " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS
|
+ " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS
|
||||||
+ " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.getTypeName() + "'" //NON-NLS
|
+ " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.getTypeName() + "'" //NON-NLS
|
||||||
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
|
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS
|
||||||
+ getFilterByDataSourceClause()
|
+ getFilterByDataSourceClause()
|
||||||
+ getRejectedArtifactFilterClause()
|
+ getRejectedArtifactFilterClause()
|
||||||
+ " GROUP BY blackboard_artifacts.obj_id, solr_attribute.value_text ) AS foo";
|
+ " GROUP BY blackboard_artifacts.obj_id, solr_attribute.value_text ) AS foo";
|
||||||
@ -1019,7 +1065,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
*/
|
*/
|
||||||
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
||||||
if (null != eventData
|
if (null != eventData
|
||||||
&& eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
|
&& eventData.getBlackboardArtifactType().getTypeID() == Type.TSK_ACCOUNT.getTypeID()) {
|
||||||
reviewStatusBus.post(eventData);
|
reviewStatusBus.post(eventData);
|
||||||
}
|
}
|
||||||
} catch (NoCurrentCaseException notUsed) { //NOPMD empy catch clause
|
} catch (NoCurrentCaseException notUsed) { //NOPMD empy catch clause
|
||||||
@ -1087,7 +1133,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
+ " COUNT(blackboard_artifacts.artifact_id) AS count " //NON-NLS
|
+ " COUNT(blackboard_artifacts.artifact_id) AS count " //NON-NLS
|
||||||
+ " FROM blackboard_artifacts " //NON-NLS
|
+ " FROM blackboard_artifacts " //NON-NLS
|
||||||
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS
|
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS
|
||||||
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
|
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS
|
||||||
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS
|
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS
|
||||||
+ getFilterByDataSourceClause()
|
+ getFilterByDataSourceClause()
|
||||||
+ getRejectedArtifactFilterClause()
|
+ getRejectedArtifactFilterClause()
|
||||||
@ -1154,7 +1200,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
= "SELECT count(distinct SUBSTR(blackboard_attributes.value_text,1,8)) AS BINs " //NON-NLS
|
= "SELECT count(distinct SUBSTR(blackboard_attributes.value_text,1,8)) AS BINs " //NON-NLS
|
||||||
+ " FROM blackboard_artifacts " //NON-NLS
|
+ " FROM blackboard_artifacts " //NON-NLS
|
||||||
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS
|
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS
|
||||||
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
|
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS
|
||||||
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS
|
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS
|
||||||
+ getFilterByDataSourceClause()
|
+ getFilterByDataSourceClause()
|
||||||
+ getRejectedArtifactFilterClause(); //NON-NLS
|
+ getRejectedArtifactFilterClause(); //NON-NLS
|
||||||
@ -1449,7 +1495,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
= "SELECT blackboard_artifacts.artifact_id " //NON-NLS
|
= "SELECT blackboard_artifacts.artifact_id " //NON-NLS
|
||||||
+ " FROM blackboard_artifacts " //NON-NLS
|
+ " FROM blackboard_artifacts " //NON-NLS
|
||||||
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
|
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
|
||||||
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
|
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS
|
||||||
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS
|
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS
|
||||||
+ " AND blackboard_attributes.value_text >= '" + bin.getBINStart() + "' AND blackboard_attributes.value_text < '" + (bin.getBINEnd() + 1) + "'" //NON-NLS
|
+ " AND blackboard_attributes.value_text >= '" + bin.getBINStart() + "' AND blackboard_attributes.value_text < '" + (bin.getBINEnd() + 1) + "'" //NON-NLS
|
||||||
+ getFilterByDataSourceClause()
|
+ getFilterByDataSourceClause()
|
||||||
@ -1523,7 +1569,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
= "SELECT count(blackboard_artifacts.artifact_id ) AS count" //NON-NLS
|
= "SELECT count(blackboard_artifacts.artifact_id ) AS count" //NON-NLS
|
||||||
+ " FROM blackboard_artifacts " //NON-NLS
|
+ " FROM blackboard_artifacts " //NON-NLS
|
||||||
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
|
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
|
||||||
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
|
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS
|
||||||
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS
|
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS
|
||||||
+ " AND blackboard_attributes.value_text >= '" + bin.getBINStart() + "' AND blackboard_attributes.value_text < '" + (bin.getBINEnd() + 1) + "'" //NON-NLS
|
+ " AND blackboard_attributes.value_text >= '" + bin.getBINStart() + "' AND blackboard_attributes.value_text < '" + (bin.getBINEnd() + 1) + "'" //NON-NLS
|
||||||
+ getFilterByDataSourceClause()
|
+ getFilterByDataSourceClause()
|
||||||
|
@ -32,6 +32,7 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.prefs.PreferenceChangeEvent;
|
import java.util.prefs.PreferenceChangeEvent;
|
||||||
@ -72,18 +73,18 @@ import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
|
|||||||
import org.sleuthkit.autopsy.corecomponents.ViewPreferencesPanel;
|
import org.sleuthkit.autopsy.corecomponents.ViewPreferencesPanel;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.AnalysisResults;
|
||||||
import org.sleuthkit.autopsy.datamodel.ArtifactNodeSelectionInfo;
|
import org.sleuthkit.autopsy.datamodel.ArtifactNodeSelectionInfo;
|
||||||
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.CreditCards;
|
import org.sleuthkit.autopsy.datamodel.CreditCards;
|
||||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.EmailExtracted;
|
import org.sleuthkit.autopsy.datamodel.EmailExtracted;
|
||||||
import org.sleuthkit.autopsy.datamodel.EmptyNode;
|
import org.sleuthkit.autopsy.datamodel.EmptyNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.ExtractedContent;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.FileTypesByMimeType;
|
import org.sleuthkit.autopsy.datamodel.FileTypesByMimeType;
|
||||||
import org.sleuthkit.autopsy.datamodel.InterestingHits;
|
import org.sleuthkit.autopsy.datamodel.InterestingHits;
|
||||||
import org.sleuthkit.autopsy.datamodel.KeywordHits;
|
import org.sleuthkit.autopsy.datamodel.KeywordHits;
|
||||||
import org.sleuthkit.autopsy.datamodel.ResultsNode;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.AutopsyTreeChildFactory;
|
import org.sleuthkit.autopsy.datamodel.AutopsyTreeChildFactory;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.DataArtifacts;
|
||||||
import org.sleuthkit.autopsy.datamodel.PersonGroupingNode;
|
import org.sleuthkit.autopsy.datamodel.PersonGroupingNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.Tags;
|
import org.sleuthkit.autopsy.datamodel.Tags;
|
||||||
import org.sleuthkit.autopsy.datamodel.ViewsNode;
|
import org.sleuthkit.autopsy.datamodel.ViewsNode;
|
||||||
@ -91,6 +92,7 @@ import org.sleuthkit.autopsy.datamodel.accounts.Accounts;
|
|||||||
import org.sleuthkit.autopsy.datamodel.accounts.BINRange;
|
import org.sleuthkit.autopsy.datamodel.accounts.BINRange;
|
||||||
import org.sleuthkit.datamodel.Account;
|
import org.sleuthkit.datamodel.Account;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifact.Category;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.DataSource;
|
import org.sleuthkit.datamodel.DataSource;
|
||||||
@ -199,19 +201,21 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
|||||||
*/
|
*/
|
||||||
private void preExpandNodes(Children rootChildren) {
|
private void preExpandNodes(Children rootChildren) {
|
||||||
BeanTreeView tree = getTree();
|
BeanTreeView tree = getTree();
|
||||||
|
for (String categoryKey : new String[]{AnalysisResults.getName(), DataArtifacts.getName()}) {
|
||||||
|
Node categoryNode = rootChildren.findChild(categoryKey);
|
||||||
|
|
||||||
Node results = rootChildren.findChild(ResultsNode.getNameIdentifier());
|
if (!Objects.isNull(categoryNode)) {
|
||||||
if (!Objects.isNull(results)) {
|
tree.expandNode(categoryNode);
|
||||||
tree.expandNode(results);
|
Children resultsChildren = categoryNode.getChildren();
|
||||||
Children resultsChildren = results.getChildren();
|
Arrays.stream(resultsChildren.getNodes()).forEach(tree::expandNode);
|
||||||
Arrays.stream(resultsChildren.getNodes()).forEach(tree::expandNode);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Node views = rootChildren.findChild(ViewsNode.NAME);
|
Node views = rootChildren.findChild(ViewsNode.NAME);
|
||||||
if (!Objects.isNull(views)) {
|
if (!Objects.isNull(views)) {
|
||||||
tree.expandNode(views);
|
tree.expandNode(views);
|
||||||
}
|
}
|
||||||
|
|
||||||
// expand all nodes parents of and including hosts if group by host/person
|
// expand all nodes parents of and including hosts if group by host/person
|
||||||
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
|
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
|
||||||
Node[] rootNodes = rootChildren.getNodes();
|
Node[] rootNodes = rootChildren.getNodes();
|
||||||
@ -223,11 +227,13 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all nodes including provided node that are parents of or are hosts.
|
* Returns all nodes including provided node that are parents of or are
|
||||||
|
* hosts.
|
||||||
|
*
|
||||||
* @param node The parent or possible host node.
|
* @param node The parent or possible host node.
|
||||||
|
*
|
||||||
* @return The descendant host nodes.
|
* @return The descendant host nodes.
|
||||||
*/
|
*/
|
||||||
private List<Node> getHostNodesAndParents(Node node) {
|
private List<Node> getHostNodesAndParents(Node node) {
|
||||||
@ -307,7 +313,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
|||||||
* Setter to determine if rejected results should be shown or not.
|
* Setter to determine if rejected results should be shown or not.
|
||||||
*
|
*
|
||||||
* @param showRejectedResults True if showing rejected results; otherwise
|
* @param showRejectedResults True if showing rejected results; otherwise
|
||||||
* false.
|
* false.
|
||||||
*/
|
*/
|
||||||
public void setShowRejectedResults(boolean showRejectedResults) {
|
public void setShowRejectedResults(boolean showRejectedResults) {
|
||||||
this.showRejectedResults = showRejectedResults;
|
this.showRejectedResults = showRejectedResults;
|
||||||
@ -1054,7 +1060,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
|||||||
* Set the selected node using a path to a previously selected node.
|
* Set the selected node using a path to a previously selected node.
|
||||||
*
|
*
|
||||||
* @param previouslySelectedNodePath Path to a previously selected node.
|
* @param previouslySelectedNodePath Path to a previously selected node.
|
||||||
* @param rootNodeName Name of the root node to match, may be null.
|
* @param rootNodeName Name of the root node to match, may be
|
||||||
|
* null.
|
||||||
*/
|
*/
|
||||||
private void setSelectedNode(final String[] previouslySelectedNodePath, final String rootNodeName) {
|
private void setSelectedNode(final String[] previouslySelectedNodePath, final String rootNodeName) {
|
||||||
if (previouslySelectedNodePath == null) {
|
if (previouslySelectedNodePath == null) {
|
||||||
@ -1112,53 +1119,82 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does dfs search of node while nodes are Host, Person, or
|
* Returns the node matching the given category that is an immediate child
|
||||||
* DataSourcesByType looking for the Results Node.
|
* of the provided Children object or empty if no immediate child matches
|
||||||
|
* the given category.
|
||||||
*
|
*
|
||||||
* @param node The node.
|
* @param children The children to search.
|
||||||
* @param dataSourceId The data source id.
|
* @param category The category to find.
|
||||||
* @return The child nodes that are at the data source level.
|
*
|
||||||
|
* @return The node matching the given category
|
||||||
*/
|
*/
|
||||||
private Node getResultsNodeSearch(Node node, long dataSourceId) {
|
private Optional<Node> getCategoryNodeChild(Children children, Category category) {
|
||||||
if (node == null) {
|
switch (category) {
|
||||||
return null;
|
case DATA_ARTIFACT:
|
||||||
} else if (node.getLookup().lookup(Host.class) != null
|
return Optional.ofNullable(children.findChild(DataArtifacts.getName()));
|
||||||
|| node.getLookup().lookup(Person.class) != null
|
case ANALYSIS_RESULT:
|
||||||
|| PersonGroupingNode.getUnknownPersonId().equals(node.getLookup().lookup(String.class))) {
|
return Optional.ofNullable(children.findChild(AnalysisResults.getName()));
|
||||||
Children children = node.getChildren();
|
default:
|
||||||
Node[] childNodes = children == null ? null : children.getNodes();
|
LOGGER.log(Level.WARNING, "Unbale to find category of type: " + category.name());
|
||||||
if (childNodes != null) {
|
return Optional.empty();
|
||||||
for (Node child : childNodes) {
|
|
||||||
Node foundExtracted = getResultsNodeSearch(child, dataSourceId);
|
|
||||||
if (foundExtracted != null) {
|
|
||||||
return foundExtracted;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DataSource dataSource = node.getLookup().lookup(DataSource.class);
|
|
||||||
if (dataSource != null && dataSource.getId() == dataSourceId) {
|
|
||||||
Children dsChildren = node.getChildren();
|
|
||||||
if (dsChildren != null) {
|
|
||||||
return dsChildren.findChild(ResultsNode.getNameIdentifier());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the results node for the specific artifact.
|
* Does depth first search of node while nodes are Host, Person, or
|
||||||
|
* DataSourcesByType looking for the appropriate category Node (i.e. the
|
||||||
|
* Data Artifacts or Analysis Results nodes).
|
||||||
*
|
*
|
||||||
* @param art The artifact to find the relevant Results Node.
|
* @param node The node.
|
||||||
* @return THe Results Node or null.
|
* @param dataSourceId The data source id.
|
||||||
|
* @param category The artifact type category.
|
||||||
|
*
|
||||||
|
* @return The child nodes that are at the data source level.
|
||||||
*/
|
*/
|
||||||
private Node getResultsNode(final BlackboardArtifact art) {
|
private Optional<Node> searchForCategoryNode(Node node, long dataSourceId, Category category) {
|
||||||
Children rootChilds = em.getRootContext().getChildren();
|
if (node == null) {
|
||||||
|
// if no node, no result
|
||||||
|
return Optional.empty();
|
||||||
|
} else if (node.getLookup().lookup(Host.class) != null
|
||||||
|
|| node.getLookup().lookup(Person.class) != null
|
||||||
|
|| PersonGroupingNode.getUnknownPersonId().equals(node.getLookup().lookup(String.class))) {
|
||||||
|
// if host or person node, recurse until we find correct data source node.
|
||||||
|
Children children = node.getChildren();
|
||||||
|
|
||||||
Node resultsNode = rootChilds.findChild(ResultsNode.getNameIdentifier());
|
Stream<Node> childNodeStream = children == null ? Stream.empty() : Stream.of(children.getNodes());
|
||||||
if (resultsNode != null) {
|
return childNodeStream
|
||||||
return resultsNode;
|
.map(childNode -> searchForCategoryNode(childNode, dataSourceId, category))
|
||||||
|
.filter(Optional::isPresent)
|
||||||
|
.map(Optional::get)
|
||||||
|
.findFirst();
|
||||||
|
} else {
|
||||||
|
DataSource dataSource = node.getLookup().lookup(DataSource.class);
|
||||||
|
// if data source node and the one we want, find the right category node.
|
||||||
|
if (dataSource != null && dataSource.getId() == dataSourceId) {
|
||||||
|
Children dsChildren = node.getChildren();
|
||||||
|
if (dsChildren != null) {
|
||||||
|
return getCategoryNodeChild(dsChildren, category);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the category node (i.e. Data Artifacts / Analysis Results) for the
|
||||||
|
* specific artifact and category.
|
||||||
|
*
|
||||||
|
* @param category The category of the artifact.
|
||||||
|
* @param art The artifact to find the relevant Results Node.
|
||||||
|
*
|
||||||
|
* @return The category node or empty.
|
||||||
|
*/
|
||||||
|
private Optional<Node> getCategoryNode(Category category, BlackboardArtifact art) {
|
||||||
|
Children rootChildren = em.getRootContext().getChildren();
|
||||||
|
Optional<Node> categoryNode = getCategoryNodeChild(rootChildren, category);
|
||||||
|
if (categoryNode.isPresent()) {
|
||||||
|
return categoryNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
long dataSourceId;
|
long dataSourceId;
|
||||||
@ -1169,17 +1205,31 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] rootNodes = rootChilds.getNodes();
|
Node[] rootNodes = rootChildren.getNodes();
|
||||||
if (rootNodes != null) {
|
Stream<Node> rootNodesStream = rootNodes == null ? Stream.empty() : Stream.of(rootNodes);
|
||||||
for (Node rootNode : rootNodes) {
|
return rootNodesStream
|
||||||
resultsNode = getResultsNodeSearch(rootNode, dataSourceId);
|
.map((rootNode) -> searchForCategoryNode(rootNode, dataSourceId, category))
|
||||||
if (resultsNode != null) {
|
.filter(Optional::isPresent)
|
||||||
return resultsNode;
|
.map(Optional::get)
|
||||||
}
|
.findFirst();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
/**
|
||||||
|
* Attempts to retrieve the artifact type for the given artifact type id.
|
||||||
|
*
|
||||||
|
* @param artifactTypeId The artifact type id.
|
||||||
|
*
|
||||||
|
* @return The artifact type if present or empty if not found.
|
||||||
|
*/
|
||||||
|
private Optional<BlackboardArtifact.Type> getType(long artifactTypeId) {
|
||||||
|
try {
|
||||||
|
return Case.getCurrentCaseThrows().getSleuthkitCase().getArtifactTypesInUse().stream()
|
||||||
|
.filter(type -> type.getTypeID() == artifactTypeId)
|
||||||
|
.findFirst();
|
||||||
|
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||||
|
LOGGER.log(Level.WARNING, "Error occurred while looking up blackboard artifact type for: " + artifactTypeId, ex);
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1196,207 +1246,34 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
|||||||
public void viewArtifact(final BlackboardArtifact art) {
|
public void viewArtifact(final BlackboardArtifact art) {
|
||||||
int typeID = art.getArtifactTypeID();
|
int typeID = art.getArtifactTypeID();
|
||||||
String typeName = art.getArtifactTypeName();
|
String typeName = art.getArtifactTypeName();
|
||||||
Node treeNode = null;
|
|
||||||
|
|
||||||
Node resultsNode = getResultsNode(art);
|
Optional<BlackboardArtifact.Type> typeOpt = getType(typeID);
|
||||||
if (resultsNode == null) {
|
Optional<Children> categoryChildrenOpt = typeOpt
|
||||||
|
.flatMap(type -> getCategoryNode(type.getCategory(), art))
|
||||||
|
.flatMap(categoryNode -> Optional.ofNullable(categoryNode.getChildren()));
|
||||||
|
|
||||||
|
if (!categoryChildrenOpt.isPresent()) {
|
||||||
|
LOGGER.log(Level.WARNING, String.format("Category node children for artifact of typeID: %d and artifactID: %d not found.",
|
||||||
|
typeID, art.getArtifactID()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Children resultsChilds = resultsNode.getChildren();
|
Children typesChildren = categoryChildrenOpt.get();
|
||||||
if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) {
|
|
||||||
Node hashsetRootNode = resultsChilds.findChild(typeName);
|
|
||||||
Children hashsetRootChilds = hashsetRootNode.getChildren();
|
|
||||||
try {
|
|
||||||
String setName = null;
|
|
||||||
List<BlackboardAttribute> attributes = art.getAttributes();
|
|
||||||
for (BlackboardAttribute att : attributes) {
|
|
||||||
int typeId = att.getAttributeType().getTypeID();
|
|
||||||
if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) {
|
|
||||||
setName = att.getValueString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
treeNode = hashsetRootChilds.findChild(setName);
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
|
|
||||||
}
|
|
||||||
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
|
|
||||||
Node keywordRootNode = resultsChilds.findChild(typeName);
|
|
||||||
Children keywordRootChilds = keywordRootNode.getChildren();
|
|
||||||
try {
|
|
||||||
String listName = null;
|
|
||||||
String keywordName = null;
|
|
||||||
String regex = null;
|
|
||||||
List<BlackboardAttribute> attributes = art.getAttributes();
|
|
||||||
for (BlackboardAttribute att : attributes) {
|
|
||||||
int typeId = att.getAttributeType().getTypeID();
|
|
||||||
if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) {
|
|
||||||
listName = att.getValueString();
|
|
||||||
} else if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) {
|
|
||||||
keywordName = att.getValueString();
|
|
||||||
} else if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID()) {
|
|
||||||
regex = att.getValueString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (listName == null) {
|
|
||||||
if (regex == null) { //using same labels used for creation
|
|
||||||
listName = NbBundle.getMessage(KeywordHits.class, "KeywordHits.simpleLiteralSearch.text");
|
|
||||||
} else {
|
|
||||||
listName = NbBundle.getMessage(KeywordHits.class, "KeywordHits.singleRegexSearch.text");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Node listNode = keywordRootChilds.findChild(listName);
|
|
||||||
if (listNode == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Children listChildren = listNode.getChildren();
|
|
||||||
if (listChildren == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (regex != null) { //For support of regex nodes such as URLs, IPs, Phone Numbers, and Email Addrs as they are down another level
|
|
||||||
Node regexNode = listChildren.findChild(regex);
|
|
||||||
if (regexNode == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
listChildren = regexNode.getChildren();
|
|
||||||
if (listChildren == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
treeNode = listChildren.findChild(keywordName);
|
Node treeNode = null;
|
||||||
|
if (typeID == BlackboardArtifact.Type.TSK_HASHSET_HIT.getTypeID()) {
|
||||||
} catch (TskCoreException ex) {
|
treeNode = getHashsetNode(typesChildren, art);
|
||||||
LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
|
} else if (typeID == BlackboardArtifact.Type.TSK_KEYWORD_HIT.getTypeID()) {
|
||||||
}
|
treeNode = getKeywordHitNode(typesChildren, art);
|
||||||
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()
|
} else if (typeID == BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID()
|
||||||
|| typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
|
|| typeID == BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
|
||||||
Node interestingItemsRootNode = resultsChilds.findChild(NbBundle
|
treeNode = getInterestingItemNode(typesChildren, art);
|
||||||
.getMessage(InterestingHits.class, "InterestingHits.interestingItems.text"));
|
} else if (typeID == BlackboardArtifact.Type.TSK_EMAIL_MSG.getTypeID()) {
|
||||||
Children interestingItemsRootChildren = interestingItemsRootNode.getChildren();
|
treeNode = getEmailNode(typesChildren, art);
|
||||||
try {
|
} else if (typeID == BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID()) {
|
||||||
String setName = null;
|
treeNode = getAccountNode(typesChildren, art);
|
||||||
List<BlackboardAttribute> 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
Children fileArtifactChildren = setNode.getChildren();
|
|
||||||
Node[] fileArtifactNodes = fileArtifactChildren == null ? null : fileArtifactChildren.getNodes();
|
|
||||||
if (fileArtifactNodes == null || fileArtifactNodes.length != 2) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
treeNode = (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID())
|
|
||||||
? fileArtifactNodes[0]
|
|
||||||
: fileArtifactNodes[1];
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
|
|
||||||
}
|
|
||||||
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) {
|
|
||||||
Node emailMsgRootNode = resultsChilds.findChild(typeName);
|
|
||||||
Children emailMsgRootChilds = emailMsgRootNode.getChildren();
|
|
||||||
Map<String, String> parsedPath = null;
|
|
||||||
try {
|
|
||||||
List<BlackboardAttribute> attributes = art.getAttributes();
|
|
||||||
for (BlackboardAttribute att : attributes) {
|
|
||||||
int typeId = att.getAttributeType().getTypeID();
|
|
||||||
if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID()) {
|
|
||||||
parsedPath = EmailExtracted.parsePath(att.getValueString());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (parsedPath == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Node defaultNode = emailMsgRootChilds.findChild(parsedPath.get(NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultAcct.text")));
|
|
||||||
Children defaultChildren = defaultNode.getChildren();
|
|
||||||
treeNode = defaultChildren.findChild(parsedPath.get(NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultFolder.text")));
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
|
|
||||||
Node accountRootNode = resultsChilds.findChild(art.getDisplayName());
|
|
||||||
Children accountRootChilds = accountRootNode.getChildren();
|
|
||||||
List<BlackboardAttribute> attributes;
|
|
||||||
String accountType = null;
|
|
||||||
String ccNumberName = null;
|
|
||||||
try {
|
|
||||||
attributes = art.getAttributes();
|
|
||||||
for (BlackboardAttribute att : attributes) {
|
|
||||||
int typeId = att.getAttributeType().getTypeID();
|
|
||||||
if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()) {
|
|
||||||
accountType = att.getValueString();
|
|
||||||
}
|
|
||||||
if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID()) {
|
|
||||||
ccNumberName = att.getValueString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (accountType == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (accountType.equals(Account.Type.CREDIT_CARD.getTypeName())) {
|
|
||||||
Node accountNode = accountRootChilds.findChild(Account.Type.CREDIT_CARD.getDisplayName());
|
|
||||||
if (accountNode == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Children accountChildren = accountNode.getChildren();
|
|
||||||
if (accountChildren == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Node binNode = accountChildren.findChild(NbBundle.getMessage(Accounts.class, "Accounts.ByBINNode.name"));
|
|
||||||
if (binNode == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Children binChildren = binNode.getChildren();
|
|
||||||
if (ccNumberName == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//right padded with 0s to 8 digits when single number
|
|
||||||
//when a range of numbers, the first 6 digits are rightpadded with 0s to 8 digits then a dash then 3 digits, the 6,7,8, digits of the end number right padded with 9s
|
|
||||||
String binName = StringUtils.rightPad(ccNumberName, 8, "0");
|
|
||||||
binName = binName.substring(0, 8);
|
|
||||||
int bin;
|
|
||||||
try {
|
|
||||||
bin = Integer.parseInt(binName);
|
|
||||||
} catch (NumberFormatException ex) {
|
|
||||||
LOGGER.log(Level.WARNING, "Unable to parseInt a BIN for node selection from string binName=" + binName, ex); //NON-NLS
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin);
|
|
||||||
if (binInfo != null) {
|
|
||||||
int startBin = ((BINRange) binInfo).getBINstart();
|
|
||||||
int endBin = ((BINRange) binInfo).getBINend();
|
|
||||||
if (startBin != endBin) {
|
|
||||||
binName = Integer.toString(startBin) + "-" + Integer.toString(endBin).substring(5); //if there is a range re-construct the name it appears as
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (binName == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
treeNode = binChildren.findChild(binName);
|
|
||||||
} else { //default account type
|
|
||||||
treeNode = accountRootChilds.findChild(accountType);
|
|
||||||
}
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Node extractedContent = resultsChilds.findChild(ExtractedContent.NAME);
|
treeNode = typesChildren.findChild(typeName);
|
||||||
Children extractedChilds = extractedContent.getChildren();
|
|
||||||
if (extractedChilds == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
treeNode = extractedChilds.findChild(typeName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (treeNode == null) {
|
if (treeNode == null) {
|
||||||
@ -1419,6 +1296,270 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
|||||||
// Another thread is needed because we have to wait for dataResult to populate
|
// Another thread is needed because we have to wait for dataResult to populate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hashset hit artifact's parent node or null if cannot be
|
||||||
|
* found.
|
||||||
|
*
|
||||||
|
* @param typesChildren The children object of the same category as hashset
|
||||||
|
* hits.
|
||||||
|
* @param art The artifact.
|
||||||
|
*
|
||||||
|
* @return The hashset hit artifact's parent node or null if cannot be
|
||||||
|
* found.
|
||||||
|
*/
|
||||||
|
private Node getHashsetNode(Children typesChildren, final BlackboardArtifact art) {
|
||||||
|
Node hashsetRootNode = typesChildren.findChild(art.getArtifactTypeName());
|
||||||
|
Children hashsetRootChilds = hashsetRootNode.getChildren();
|
||||||
|
try {
|
||||||
|
String setName = null;
|
||||||
|
List<BlackboardAttribute> attributes = art.getAttributes();
|
||||||
|
for (BlackboardAttribute att : attributes) {
|
||||||
|
int typeId = att.getAttributeType().getTypeID();
|
||||||
|
if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) {
|
||||||
|
setName = att.getValueString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hashsetRootChilds.findChild(setName);
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the keyword hit artifact's parent node or null if cannot be
|
||||||
|
* found.
|
||||||
|
*
|
||||||
|
* @param typesChildren The children object of the same category as keyword
|
||||||
|
* hits.
|
||||||
|
* @param art The artifact.
|
||||||
|
*
|
||||||
|
* @return The keyword hit artifact's parent node or null if cannot be
|
||||||
|
* found.
|
||||||
|
*/
|
||||||
|
private Node getKeywordHitNode(Children typesChildren, BlackboardArtifact art) {
|
||||||
|
Node keywordRootNode = typesChildren.findChild(art.getArtifactTypeName());
|
||||||
|
Children keywordRootChilds = keywordRootNode.getChildren();
|
||||||
|
try {
|
||||||
|
String listName = null;
|
||||||
|
String keywordName = null;
|
||||||
|
String regex = null;
|
||||||
|
List<BlackboardAttribute> attributes = art.getAttributes();
|
||||||
|
for (BlackboardAttribute att : attributes) {
|
||||||
|
int typeId = att.getAttributeType().getTypeID();
|
||||||
|
if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) {
|
||||||
|
listName = att.getValueString();
|
||||||
|
} else if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) {
|
||||||
|
keywordName = att.getValueString();
|
||||||
|
} else if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID()) {
|
||||||
|
regex = att.getValueString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (listName == null) {
|
||||||
|
if (regex == null) { //using same labels used for creation
|
||||||
|
listName = NbBundle.getMessage(KeywordHits.class, "KeywordHits.simpleLiteralSearch.text");
|
||||||
|
} else {
|
||||||
|
listName = NbBundle.getMessage(KeywordHits.class, "KeywordHits.singleRegexSearch.text");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Node listNode = keywordRootChilds.findChild(listName);
|
||||||
|
if (listNode == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Children listChildren = listNode.getChildren();
|
||||||
|
if (listChildren == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (regex != null) { //For support of regex nodes such as URLs, IPs, Phone Numbers, and Email Addrs as they are down another level
|
||||||
|
Node regexNode = listChildren.findChild(listName);
|
||||||
|
regexNode = (regexNode == null) ? listChildren.findChild(listName + "_" + regex) : regexNode;
|
||||||
|
if (regexNode == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
listChildren = regexNode.getChildren();
|
||||||
|
if (listChildren == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return listChildren.findChild(keywordName);
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the interesting item artifact's parent node or null if cannot be
|
||||||
|
* found.
|
||||||
|
*
|
||||||
|
* @param typesChildren The children object of the same category as
|
||||||
|
* interesting item.
|
||||||
|
* @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();
|
||||||
|
try {
|
||||||
|
String setName = null;
|
||||||
|
List<BlackboardAttribute> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the email artifact's parent node or null if cannot be found.
|
||||||
|
*
|
||||||
|
* @param typesChildren The children object of the same category as email.
|
||||||
|
* @param art The artifact.
|
||||||
|
*
|
||||||
|
* @return The email artifact's parent node or null if cannot be found.
|
||||||
|
*/
|
||||||
|
private Node getEmailNode(Children typesChildren, BlackboardArtifact art) {
|
||||||
|
Node emailMsgRootNode = typesChildren.findChild(art.getArtifactTypeName());
|
||||||
|
Children emailMsgRootChilds = emailMsgRootNode.getChildren();
|
||||||
|
Map<String, String> parsedPath = null;
|
||||||
|
try {
|
||||||
|
List<BlackboardAttribute> attributes = art.getAttributes();
|
||||||
|
for (BlackboardAttribute att : attributes) {
|
||||||
|
int typeId = att.getAttributeType().getTypeID();
|
||||||
|
if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID()) {
|
||||||
|
parsedPath = EmailExtracted.parsePath(att.getValueString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (parsedPath == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Node defaultNode = emailMsgRootChilds.findChild(parsedPath.get(NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultAcct.text")));
|
||||||
|
Children defaultChildren = defaultNode.getChildren();
|
||||||
|
return defaultChildren.findChild(parsedPath.get(NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultFolder.text")));
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the account artifact's parent node or null if cannot be found.
|
||||||
|
*
|
||||||
|
* @param typesChildren The children object of the same category as the
|
||||||
|
* account.
|
||||||
|
* @param art The artifact.
|
||||||
|
*
|
||||||
|
* @return The account artifact's parent node or null if cannot be found.
|
||||||
|
*/
|
||||||
|
private Node getAccountNode(Children typesChildren, BlackboardArtifact art) {
|
||||||
|
Node accountRootNode = typesChildren.findChild(art.getDisplayName());
|
||||||
|
Children accountRootChilds = accountRootNode.getChildren();
|
||||||
|
List<BlackboardAttribute> attributes;
|
||||||
|
String accountType = null;
|
||||||
|
String ccNumberName = null;
|
||||||
|
try {
|
||||||
|
attributes = art.getAttributes();
|
||||||
|
for (BlackboardAttribute att : attributes) {
|
||||||
|
int typeId = att.getAttributeType().getTypeID();
|
||||||
|
if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()) {
|
||||||
|
accountType = att.getValueString();
|
||||||
|
}
|
||||||
|
if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID()) {
|
||||||
|
ccNumberName = att.getValueString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (accountType == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accountType.equals(Account.Type.CREDIT_CARD.getTypeName())) {
|
||||||
|
return getCreditCardAccountNode(accountRootChilds, ccNumberName);
|
||||||
|
} else { //default account type
|
||||||
|
return accountRootChilds.findChild(accountType);
|
||||||
|
}
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the credit card artifact's parent node or null if cannot be
|
||||||
|
* found.
|
||||||
|
*
|
||||||
|
* @param typesChildren The children object of the same category as credit
|
||||||
|
* card.
|
||||||
|
* @param art The artifact.
|
||||||
|
*
|
||||||
|
* @return The credit card artifact's parent node or null if cannot be
|
||||||
|
* found.
|
||||||
|
*/
|
||||||
|
private Node getCreditCardAccountNode(Children accountRootChildren, String ccNumberName) {
|
||||||
|
Node accountNode = accountRootChildren.findChild(Account.Type.CREDIT_CARD.getDisplayName());
|
||||||
|
if (accountNode == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Children accountChildren = accountNode.getChildren();
|
||||||
|
if (accountChildren == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Node binNode = accountChildren.findChild(NbBundle.getMessage(Accounts.class, "Accounts.ByBINNode.name"));
|
||||||
|
if (binNode == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Children binChildren = binNode.getChildren();
|
||||||
|
if (ccNumberName == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
//right padded with 0s to 8 digits when single number
|
||||||
|
//when a range of numbers, the first 6 digits are rightpadded with 0s to 8 digits then a dash then 3 digits, the 6,7,8, digits of the end number right padded with 9s
|
||||||
|
String binName = StringUtils.rightPad(ccNumberName, 8, "0");
|
||||||
|
binName = binName.substring(0, 8);
|
||||||
|
int bin;
|
||||||
|
try {
|
||||||
|
bin = Integer.parseInt(binName);
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
LOGGER.log(Level.WARNING, "Unable to parseInt a BIN for node selection from string binName=" + binName, ex); //NON-NLS
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin);
|
||||||
|
if (binInfo != null) {
|
||||||
|
int startBin = ((BINRange) binInfo).getBINstart();
|
||||||
|
int endBin = ((BINRange) binInfo).getBINend();
|
||||||
|
if (startBin != endBin) {
|
||||||
|
binName = Integer.toString(startBin) + "-" + Integer.toString(endBin).substring(5); //if there is a range re-construct the name it appears as
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (binName == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return binChildren.findChild(binName);
|
||||||
|
}
|
||||||
|
|
||||||
public void viewArtifactContent(BlackboardArtifact art) {
|
public void viewArtifactContent(BlackboardArtifact art) {
|
||||||
new ViewContextAction(
|
new ViewContextAction(
|
||||||
NbBundle.getMessage(this.getClass(), "DirectoryTreeTopComponent.action.viewArtContent.text"),
|
NbBundle.getMessage(this.getClass(), "DirectoryTreeTopComponent.action.viewArtContent.text"),
|
||||||
|
BIN
Core/src/org/sleuthkit/autopsy/images/analysis_result.png
Normal file
BIN
Core/src/org/sleuthkit/autopsy/images/analysis_result.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 443 B |
Loading…
x
Reference in New Issue
Block a user