mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-18 10:37: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
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
* Copyright 2011-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* 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.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
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 SleuthkitCase skCase;
|
||||||
private final DeletedContent.DeletedContentFilter filter;
|
private final DeletedContent.DeletedContentFilter filter;
|
||||||
@ -368,6 +367,7 @@ public class DeletedContent implements AutopsyVisitableItem {
|
|||||||
private final long datasourceObjId;
|
private final long datasourceObjId;
|
||||||
|
|
||||||
DeletedContentChildren(DeletedContent.DeletedContentFilter filter, SleuthkitCase skCase, Observable o, long datasourceObjId) {
|
DeletedContentChildren(DeletedContent.DeletedContentFilter filter, SleuthkitCase skCase, Observable o, long datasourceObjId) {
|
||||||
|
super(filter.getName());
|
||||||
this.skCase = skCase;
|
this.skCase = skCase;
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
this.notifier = o;
|
this.notifier = o;
|
||||||
@ -376,6 +376,11 @@ public class DeletedContent implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
private final Observer observer = new DeletedContentChildrenObserver();
|
private final Observer observer = new DeletedContentChildrenObserver();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<AbstractFile> makeKeys() {
|
||||||
|
return runFsQuery();
|
||||||
|
}
|
||||||
|
|
||||||
// Cause refresh of children if there are changes
|
// Cause refresh of children if there are changes
|
||||||
private class DeletedContentChildrenObserver implements Observer {
|
private class DeletedContentChildrenObserver implements Observer {
|
||||||
|
|
||||||
@ -386,25 +391,19 @@ public class DeletedContent implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addNotify() {
|
protected void onAdd() {
|
||||||
if (notifier != null) {
|
if (notifier != null) {
|
||||||
notifier.addObserver(observer);
|
notifier.addObserver(observer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void removeNotify() {
|
protected void onRemove() {
|
||||||
if (notifier != null) {
|
if (notifier != null) {
|
||||||
notifier.deleteObserver(observer);
|
notifier.deleteObserver(observer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean createKeys(List<AbstractFile> list) {
|
|
||||||
list.addAll(runFsQuery());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static private String makeQuery(DeletedContent.DeletedContentFilter filter, long filteringDSObjId) {
|
static private String makeQuery(DeletedContent.DeletedContentFilter filter, long filteringDSObjId) {
|
||||||
String query = "";
|
String query = "";
|
||||||
switch (filter) {
|
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)) {
|
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
|
||||||
query += " AND data_source_obj_id = " + filteringDSObjId;
|
query += " AND data_source_obj_id = " + filteringDSObjId;
|
||||||
}
|
}
|
||||||
|
@ -423,12 +423,12 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
|||||||
/**
|
/**
|
||||||
* Creates children for a given artifact type
|
* Creates children for a given artifact type
|
||||||
*/
|
*/
|
||||||
private class ArtifactFactory extends ChildFactory.Detachable<BlackboardArtifact> {
|
private class ArtifactFactory extends BaseChildFactory<BlackboardArtifact> {
|
||||||
|
|
||||||
private BlackboardArtifact.Type type;
|
private BlackboardArtifact.Type type;
|
||||||
|
|
||||||
public ArtifactFactory(BlackboardArtifact.Type type) {
|
public ArtifactFactory(BlackboardArtifact.Type type) {
|
||||||
super();
|
super(type.getTypeName());
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,36 +481,36 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
|||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addNotify() {
|
protected void onAdd() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void removeNotify() {
|
protected void onRemove() {
|
||||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().removeIngestModuleEventListener(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
|
@Override
|
||||||
protected Node createNodeForKey(BlackboardArtifact key) {
|
protected Node createNodeForKey(BlackboardArtifact key) {
|
||||||
return new BlackboardArtifactNode(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
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2013-2018 Basis Technology Corp.
|
* Copyright 2013-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* 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
|
* 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 SleuthkitCase skCase;
|
||||||
private final FileSizeFilter filter;
|
private final FileSizeFilter filter;
|
||||||
@ -377,6 +377,7 @@ public class FileSize implements AutopsyVisitableItem {
|
|||||||
* added to case
|
* added to case
|
||||||
*/
|
*/
|
||||||
FileSizeChildren(FileSizeFilter filter, SleuthkitCase skCase, Observable o, long dsObjId) {
|
FileSizeChildren(FileSizeFilter filter, SleuthkitCase skCase, Observable o, long dsObjId) {
|
||||||
|
super(filter.getName());
|
||||||
this.skCase = skCase;
|
this.skCase = skCase;
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
this.notifier = o;
|
this.notifier = o;
|
||||||
@ -385,14 +386,14 @@ public class FileSize implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addNotify() {
|
protected void onAdd() {
|
||||||
if (notifier != null) {
|
if (notifier != null) {
|
||||||
notifier.addObserver(observer);
|
notifier.addObserver(observer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void removeNotify() {
|
protected void onRemove() {
|
||||||
if (notifier != null) {
|
if (notifier != null) {
|
||||||
notifier.deleteObserver(observer);
|
notifier.deleteObserver(observer);
|
||||||
}
|
}
|
||||||
@ -400,6 +401,11 @@ public class FileSize implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
private final Observer observer = new FileSizeChildrenObserver();
|
private final Observer observer = new FileSizeChildrenObserver();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<AbstractFile> makeKeys() {
|
||||||
|
return runFsQuery();
|
||||||
|
}
|
||||||
|
|
||||||
// Cause refresh of children if there are changes
|
// Cause refresh of children if there are changes
|
||||||
private class FileSizeChildrenObserver implements Observer {
|
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) {
|
private static String makeQuery(FileSizeFilter filter, long filteringDSObjId) {
|
||||||
String query;
|
String query;
|
||||||
switch (filter) {
|
switch (filter) {
|
||||||
@ -436,17 +436,6 @@ public class FileSize implements AutopsyVisitableItem {
|
|||||||
// Ignore unallocated block files.
|
// Ignore unallocated block files.
|
||||||
query = query + " AND (type != " + TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType() + ")"; //NON-NLS
|
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
|
// filter by datasource if indicated in case preferences
|
||||||
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
|
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
|
||||||
query += " AND data_source_obj_id = " + filteringDSObjId;
|
query += " AND data_source_obj_id = " + filteringDSObjId;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
* Copyright 2011-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* 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.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -292,7 +293,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
|||||||
* should refresh
|
* should refresh
|
||||||
*/
|
*/
|
||||||
FileExtensionNode(FileTypesByExtension.SearchFilterInterface filter, SleuthkitCase skCase, FileTypesByExtObservable o) {
|
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()));
|
Lookups.singleton(filter.getDisplayName()));
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
super.setName(filter.getDisplayName());
|
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.
|
* 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 SleuthkitCase skCase;
|
||||||
private final FileTypesByExtension.SearchFilterInterface filter;
|
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
|
* @param o Observable that will notify when there could be new
|
||||||
* data to display
|
* data to display
|
||||||
*/
|
*/
|
||||||
private FileExtensionNodeChildren(FileTypesByExtension.SearchFilterInterface filter, SleuthkitCase skCase, Observable o) {
|
private FileExtensionNodeChildren(FileTypesByExtension.SearchFilterInterface filter, SleuthkitCase skCase, Observable o, String nodeName) {
|
||||||
super();
|
super(nodeName);
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
this.skCase = skCase;
|
this.skCase = skCase;
|
||||||
notifier = o;
|
notifier = o;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addNotify() {
|
protected void onAdd() {
|
||||||
if (notifier != null) {
|
if (notifier != null) {
|
||||||
notifier.addObserver(this);
|
notifier.addObserver(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void removeNotify() {
|
protected void onRemove() {
|
||||||
if (notifier != null) {
|
if (notifier != null) {
|
||||||
notifier.deleteObserver(this);
|
notifier.deleteObserver(this);
|
||||||
}
|
}
|
||||||
@ -417,19 +418,19 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean createKeys(List<FileTypesKey> list) {
|
protected Node createNodeForKey(FileTypesKey key) {
|
||||||
try {
|
return key.accept(new FileTypes.FileNodeCreationVisitor());
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Node createNodeForKey(FileTypesKey key) {
|
protected List<FileTypesKey> makeKeys() {
|
||||||
return key.accept(new FileTypes.FileNodeCreationVisitor());
|
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
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
* Copyright 2011-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* 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
|
* files that match MimeType which is represented by this position in the
|
||||||
* tree.
|
* tree.
|
||||||
*/
|
*/
|
||||||
private class MediaSubTypeNodeChildren extends ChildFactory.Detachable<FileTypesKey> implements Observer {
|
private class MediaSubTypeNodeChildren extends BaseChildFactory<FileTypesKey> implements Observer {
|
||||||
|
|
||||||
private final String mimeType;
|
private final String mimeType;
|
||||||
|
|
||||||
private MediaSubTypeNodeChildren(String mimeType) {
|
private MediaSubTypeNodeChildren(String mimeType) {
|
||||||
super();
|
super(mimeType);
|
||||||
addObserver(this);
|
addObserver(this);
|
||||||
this.mimeType = mimeType;
|
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
|
@Override
|
||||||
public void update(Observable o, Object arg) {
|
public void update(Observable o, Object arg) {
|
||||||
refresh(true);
|
refresh(true);
|
||||||
@ -475,5 +464,26 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
|||||||
protected Node createNodeForKey(FileTypesKey key) {
|
protected Node createNodeForKey(FileTypesKey key) {
|
||||||
return key.accept(new FileTypes.FileNodeCreationVisitor());
|
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
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
* Copyright 2011-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* 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.Observer;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
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;
|
||||||
@ -44,7 +45,6 @@ import org.openide.util.lookup.Lookups;
|
|||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
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;
|
||||||
@ -378,33 +378,40 @@ public class HashsetHits implements AutopsyVisitableItem {
|
|||||||
/**
|
/**
|
||||||
* Creates the nodes for the hits in a given set.
|
* 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 String hashsetName;
|
||||||
private Map<Long, BlackboardArtifact> artifactHits = new HashMap<>();
|
private Map<Long, BlackboardArtifact> artifactHits = new HashMap<>();
|
||||||
|
|
||||||
private HitFactory(String hashsetName) {
|
private HitFactory(String hashsetName) {
|
||||||
super();
|
super(hashsetName);
|
||||||
this.hashsetName = hashsetName;
|
this.hashsetName = hashsetName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addNotify() {
|
protected void onAdd() {
|
||||||
hashsetResults.addObserver(this);
|
hashsetResults.addObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void removeNotify() {
|
protected void onRemove() {
|
||||||
hashsetResults.deleteObserver(this);
|
hashsetResults.deleteObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean createKeys(List<Long> list) {
|
protected Node createNodeForKey(BlackboardArtifact key) {
|
||||||
|
return new BlackboardArtifactNode(key);
|
||||||
if (skCase == null) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Observable o, Object arg) {
|
||||||
|
refresh(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<BlackboardArtifact> makeKeys() {
|
||||||
|
if (skCase != null) {
|
||||||
|
|
||||||
hashsetResults.getArtifactIds(hashsetName).forEach((id) -> {
|
hashsetResults.getArtifactIds(hashsetName).forEach((id) -> {
|
||||||
try {
|
try {
|
||||||
if (!artifactHits.containsKey(id)) {
|
if (!artifactHits.containsKey(id)) {
|
||||||
@ -415,23 +422,9 @@ public class HashsetHits implements AutopsyVisitableItem {
|
|||||||
logger.log(Level.SEVERE, "TSK Exception occurred", ex); //NON-NLS
|
logger.log(Level.SEVERE, "TSK Exception occurred", ex); //NON-NLS
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return new ArrayList<>(artifactHits.values());
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
@Override
|
|
||||||
protected Node createNodeForKey(Long id) {
|
|
||||||
BlackboardArtifact art = artifactHits.get(id);
|
|
||||||
return (null == art) ? null : new BlackboardArtifactNode(art);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update(Observable o, Object arg) {
|
|
||||||
refresh(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
* Copyright 2011-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -449,26 +449,23 @@ 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 setName;
|
||||||
private final String typeName;
|
private final String typeName;
|
||||||
private final Map<Long, BlackboardArtifact> artifactHits = new HashMap<>();
|
private final Map<Long, BlackboardArtifact> artifactHits = new HashMap<>();
|
||||||
|
|
||||||
private HitFactory(String setName, String typeName) {
|
private HitFactory(String setName, String typeName) {
|
||||||
super();
|
super(typeName);
|
||||||
this.setName = setName;
|
this.setName = setName;
|
||||||
this.typeName = typeName;
|
this.typeName = typeName;
|
||||||
interestingResults.addObserver(this);
|
interestingResults.addObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean createKeys(List<Long> list) {
|
protected List<BlackboardArtifact> makeKeys() {
|
||||||
|
|
||||||
if (skCase == null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (skCase != null) {
|
||||||
interestingResults.getArtifactIds(setName, typeName).forEach((id) -> {
|
interestingResults.getArtifactIds(setName, typeName).forEach((id) -> {
|
||||||
try {
|
try {
|
||||||
if (!artifactHits.containsKey(id)) {
|
if (!artifactHits.containsKey(id)) {
|
||||||
@ -480,20 +477,29 @@ public class InterestingHits implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
list.addAll(artifactHits.keySet());
|
return new ArrayList<>(artifactHits.values());
|
||||||
|
}
|
||||||
return true;
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Node createNodeForKey(Long l) {
|
protected Node createNodeForKey(BlackboardArtifact art) {
|
||||||
BlackboardArtifact art = artifactHits.get(l);
|
return new BlackboardArtifactNode(art);
|
||||||
return (null == art) ? null : new BlackboardArtifactNode(art);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(Observable o, Object arg) {
|
public void update(Observable o, Object arg) {
|
||||||
refresh(true);
|
refresh(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onAdd() {
|
||||||
|
// No-op
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRemove() {
|
||||||
|
// No-op
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
* Copyright 2011-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* 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.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -34,7 +35,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 java.util.stream.Collectors;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.openide.nodes.ChildFactory;
|
import org.openide.nodes.ChildFactory;
|
||||||
import org.openide.nodes.Children;
|
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.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import static org.sleuthkit.autopsy.datamodel.Bundle.*;
|
import static org.sleuthkit.autopsy.datamodel.Bundle.*;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
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";
|
private static final String DEFAULT_INSTANCE_NAME = "DEFAULT_INSTANCE_NAME";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* query attributes table for the ones that we need for the tree
|
* query attributes table for the ones that we need for the tree
|
||||||
*/
|
*/
|
||||||
@ -530,7 +528,7 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final void updateDisplayName() {
|
final void updateDisplayName() {
|
||||||
super.setDisplayName(getName() + " (" + countTotalDescendants() + ")");
|
super.setDisplayName(getDisplayName() + " (" + countTotalDescendants() + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract int 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
|
* Represents the search term or regexp that user searched for
|
||||||
*/
|
*/
|
||||||
@ -640,8 +656,17 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
private final String keyword;
|
private final String keyword;
|
||||||
|
|
||||||
private TermNode(String setName, String keyword) {
|
private TermNode(String setName, String keyword) {
|
||||||
super(Children.create(new RegExpInstancesFactory(setName, keyword), true), Lookups.singleton(keyword));
|
super(Children.create(createChildFactory(setName, keyword), true), Lookups.singleton(keyword));
|
||||||
super.setName(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.setName = setName;
|
||||||
this.keyword = keyword;
|
this.keyword = keyword;
|
||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS
|
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
|
* Creates the nodes for a given regexp that represent the specific terms
|
||||||
* that were found
|
* that were found
|
||||||
*/
|
*/
|
||||||
private class RegExpInstancesFactory extends DetachableObserverChildFactory<RegExpInstanceKey> {
|
private class RegExpInstancesFactory extends DetachableObserverChildFactory<String> {
|
||||||
|
|
||||||
private final String keyword;
|
private final String keyword;
|
||||||
private final String setName;
|
private final String setName;
|
||||||
@ -744,35 +735,17 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean createKeys(List<RegExpInstanceKey> list) {
|
protected boolean createKeys(List<String> list) {
|
||||||
List<String> instances = keywordResults.getKeywordInstances(setName, keyword);
|
list.addAll(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()));
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Node createNodeForKey(RegExpInstanceKey key) {
|
protected Node createNodeForKey(String key) {
|
||||||
if (key.isRegExp()) {
|
return new RegExpInstanceNode(setName, keyword, key);
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a specific term that was found from a regexp
|
* Represents a specific term that was found from a regexp
|
||||||
*/
|
*/
|
||||||
@ -784,7 +757,15 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
private RegExpInstanceNode(String setName, String keyword, String instance) {
|
private RegExpInstanceNode(String setName, String keyword, String instance) {
|
||||||
super(Children.create(new HitsFactory(setName, keyword, instance), true), Lookups.singleton(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.setName = setName;
|
||||||
this.keyword = keyword;
|
this.keyword = keyword;
|
||||||
this.instance = instance;
|
this.instance = instance;
|
||||||
@ -837,7 +818,7 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
/**
|
/**
|
||||||
* Create a blackboard node for the given Keyword Hit artifact
|
* Create a blackboard node for the given Keyword Hit artifact
|
||||||
*
|
*
|
||||||
* @param artifactId
|
* @param art
|
||||||
*
|
*
|
||||||
* @return Node or null on error
|
* @return Node or null on error
|
||||||
*/
|
*/
|
||||||
@ -850,14 +831,13 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
"KeywordHits.createNodeForKey.chgTime.name=ChangeTime",
|
"KeywordHits.createNodeForKey.chgTime.name=ChangeTime",
|
||||||
"KeywordHits.createNodeForKey.chgTime.displayName=Change Time",
|
"KeywordHits.createNodeForKey.chgTime.displayName=Change Time",
|
||||||
"KeywordHits.createNodeForKey.chgTime.desc=Change Time"})
|
"KeywordHits.createNodeForKey.chgTime.desc=Change Time"})
|
||||||
private BlackboardArtifactNode createBlackboardArtifactNode(Long artifactId) {
|
private BlackboardArtifactNode createBlackboardArtifactNode(BlackboardArtifact art) {
|
||||||
if (skCase == null) {
|
if (skCase == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
BlackboardArtifactNode n = new BlackboardArtifactNode(art); //NON-NLS
|
||||||
BlackboardArtifact art = skCase.getBlackboardArtifact(artifactId);
|
|
||||||
BlackboardArtifactNode n = new BlackboardArtifactNode(art);
|
|
||||||
// The associated file should be available through the Lookup that
|
// The associated file should be available through the Lookup that
|
||||||
// gets created when the BlackboardArtifactNode is constructed.
|
// gets created when the BlackboardArtifactNode is constructed.
|
||||||
AbstractFile file = n.getLookup().lookup(AbstractFile.class);
|
AbstractFile file = n.getLookup().lookup(AbstractFile.class);
|
||||||
@ -870,14 +850,13 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* It is possible to get a keyword hit on artifacts generated for
|
* It is possible to get a keyword hit on artifacts generated for the
|
||||||
* the underlying image in which case MAC times are not
|
* underlying image in which case MAC times are not
|
||||||
* available/applicable/useful.
|
* available/applicable/useful.
|
||||||
*/
|
*/
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
n.addNodeProperty(new NodeProperty<>(
|
n.addNodeProperty(new NodeProperty<>(
|
||||||
KeywordHits_createNodeForKey_modTime_name(),
|
KeywordHits_createNodeForKey_modTime_name(),
|
||||||
KeywordHits_createNodeForKey_modTime_displayName(),
|
KeywordHits_createNodeForKey_modTime_displayName(),
|
||||||
@ -894,37 +873,68 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
KeywordHits_createNodeForKey_chgTime_desc(),
|
KeywordHits_createNodeForKey_chgTime_desc(),
|
||||||
ContentUtils.getStringTime(file.getCtime(), file)));
|
ContentUtils.getStringTime(file.getCtime(), file)));
|
||||||
return n;
|
return n;
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
logger.log(Level.WARNING, "TSK Exception occurred", ex); //NON-NLS
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates nodes for individual files that had hits
|
* 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 keyword;
|
||||||
private final String setName;
|
private final String setName;
|
||||||
private final String instance;
|
private final String instance;
|
||||||
|
private final Map<Long, BlackboardArtifact> artifactHits = new HashMap<>();
|
||||||
|
|
||||||
private HitsFactory(String setName, String keyword, String instance) {
|
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.setName = setName;
|
||||||
this.keyword = keyword;
|
this.keyword = keyword;
|
||||||
this.instance = instance;
|
this.instance = instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean createKeys(List<Long> list) {
|
protected List<BlackboardArtifact> makeKeys() {
|
||||||
list.addAll(keywordResults.getArtifactIds(setName, keyword, instance));
|
if (skCase != null) {
|
||||||
return true;
|
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
|
@Override
|
||||||
protected Node createNodeForKey(Long artifactId) {
|
protected Node createNodeForKey(BlackboardArtifact art) {
|
||||||
return createBlackboardArtifactNode(artifactId);
|
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