mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-17 18:17:43 +00:00
Converted DeletedContent, ExtractedContent, FileSize, FileTypesByExtension, FileTypesByMimeType, HashsetHits, InterestingHits and KeywordHits to new child factory approach that supports paging.
This commit is contained in:
parent
f54c9aa2ff
commit
c4e81f2ea2
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Copyright 2011-2019 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -39,7 +39,6 @@ import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
@ -358,7 +357,7 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
}
|
||||
}
|
||||
|
||||
static class DeletedContentChildren extends ChildFactory.Detachable<AbstractFile> {
|
||||
static class DeletedContentChildren extends BaseChildFactory<AbstractFile> {
|
||||
|
||||
private final SleuthkitCase skCase;
|
||||
private final DeletedContent.DeletedContentFilter filter;
|
||||
@ -368,6 +367,7 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
private final long datasourceObjId;
|
||||
|
||||
DeletedContentChildren(DeletedContent.DeletedContentFilter filter, SleuthkitCase skCase, Observable o, long datasourceObjId) {
|
||||
super(filter.getName());
|
||||
this.skCase = skCase;
|
||||
this.filter = filter;
|
||||
this.notifier = o;
|
||||
@ -376,6 +376,11 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
|
||||
private final Observer observer = new DeletedContentChildrenObserver();
|
||||
|
||||
@Override
|
||||
protected List<AbstractFile> makeKeys() {
|
||||
return runFsQuery();
|
||||
}
|
||||
|
||||
// Cause refresh of children if there are changes
|
||||
private class DeletedContentChildrenObserver implements Observer {
|
||||
|
||||
@ -386,25 +391,19 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addNotify() {
|
||||
protected void onAdd() {
|
||||
if (notifier != null) {
|
||||
notifier.addObserver(observer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeNotify() {
|
||||
protected void onRemove() {
|
||||
if (notifier != null) {
|
||||
notifier.deleteObserver(observer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<AbstractFile> list) {
|
||||
list.addAll(runFsQuery());
|
||||
return true;
|
||||
}
|
||||
|
||||
static private String makeQuery(DeletedContent.DeletedContentFilter filter, long filteringDSObjId) {
|
||||
String query = "";
|
||||
switch (filter) {
|
||||
@ -440,11 +439,6 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
|
||||
}
|
||||
|
||||
if (UserPreferences.hideKnownFilesInViewsTree()) {
|
||||
query += " AND (known != " + TskData.FileKnown.KNOWN.getFileKnownValue() //NON-NLS
|
||||
+ " OR known IS NULL)"; //NON-NLS
|
||||
}
|
||||
|
||||
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
|
||||
query += " AND data_source_obj_id = " + filteringDSObjId;
|
||||
}
|
||||
|
@ -423,12 +423,12 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
||||
/**
|
||||
* Creates children for a given artifact type
|
||||
*/
|
||||
private class ArtifactFactory extends ChildFactory.Detachable<BlackboardArtifact> {
|
||||
private class ArtifactFactory extends BaseChildFactory<BlackboardArtifact> {
|
||||
|
||||
private BlackboardArtifact.Type type;
|
||||
|
||||
public ArtifactFactory(BlackboardArtifact.Type type) {
|
||||
super();
|
||||
super(type.getTypeName());
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@ -481,36 +481,36 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void addNotify() {
|
||||
protected void onAdd() {
|
||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeNotify() {
|
||||
protected void onRemove() {
|
||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<BlackboardArtifact> list) {
|
||||
if (skCase != null) {
|
||||
try {
|
||||
List<BlackboardArtifact> arts =
|
||||
Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) ?
|
||||
blackboard.getArtifacts(type.getTypeID(), datasourceObjId) :
|
||||
skCase.getBlackboardArtifacts(type.getTypeID());
|
||||
list.addAll(arts);
|
||||
} catch (TskException ex) {
|
||||
Logger.getLogger(ArtifactFactory.class.getName()).log(Level.SEVERE, "Couldn't get blackboard artifacts from database", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(BlackboardArtifact key) {
|
||||
return new BlackboardArtifactNode(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<BlackboardArtifact> makeKeys() {
|
||||
if (skCase != null) {
|
||||
try {
|
||||
List<BlackboardArtifact> arts =
|
||||
Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true) ?
|
||||
blackboard.getArtifacts(type.getTypeID(), datasourceObjId) :
|
||||
skCase.getBlackboardArtifacts(type.getTypeID());
|
||||
return arts;
|
||||
} catch (TskException ex) {
|
||||
Logger.getLogger(ArtifactFactory.class.getName()).log(Level.SEVERE, "Couldn't get blackboard artifacts from database", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-2018 Basis Technology Corp.
|
||||
* Copyright 2013-2019 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -361,7 +361,7 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
/*
|
||||
* Makes children, which are nodes for files of a given range
|
||||
*/
|
||||
static class FileSizeChildren extends ChildFactory.Detachable<AbstractFile> {
|
||||
static class FileSizeChildren extends BaseChildFactory<AbstractFile> {
|
||||
|
||||
private final SleuthkitCase skCase;
|
||||
private final FileSizeFilter filter;
|
||||
@ -377,6 +377,7 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
* added to case
|
||||
*/
|
||||
FileSizeChildren(FileSizeFilter filter, SleuthkitCase skCase, Observable o, long dsObjId) {
|
||||
super(filter.getName());
|
||||
this.skCase = skCase;
|
||||
this.filter = filter;
|
||||
this.notifier = o;
|
||||
@ -385,14 +386,14 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addNotify() {
|
||||
protected void onAdd() {
|
||||
if (notifier != null) {
|
||||
notifier.addObserver(observer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeNotify() {
|
||||
protected void onRemove() {
|
||||
if (notifier != null) {
|
||||
notifier.deleteObserver(observer);
|
||||
}
|
||||
@ -400,6 +401,11 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
|
||||
private final Observer observer = new FileSizeChildrenObserver();
|
||||
|
||||
@Override
|
||||
protected List<AbstractFile> makeKeys() {
|
||||
return runFsQuery();
|
||||
}
|
||||
|
||||
// Cause refresh of children if there are changes
|
||||
private class FileSizeChildrenObserver implements Observer {
|
||||
|
||||
@ -409,12 +415,6 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<AbstractFile> list) {
|
||||
list.addAll(runFsQuery());
|
||||
return true;
|
||||
}
|
||||
|
||||
private static String makeQuery(FileSizeFilter filter, long filteringDSObjId) {
|
||||
String query;
|
||||
switch (filter) {
|
||||
@ -436,17 +436,6 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
// Ignore unallocated block files.
|
||||
query = query + " AND (type != " + TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType() + ")"; //NON-NLS
|
||||
|
||||
// Hide known files if indicated in the user preferences.
|
||||
if(UserPreferences.hideKnownFilesInViewsTree()) {
|
||||
query += " AND (known != " + TskData.FileKnown.KNOWN.getFileKnownValue() //NON-NLS
|
||||
+ " OR known IS NULL)"; //NON-NLS
|
||||
}
|
||||
|
||||
// Hide slack files if indicated in the user preferences.
|
||||
if(UserPreferences.hideSlackFilesInViewsTree()) {
|
||||
query += " AND (type != " + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType() + ")"; //NON-NLS
|
||||
}
|
||||
|
||||
// filter by datasource if indicated in case preferences
|
||||
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
|
||||
query += " AND data_source_obj_id = " + filteringDSObjId;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Copyright 2011-2019 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@ -292,7 +293,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
||||
* should refresh
|
||||
*/
|
||||
FileExtensionNode(FileTypesByExtension.SearchFilterInterface filter, SleuthkitCase skCase, FileTypesByExtObservable o) {
|
||||
super(typesRoot, Children.create(new FileExtensionNodeChildren(filter, skCase, o), true),
|
||||
super(typesRoot, Children.create(new FileExtensionNodeChildren(filter, skCase, o, filter.getDisplayName()), true),
|
||||
Lookups.singleton(filter.getDisplayName()));
|
||||
this.filter = filter;
|
||||
super.setName(filter.getDisplayName());
|
||||
@ -377,7 +378,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
||||
/**
|
||||
* Child node factory for a specific file type - does the database query.
|
||||
*/
|
||||
private class FileExtensionNodeChildren extends ChildFactory.Detachable<FileTypesKey> implements Observer {
|
||||
private class FileExtensionNodeChildren extends BaseChildFactory<FileTypesKey> implements Observer {
|
||||
|
||||
private final SleuthkitCase skCase;
|
||||
private final FileTypesByExtension.SearchFilterInterface filter;
|
||||
@ -390,22 +391,22 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
||||
* @param o Observable that will notify when there could be new
|
||||
* data to display
|
||||
*/
|
||||
private FileExtensionNodeChildren(FileTypesByExtension.SearchFilterInterface filter, SleuthkitCase skCase, Observable o) {
|
||||
super();
|
||||
private FileExtensionNodeChildren(FileTypesByExtension.SearchFilterInterface filter, SleuthkitCase skCase, Observable o, String nodeName) {
|
||||
super(nodeName);
|
||||
this.filter = filter;
|
||||
this.skCase = skCase;
|
||||
notifier = o;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addNotify() {
|
||||
protected void onAdd() {
|
||||
if (notifier != null) {
|
||||
notifier.addObserver(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeNotify() {
|
||||
protected void onRemove() {
|
||||
if (notifier != null) {
|
||||
notifier.deleteObserver(this);
|
||||
}
|
||||
@ -417,19 +418,19 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<FileTypesKey> list) {
|
||||
try {
|
||||
list.addAll(skCase.findAllFilesWhere(createQuery(filter))
|
||||
.stream().map(f -> new FileTypesKey(f)).collect(Collectors.toList()));
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS
|
||||
}
|
||||
return true;
|
||||
protected Node createNodeForKey(FileTypesKey key) {
|
||||
return key.accept(new FileTypes.FileNodeCreationVisitor());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(FileTypesKey key) {
|
||||
return key.accept(new FileTypes.FileNodeCreationVisitor());
|
||||
protected List<FileTypesKey> makeKeys() {
|
||||
try {
|
||||
return skCase.findAllFilesWhere(createQuery(filter))
|
||||
.stream().map(f -> new FileTypesKey(f)).collect(Collectors.toList());
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Copyright 2011-2019 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -445,27 +445,16 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
* files that match MimeType which is represented by this position in the
|
||||
* tree.
|
||||
*/
|
||||
private class MediaSubTypeNodeChildren extends ChildFactory.Detachable<FileTypesKey> implements Observer {
|
||||
private class MediaSubTypeNodeChildren extends BaseChildFactory<FileTypesKey> implements Observer {
|
||||
|
||||
private final String mimeType;
|
||||
|
||||
private MediaSubTypeNodeChildren(String mimeType) {
|
||||
super();
|
||||
super(mimeType);
|
||||
addObserver(this);
|
||||
this.mimeType = mimeType;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<FileTypesKey> list) {
|
||||
try {
|
||||
list.addAll(skCase.findAllFilesWhere(createBaseWhereExpr() + " AND mime_type = '" + mimeType + "'")
|
||||
.stream().map(f -> new FileTypesKey(f)).collect(Collectors.toList())); //NON-NLS
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Observable o, Object arg) {
|
||||
refresh(true);
|
||||
@ -475,5 +464,26 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
protected Node createNodeForKey(FileTypesKey key) {
|
||||
return key.accept(new FileTypes.FileNodeCreationVisitor());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<FileTypesKey> makeKeys() {
|
||||
try {
|
||||
return skCase.findAllFilesWhere(createBaseWhereExpr() + " AND mime_type = '" + mimeType + "'")
|
||||
.stream().map(f -> new FileTypesKey(f)).collect(Collectors.toList()); //NON-NLS
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAdd() {
|
||||
// No-op
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRemove() {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Copyright 2011-2019 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -35,6 +35,7 @@ import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
@ -44,7 +45,6 @@ import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||
@ -378,60 +378,53 @@ public class HashsetHits implements AutopsyVisitableItem {
|
||||
/**
|
||||
* Creates the nodes for the hits in a given set.
|
||||
*/
|
||||
private class HitFactory extends ChildFactory.Detachable<Long> implements Observer {
|
||||
private class HitFactory extends BaseChildFactory<BlackboardArtifact> implements Observer {
|
||||
|
||||
private String hashsetName;
|
||||
private Map<Long, BlackboardArtifact> artifactHits = new HashMap<>();
|
||||
|
||||
private HitFactory(String hashsetName) {
|
||||
super();
|
||||
super(hashsetName);
|
||||
this.hashsetName = hashsetName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addNotify() {
|
||||
protected void onAdd() {
|
||||
hashsetResults.addObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeNotify() {
|
||||
protected void onRemove() {
|
||||
hashsetResults.deleteObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<Long> list) {
|
||||
|
||||
if (skCase == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
hashsetResults.getArtifactIds(hashsetName).forEach((id) -> {
|
||||
try {
|
||||
if (!artifactHits.containsKey(id)) {
|
||||
BlackboardArtifact art = skCase.getBlackboardArtifact(id);
|
||||
artifactHits.put(id, art);
|
||||
}
|
||||
} catch (TskException ex) {
|
||||
logger.log(Level.SEVERE, "TSK Exception occurred", ex); //NON-NLS
|
||||
}
|
||||
});
|
||||
|
||||
// Adding all keys at once is more efficient than adding one at a
|
||||
// time because Netbeans triggers internal processing each time an
|
||||
// element is added to the list.
|
||||
list.addAll(artifactHits.keySet());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(Long id) {
|
||||
BlackboardArtifact art = artifactHits.get(id);
|
||||
return (null == art) ? null : new BlackboardArtifactNode(art);
|
||||
protected Node createNodeForKey(BlackboardArtifact key) {
|
||||
return new BlackboardArtifactNode(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Observable o, Object arg) {
|
||||
refresh(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<BlackboardArtifact> makeKeys() {
|
||||
if (skCase != null) {
|
||||
|
||||
hashsetResults.getArtifactIds(hashsetName).forEach((id) -> {
|
||||
try {
|
||||
if (!artifactHits.containsKey(id)) {
|
||||
BlackboardArtifact art = skCase.getBlackboardArtifact(id);
|
||||
artifactHits.put(id, art);
|
||||
}
|
||||
} catch (TskException ex) {
|
||||
logger.log(Level.SEVERE, "TSK Exception occurred", ex); //NON-NLS
|
||||
}
|
||||
});
|
||||
return new ArrayList<>(artifactHits.values());
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Copyright 2011-2019 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -449,51 +449,57 @@ public class InterestingHits implements AutopsyVisitableItem {
|
||||
}
|
||||
}
|
||||
|
||||
private class HitFactory extends ChildFactory<Long> implements Observer {
|
||||
private class HitFactory extends BaseChildFactory<BlackboardArtifact> implements Observer {
|
||||
|
||||
private final String setName;
|
||||
private final String typeName;
|
||||
private final Map<Long, BlackboardArtifact> artifactHits = new HashMap<>();
|
||||
|
||||
private HitFactory(String setName, String typeName) {
|
||||
super();
|
||||
super(typeName);
|
||||
this.setName = setName;
|
||||
this.typeName = typeName;
|
||||
interestingResults.addObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<Long> list) {
|
||||
protected List<BlackboardArtifact> makeKeys() {
|
||||
|
||||
if (skCase == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
interestingResults.getArtifactIds(setName, typeName).forEach((id) -> {
|
||||
try {
|
||||
if (!artifactHits.containsKey(id)) {
|
||||
BlackboardArtifact art = skCase.getBlackboardArtifact(id);
|
||||
artifactHits.put(id, art);
|
||||
if (skCase != null) {
|
||||
interestingResults.getArtifactIds(setName, typeName).forEach((id) -> {
|
||||
try {
|
||||
if (!artifactHits.containsKey(id)) {
|
||||
BlackboardArtifact art = skCase.getBlackboardArtifact(id);
|
||||
artifactHits.put(id, art);
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "TSK Exception occurred", ex); //NON-NLS
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "TSK Exception occurred", ex); //NON-NLS
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
list.addAll(artifactHits.keySet());
|
||||
|
||||
return true;
|
||||
return new ArrayList<>(artifactHits.values());
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(Long l) {
|
||||
BlackboardArtifact art = artifactHits.get(l);
|
||||
return (null == art) ? null : new BlackboardArtifactNode(art);
|
||||
protected Node createNodeForKey(BlackboardArtifact art) {
|
||||
return new BlackboardArtifactNode(art);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Observable o, Object arg) {
|
||||
refresh(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAdd() {
|
||||
// No-op
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRemove() {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Copyright 2011-2019 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -25,6 +25,7 @@ import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@ -34,7 +35,6 @@ import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
@ -46,7 +46,6 @@ import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import static org.sleuthkit.autopsy.datamodel.Bundle.*;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
@ -85,7 +84,6 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
*/
|
||||
private static final String DEFAULT_INSTANCE_NAME = "DEFAULT_INSTANCE_NAME";
|
||||
|
||||
|
||||
/**
|
||||
* query attributes table for the ones that we need for the tree
|
||||
*/
|
||||
@ -108,20 +106,20 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param skCase Case DB
|
||||
*/
|
||||
*
|
||||
* @param skCase Case DB
|
||||
*/
|
||||
KeywordHits(SleuthkitCase skCase) {
|
||||
this(skCase, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param skCase Case DB
|
||||
* @param objId Object id of the data source
|
||||
*
|
||||
*/
|
||||
*
|
||||
* @param skCase Case DB
|
||||
* @param objId Object id of the data source
|
||||
*
|
||||
*/
|
||||
public KeywordHits(SleuthkitCase skCase, long objId) {
|
||||
this.skCase = skCase;
|
||||
this.datasourceObjId = objId;
|
||||
@ -324,9 +322,9 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
|
||||
String queryStr = KEYWORD_HIT_ATTRIBUTES_QUERY;
|
||||
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
|
||||
queryStr += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId;
|
||||
queryStr += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId;
|
||||
}
|
||||
|
||||
|
||||
try (CaseDbQuery dbQuery = skCase.executeQuery(queryStr)) {
|
||||
ResultSet resultSet = dbQuery.getResultSet();
|
||||
while (resultSet.next()) {
|
||||
@ -530,7 +528,7 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
final void updateDisplayName() {
|
||||
super.setDisplayName(getName() + " (" + countTotalDescendants() + ")");
|
||||
super.setDisplayName(getDisplayName() + " (" + countTotalDescendants() + ")");
|
||||
}
|
||||
|
||||
abstract int countTotalDescendants();
|
||||
@ -631,6 +629,24 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ChildFactory object for the given set name and keyword.
|
||||
*
|
||||
* The type of ChildFactory we create is based on whether the node
|
||||
* represents a regular expression keyword search or not. For regular
|
||||
* expression keyword searches there will be an extra layer in the tree that
|
||||
* represents each of the individual terms found by the regular expression.
|
||||
* E.g., for an email regular expression search there will be a node in the
|
||||
* tree for every email address hit.
|
||||
*/
|
||||
ChildFactory<?> createChildFactory(String setName, String keyword) {
|
||||
if (isOnlyDefaultInstance(keywordResults.getKeywordInstances(setName, keyword))) {
|
||||
return new HitsFactory(setName, keyword, DEFAULT_INSTANCE_NAME);
|
||||
} else {
|
||||
return new RegExpInstancesFactory(setName, keyword);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the search term or regexp that user searched for
|
||||
*/
|
||||
@ -640,8 +656,17 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
private final String keyword;
|
||||
|
||||
private TermNode(String setName, String keyword) {
|
||||
super(Children.create(new RegExpInstancesFactory(setName, keyword), true), Lookups.singleton(keyword));
|
||||
super.setName(keyword);
|
||||
super(Children.create(createChildFactory(setName, keyword), true), Lookups.singleton(keyword));
|
||||
|
||||
super.setDisplayName(keyword);
|
||||
/**
|
||||
* We differentiate between the programmatic name and the display
|
||||
* name. The programmatic name is used to create an association with
|
||||
* an event bus and must be the same as the node name passed by our
|
||||
* ChildFactory to it's parent constructor. See the HitsFactory
|
||||
* constructor for an example.
|
||||
*/
|
||||
super.setName(setName + "_" + keyword);
|
||||
this.setName = setName;
|
||||
this.keyword = keyword;
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS
|
||||
@ -694,45 +719,11 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows us to pass in either longs or strings as they keys for different
|
||||
* types of nodes at the same level. Probably a better way to do this, but
|
||||
* it works.
|
||||
*/
|
||||
private class RegExpInstanceKey {
|
||||
|
||||
private final boolean isRegExp;
|
||||
private String strKey;
|
||||
private Long longKey;
|
||||
|
||||
RegExpInstanceKey(String key) {
|
||||
isRegExp = true;
|
||||
strKey = key;
|
||||
}
|
||||
|
||||
RegExpInstanceKey(Long key) {
|
||||
isRegExp = false;
|
||||
longKey = key;
|
||||
}
|
||||
|
||||
boolean isRegExp() {
|
||||
return isRegExp;
|
||||
}
|
||||
|
||||
Long getIdKey() {
|
||||
return longKey;
|
||||
}
|
||||
|
||||
String getRegExpKey() {
|
||||
return strKey;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the nodes for a given regexp that represent the specific terms
|
||||
* that were found
|
||||
*/
|
||||
private class RegExpInstancesFactory extends DetachableObserverChildFactory<RegExpInstanceKey> {
|
||||
private class RegExpInstancesFactory extends DetachableObserverChildFactory<String> {
|
||||
|
||||
private final String keyword;
|
||||
private final String setName;
|
||||
@ -744,33 +735,15 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<RegExpInstanceKey> list) {
|
||||
List<String> instances = keywordResults.getKeywordInstances(setName, keyword);
|
||||
// The keys are different depending on what we are displaying.
|
||||
// regexp get another layer to show instances.
|
||||
// Exact/substring matches don't.
|
||||
if (isOnlyDefaultInstance(instances)) {
|
||||
list.addAll(keywordResults.getArtifactIds(setName, keyword, DEFAULT_INSTANCE_NAME).stream()
|
||||
.map(RegExpInstanceKey::new)
|
||||
.collect(Collectors.toList()));
|
||||
} else {
|
||||
list.addAll(instances.stream()
|
||||
.map(RegExpInstanceKey::new)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
protected boolean createKeys(List<String> list) {
|
||||
list.addAll(keywordResults.getKeywordInstances(setName, keyword));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(RegExpInstanceKey key) {
|
||||
if (key.isRegExp()) {
|
||||
return new RegExpInstanceNode(setName, keyword, key.getRegExpKey());
|
||||
} else {
|
||||
// if it isn't a regexp, then skip the 'instance' layer of the tree
|
||||
return createBlackboardArtifactNode(key.getIdKey());
|
||||
}
|
||||
protected Node createNodeForKey(String key) {
|
||||
return new RegExpInstanceNode(setName, keyword, key);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -784,7 +757,15 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
|
||||
private RegExpInstanceNode(String setName, String keyword, String instance) {
|
||||
super(Children.create(new HitsFactory(setName, keyword, instance), true), Lookups.singleton(instance));
|
||||
super.setName(instance); //the instance represents the name of the keyword hit at this point as the keyword is the regex
|
||||
super.setDisplayName(instance); //the instance represents the name of the keyword hit at this point as the keyword is the regex
|
||||
/**
|
||||
* We differentiate between the programmatic name and the display
|
||||
* name. The programmatic name is used to create an association with
|
||||
* an event bus and must be the same as the node name passed by our
|
||||
* ChildFactory to it's parent constructor. See the HitsFactory
|
||||
* constructor for an example.
|
||||
*/
|
||||
super.setName(setName + "_" + keyword + "_" + instance);
|
||||
this.setName = setName;
|
||||
this.keyword = keyword;
|
||||
this.instance = instance;
|
||||
@ -837,7 +818,7 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
/**
|
||||
* Create a blackboard node for the given Keyword Hit artifact
|
||||
*
|
||||
* @param artifactId
|
||||
* @param art
|
||||
*
|
||||
* @return Node or null on error
|
||||
*/
|
||||
@ -850,81 +831,110 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
"KeywordHits.createNodeForKey.chgTime.name=ChangeTime",
|
||||
"KeywordHits.createNodeForKey.chgTime.displayName=Change Time",
|
||||
"KeywordHits.createNodeForKey.chgTime.desc=Change Time"})
|
||||
private BlackboardArtifactNode createBlackboardArtifactNode(Long artifactId) {
|
||||
private BlackboardArtifactNode createBlackboardArtifactNode(BlackboardArtifact art) {
|
||||
if (skCase == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
BlackboardArtifact art = skCase.getBlackboardArtifact(artifactId);
|
||||
BlackboardArtifactNode n = new BlackboardArtifactNode(art);
|
||||
// The associated file should be available through the Lookup that
|
||||
// gets created when the BlackboardArtifactNode is constructed.
|
||||
AbstractFile file = n.getLookup().lookup(AbstractFile.class);
|
||||
if (file == null) {
|
||||
try {
|
||||
file = skCase.getAbstractFileById(art.getObjectID());
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "TskCoreException while constructing BlackboardArtifact Node from KeywordHitsKeywordChildren", ex); //NON-NLS
|
||||
return n;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* It is possible to get a keyword hit on artifacts generated for
|
||||
* the underlying image in which case MAC times are not
|
||||
* available/applicable/useful.
|
||||
*/
|
||||
if (file == null) {
|
||||
BlackboardArtifactNode n = new BlackboardArtifactNode(art); //NON-NLS
|
||||
|
||||
// The associated file should be available through the Lookup that
|
||||
// gets created when the BlackboardArtifactNode is constructed.
|
||||
AbstractFile file = n.getLookup().lookup(AbstractFile.class);
|
||||
if (file == null) {
|
||||
try {
|
||||
file = skCase.getAbstractFileById(art.getObjectID());
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "TskCoreException while constructing BlackboardArtifact Node from KeywordHitsKeywordChildren", ex); //NON-NLS
|
||||
return n;
|
||||
}
|
||||
|
||||
n.addNodeProperty(new NodeProperty<>(
|
||||
KeywordHits_createNodeForKey_modTime_name(),
|
||||
KeywordHits_createNodeForKey_modTime_displayName(),
|
||||
KeywordHits_createNodeForKey_modTime_desc(),
|
||||
ContentUtils.getStringTime(file.getMtime(), file)));
|
||||
n.addNodeProperty(new NodeProperty<>(
|
||||
KeywordHits_createNodeForKey_accessTime_name(),
|
||||
KeywordHits_createNodeForKey_accessTime_displayName(),
|
||||
KeywordHits_createNodeForKey_accessTime_desc(),
|
||||
ContentUtils.getStringTime(file.getAtime(), file)));
|
||||
n.addNodeProperty(new NodeProperty<>(
|
||||
KeywordHits_createNodeForKey_chgTime_name(),
|
||||
KeywordHits_createNodeForKey_chgTime_displayName(),
|
||||
KeywordHits_createNodeForKey_chgTime_desc(),
|
||||
ContentUtils.getStringTime(file.getCtime(), file)));
|
||||
return n;
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "TSK Exception occurred", ex); //NON-NLS
|
||||
}
|
||||
return null;
|
||||
/*
|
||||
* It is possible to get a keyword hit on artifacts generated for the
|
||||
* underlying image in which case MAC times are not
|
||||
* available/applicable/useful.
|
||||
*/
|
||||
if (file == null) {
|
||||
return n;
|
||||
}
|
||||
n.addNodeProperty(new NodeProperty<>(
|
||||
KeywordHits_createNodeForKey_modTime_name(),
|
||||
KeywordHits_createNodeForKey_modTime_displayName(),
|
||||
KeywordHits_createNodeForKey_modTime_desc(),
|
||||
ContentUtils.getStringTime(file.getMtime(), file)));
|
||||
n.addNodeProperty(new NodeProperty<>(
|
||||
KeywordHits_createNodeForKey_accessTime_name(),
|
||||
KeywordHits_createNodeForKey_accessTime_displayName(),
|
||||
KeywordHits_createNodeForKey_accessTime_desc(),
|
||||
ContentUtils.getStringTime(file.getAtime(), file)));
|
||||
n.addNodeProperty(new NodeProperty<>(
|
||||
KeywordHits_createNodeForKey_chgTime_name(),
|
||||
KeywordHits_createNodeForKey_chgTime_displayName(),
|
||||
KeywordHits_createNodeForKey_chgTime_desc(),
|
||||
ContentUtils.getStringTime(file.getCtime(), file)));
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates nodes for individual files that had hits
|
||||
*/
|
||||
private class HitsFactory extends DetachableObserverChildFactory<Long> {
|
||||
private class HitsFactory extends BaseChildFactory<BlackboardArtifact> implements Observer {
|
||||
|
||||
private final String keyword;
|
||||
private final String setName;
|
||||
private final String instance;
|
||||
private final Map<Long, BlackboardArtifact> artifactHits = new HashMap<>();
|
||||
|
||||
private HitsFactory(String setName, String keyword, String instance) {
|
||||
super();
|
||||
/**
|
||||
* The node name passed to the parent constructor will consist of
|
||||
* the set name, keyword and optionally the instance name (in the
|
||||
* case of regular expression hits. This name must match the name
|
||||
* set in the TermNode or RegExpInstanceNode constructors.
|
||||
*/
|
||||
super(setName + "_" + keyword + (DEFAULT_INSTANCE_NAME.equals(instance) ? "" : "_" + instance));
|
||||
this.setName = setName;
|
||||
this.keyword = keyword;
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<Long> list) {
|
||||
list.addAll(keywordResults.getArtifactIds(setName, keyword, instance));
|
||||
return true;
|
||||
protected List<BlackboardArtifact> makeKeys() {
|
||||
if (skCase != null) {
|
||||
keywordResults.getArtifactIds(setName, keyword, instance).forEach((id) -> {
|
||||
try {
|
||||
if (!artifactHits.containsKey(id)) {
|
||||
BlackboardArtifact art = skCase.getBlackboardArtifact(id);
|
||||
artifactHits.put(id, art);
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "TSK Exception occurred", ex); //NON-NLS
|
||||
}
|
||||
});
|
||||
|
||||
return new ArrayList<>(artifactHits.values());
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(Long artifactId) {
|
||||
return createBlackboardArtifactNode(artifactId);
|
||||
protected Node createNodeForKey(BlackboardArtifact art) {
|
||||
return createBlackboardArtifactNode(art);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAdd() {
|
||||
keywordResults.addObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRemove() {
|
||||
keywordResults.deleteObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Observable o, Object arg) {
|
||||
refresh(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user