more progress

This commit is contained in:
Brian Sweeney 2018-06-06 18:12:03 -06:00
parent 4c0984c6d2
commit 69b6eb14fa
9 changed files with 221 additions and 83 deletions

View File

@ -0,0 +1,46 @@
/*
*
* Autopsy Forensic Browser
*
* Copyright 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.commonfilesearch;
import java.util.Map;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepositoryFile;
import org.sleuthkit.autopsy.datamodel.CentralRepositoryFileInstanceNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.datamodel.AbstractFile;
/**
* Generates a DisplayableItmeNode using a CentralRepositoryFile.
*/
public class CentralRepositoryCaseFileInstanceMetadata extends FileInstanceNodeGenerator {
private CentralRepositoryFile crFile;
CentralRepositoryCaseFileInstanceMetadata(CentralRepositoryFile crFile, Long abstractFileReference, Map<Long, AbstractFile> cachedFiles, String dataSource){
super(abstractFileReference, cachedFiles, dataSource);
//TODO should we actually just take an ID instead of the whole object
// like we've done previously, or is this ok?
this.crFile = crFile;
}
@Override
public DisplayableItemNode generateNode() {
return new CentralRepositoryFileInstanceNode(this.crFile, this.lookupOrCreateAbstractFile());
}
}

View File

@ -32,6 +32,7 @@ import java.util.stream.Stream;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.HashUtility; import org.sleuthkit.datamodel.HashUtility;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
@ -173,6 +174,8 @@ public abstract class CommonFilesMetadataBuilder {
SleuthkitCase sleuthkitCase = Case.getCurrentCaseThrows().getSleuthkitCase(); SleuthkitCase sleuthkitCase = Case.getCurrentCaseThrows().getSleuthkitCase();
String selectStatement = this.buildSqlSelectStatement(); String selectStatement = this.buildSqlSelectStatement();
Map<Long, AbstractFile> fileCache = new HashMap<>();
try ( try (
CaseDbQuery query = sleuthkitCase.executeQuery(selectStatement); CaseDbQuery query = sleuthkitCase.executeQuery(selectStatement);
ResultSet resultSet = query.getResultSet()) { ResultSet resultSet = query.getResultSet()) {
@ -189,11 +192,10 @@ public abstract class CommonFilesMetadataBuilder {
if (commonFiles.containsKey(md5)) { if (commonFiles.containsKey(md5)) {
final Md5Metadata md5Metadata = commonFiles.get(md5); final Md5Metadata md5Metadata = commonFiles.get(md5);
md5Metadata.addFileInstanceMetadata(new FileInstanceMetadata(objectId, dataSource)); md5Metadata.addFileInstanceMetadata(new SleuthkitCaseFileInstanceMetadata(objectId, fileCache, dataSource));
} else { } else {
final List<FileInstanceMetadata> fileInstances = new ArrayList<>(); final Md5Metadata md5Metadata = new Md5Metadata(md5);
fileInstances.add(new FileInstanceMetadata(objectId, dataSource)); md5Metadata.addFileInstanceMetadata(new SleuthkitCaseFileInstanceMetadata(objectId, fileCache, dataSource));
Md5Metadata md5Metadata = new Md5Metadata(md5, fileInstances);
commonFiles.put(md5, md5Metadata); commonFiles.put(md5, md5Metadata);
} }
} }

View File

@ -111,6 +111,7 @@ public abstract class EamDbCommonFilesAlgorithm extends CommonFilesMetadataBuild
private Map<String, Md5Metadata> gatherIntercaseResults(Collection<CentralRepositoryFile> artifactInstances, Map<String, Md5Metadata> commonFiles) { private Map<String, Md5Metadata> gatherIntercaseResults(Collection<CentralRepositoryFile> artifactInstances, Map<String, Md5Metadata> commonFiles) {
Map<String, Md5Metadata> interCaseCommonFiles = new HashMap<>(); Map<String, Md5Metadata> interCaseCommonFiles = new HashMap<>();
Map<Long, AbstractFile> cachedFiles = new HashMap<>();
for (CentralRepositoryFile instance : artifactInstances) { for (CentralRepositoryFile instance : artifactInstances) {
@ -130,15 +131,16 @@ public abstract class EamDbCommonFilesAlgorithm extends CommonFilesMetadataBuild
//TODO resume here!!! //TODO resume here!!!
//TODO need to figure out if we have a CR instance or a SK resource and create as appropriate.... //TODO need to figure out if we have a CR instance or a SK resource and create as appropriate....
Long objectId = commonFiles.get(md5).getMetadata().iterator().next().getObjectId(); Long objectId = commonFiles.get(md5).getMetadata().iterator().next().getIdenticalFileSleuthkitCaseObjectID();
if(interCaseCommonFiles.containsKey(md5)) { if(interCaseCommonFiles.containsKey(md5)) {
//Add to intercase metaData //Add to intercase metaData
final Md5Metadata md5Metadata = interCaseCommonFiles.get(md5); final Md5Metadata md5Metadata = interCaseCommonFiles.get(md5);
md5Metadata.addFileInstanceMetadata(new FileInstanceMetadata(objectId, dataSource), correlationCaseDisplayName); md5Metadata.addFileInstanceMetadata(new SleuthkitCaseFileInstanceMetadata(objectId, dataSource), correlationCaseDisplayName);
} else { } else {
Md5Metadata md5Metadata = new Md5Metadata(md5); Md5Metadata md5Metadata = new Md5Metadata(md5);
md5Metadata.addFileInstanceMetadata(new FileInstanceMetadata(objectId, dataSource), correlationCaseDisplayName); md5Metadata.addFileInstanceMetadata(new SleuthkitCaseFileInstanceMetadata(objectId, dataSource), correlationCaseDisplayName);
interCaseCommonFiles.put(md5, md5Metadata); interCaseCommonFiles.put(md5, md5Metadata);
} }
} }

View File

@ -0,0 +1,132 @@
/*
*
* Autopsy Forensic Browser
*
* Copyright 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.commonfilesearch;
import java.util.Map;
import java.util.logging.Level;
import org.openide.util.Exceptions;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepositoryFile;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.CentralRepositoryFileInstanceNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.autopsy.datamodel.SleuthkitCaseFileInstanceNode;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Defines types which can be used to get some sort of File Instance node (a
* child of the MD5Node) for use in the common files tree table.
*/
public abstract class FileInstanceNodeGenerator {
private static final Logger LOGGER = Logger.getLogger(FileInstanceNodeGenerator.class.getName());
protected Long abstractFileReference;
protected Map<Long, AbstractFile> cachedFiles;
private String dataSource;
public FileInstanceNodeGenerator(Long abstractFileReference, Map<Long, AbstractFile> cachedFiles, String dataSource){
this.abstractFileReference = abstractFileReference;
this.cachedFiles = cachedFiles;
this.dataSource = dataSource;
}
/**
* Grab a cached instance of the AbstractFile or grab one from the
* SleuthkitCase. Use this in implementations of <code>generateNode</code>.
*
* @param objectId
* @param cachedFiles
* @return AbstractFile which is identical to the file instance generated by
* implementations of this object
*/
protected AbstractFile lookupOrCreateAbstractFile() {
if (this.cachedFiles.containsKey(this.abstractFileReference)) {
return this.cachedFiles.get(this.abstractFileReference);
} else {
AbstractFile file = FileInstanceNodeGenerator.loadFileFromSleuthkitCase(this.abstractFileReference);
this.cachedFiles.put(this.abstractFileReference, file);
return file;
}
}
private static AbstractFile loadFileFromSleuthkitCase(Long objectId) {
Case currentCase;
try {
currentCase = Case.getCurrentCaseThrows();
SleuthkitCase tskDb = currentCase.getSleuthkitCase();
AbstractFile abstractFile = tskDb.findAllFilesWhere(String.format("obj_id in (%s)", objectId)).get(0);
return abstractFile;
} catch (TskCoreException | NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, String.format("Unable to find AbstractFile for record with obj_id: %s. Node not created.", new Object[]{objectId}), ex);
return null;
}
}
private static AbstractFile lookupOrCreateAbstractFile(Long objectId, Map<Long, AbstractFile> cachedFiles){
if (cachedFiles.containsKey(objectId)) {
return cachedFiles.get(objectId);
} else {
AbstractFile file = FileInstanceNodeGenerator.loadFileFromSleuthkitCase(objectId);
cachedFiles.put(objectId, file);
return file;
}
}
/**
* Create a node which is a child of the MD5Node, to be used to display a
* row in the tree table
*
* @return child row node
*/
public abstract DisplayableItemNode generateNode();
/**
* Get string name of the data source where this instance appears.
*
* @return
*/
public String getDataSource(){
/**
* Even though we could get this from the CR record or the AbstractFile,
* we want to avoid getting it from the AbstractFile because it would be an
* extra database roundtrip.
*/
return this.dataSource;
}
public Long getIdenticalFileSleuthkitCaseObjectID(){
return this.abstractFileReference;
}
public static FileInstanceNodeGenerator createInstance(Long objectId, CentralRepositoryFile instance, Map<Long, AbstractFile> cachedFiles){
AbstractFile referenceFile = FileInstanceNodeGenerator.lookupOrCreateAbstractFile(objectId, cachedFiles);
}
}

View File

@ -32,9 +32,9 @@ import java.util.Set;
final public class Md5Metadata { final public class Md5Metadata {
private final String md5; private final String md5;
private final List<FileInstanceMetadata> fileInstances; private final List<FileInstanceNodeGenerator> fileInstances;
Md5Metadata(String md5, List<FileInstanceMetadata> fileInstances){ Md5Metadata(String md5, List<FileInstanceNodeGenerator> fileInstances){
this.md5 = md5; this.md5 = md5;
this.fileInstances = fileInstances; this.fileInstances = fileInstances;
} }
@ -48,15 +48,15 @@ final public class Md5Metadata {
return this.md5; return this.md5;
} }
void addFileInstanceMetadata(FileInstanceMetadata metadata){ void addFileInstanceMetadata(FileInstanceNodeGenerator metadata){
this.fileInstances.add(metadata); this.fileInstances.add(metadata);
} }
void addFileInstanceMetadata(FileInstanceMetadata metadata, String caseName){ void addFileInstanceMetadata(SleuthkitCaseFileInstanceMetadata metadata, String caseName){
this.fileInstances.add(metadata); this.fileInstances.add(metadata);
} }
public Collection<FileInstanceMetadata> getMetadata(){ public Collection<FileInstanceNodeGenerator> getMetadata(){
return Collections.unmodifiableCollection(this.fileInstances); return Collections.unmodifiableCollection(this.fileInstances);
} }
@ -70,8 +70,8 @@ final public class Md5Metadata {
public String getDataSources() { public String getDataSources() {
Set<String> sources = new HashSet<> (); Set<String> sources = new HashSet<> ();
for(FileInstanceMetadata data : this.fileInstances){ for(FileInstanceNodeGenerator data : this.fileInstances){
sources.add(data.getDataSourceName()); sources.add(data.getDataSource());
} }
return String.join(", ", sources); return String.join(", ", sources);
} }

View File

@ -20,58 +20,29 @@
package org.sleuthkit.autopsy.commonfilesearch; package org.sleuthkit.autopsy.commonfilesearch;
import java.io.File; import java.io.File;
import java.util.Map;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepositoryFile; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepositoryFile;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.autopsy.datamodel.SleuthkitCaseFileInstanceNode;
import org.sleuthkit.datamodel.AbstractFile;
/** /**
* Encapsulates data required to instantiate a <code>FileInstanceNode</code>. * Encapsulates data required to instantiate a <code>FileInstanceNode</code>.
*/ */
final public class FileInstanceMetadata { //TODO become abstract or interface final public class SleuthkitCaseFileInstanceMetadata extends FileInstanceNodeGenerator { //TODO become abstract or interface
private final Long objectId;
private final String dataSourceName;
private final CentralRepositoryFile crFile;
/** /**
* Create meta data required to find an abstract file and build a FileInstanceNode. * Create meta data required to find an abstract file and build a FileInstanceNode.
* @param objectId id of abstract file to find * @param objectId id of abstract file to find
* @param dataSourceName name of datasource where the object is found * @param dataSourceName name of datasource where the object is found
*/ */
FileInstanceMetadata (Long objectId, String dataSourceName) { SleuthkitCaseFileInstanceMetadata (Long abstractFileReference, Map<Long, AbstractFile> cachedFiles, String dataSource) {
this.objectId = objectId; super(abstractFileReference, cachedFiles, dataSource);
this.dataSourceName = dataSourceName;
this.crFile = null;
} }
FileInstanceMetadata (CentralRepositoryFile crFile){ @Override
//TODO should we actually just take an ID instead of the whole object public DisplayableItemNode generateNode() {
// like we've done previously, or is this ok? return new SleuthkitCaseFileInstanceNode(this.lookupOrCreateAbstractFile(), this.getDataSource());
this.objectId = null;
this.dataSourceName = null;
this.crFile = crFile;
}
/**
* obj_id for the file represented by this object
* @return
*/
public Long getObjectId(){
return this.objectId;
}
/**
* Name of datasource where this instance was found.
* @return
*/
public String getDataSourceName(){
return this.dataSourceName;
}
public boolean isPresentInCurrentCase() {
return this.crFile != null;
}
public CentralRepositoryFile getCentralRepoFileInstance() {
return this.crFile;
} }
} }

View File

@ -19,6 +19,7 @@
*/ */
package org.sleuthkit.autopsy.datamodel; package org.sleuthkit.autopsy.datamodel;
import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -32,7 +33,8 @@ import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepositoryFile; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepositoryFile;
import org.sleuthkit.autopsy.commonfilesearch.FileInstanceMetadata; import org.sleuthkit.autopsy.commonfilesearch.FileInstanceNodeGenerator;
import org.sleuthkit.autopsy.commonfilesearch.SleuthkitCaseFileInstanceMetadata;
import org.sleuthkit.autopsy.commonfilesearch.Md5Metadata; import org.sleuthkit.autopsy.commonfilesearch.Md5Metadata;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
@ -130,41 +132,24 @@ public class Md5Node extends DisplayableItemNode {
* Child generator for <code>SleuthkitCaseFileInstanceNode</code> of * Child generator for <code>SleuthkitCaseFileInstanceNode</code> of
* <code>Md5Node</code>. * <code>Md5Node</code>.
*/ */
static class FileInstanceNodeFactory extends ChildFactory<FileInstanceMetadata> { static class FileInstanceNodeFactory extends ChildFactory<FileInstanceNodeGenerator> {
private Map<Long, AbstractFile> cachedFiles;
private final Md5Metadata descendants; private final Md5Metadata descendants;
FileInstanceNodeFactory(Md5Metadata descendants) { FileInstanceNodeFactory(Md5Metadata descendants) {
this.descendants = descendants; this.descendants = descendants;
this.cachedFiles = new HashMap<>();
} }
@Override @Override
protected Node createNodeForKey(FileInstanceMetadata file) { protected Node createNodeForKey(FileInstanceNodeGenerator file) {
return file.generateNode();
try {
Case currentCase = Case.getCurrentCaseThrows();
SleuthkitCase tskDb = currentCase.getSleuthkitCase();
AbstractFile abstractFile = tskDb.findAllFilesWhere(String.format("obj_id in (%s)", file.getObjectId())).get(0);
//TODO it would be an improvement to utilize some sort of polymorphism
// (interface with getNode is probably plenty) rather than this conditional
if (file.isPresentInCurrentCase()) {
return new SleuthkitCaseFileInstanceNode(abstractFile, file.getDataSourceName());
} else {
CentralRepositoryFile crFile = file.getCentralRepoFileInstance();
return new CentralRepositoryFileInstanceNode(crFile, abstractFile);
}
} catch (NoCurrentCaseException | TskCoreException ex) {
LOGGER.log(Level.SEVERE, String.format("Unable to find AbstractFile for record with obj_id: %s. Node not created.", new Object[]{file.getObjectId()}), ex);
}
return null;
} }
@Override @Override
protected boolean createKeys(List<FileInstanceMetadata> list) { protected boolean createKeys(List<FileInstanceNodeGenerator> list) {
list.addAll(this.descendants.getMetadata()); list.addAll(this.descendants.getMetadata());
return true; return true;
} }

View File

@ -53,7 +53,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.commonfilesearch.CommonFilesMetadata; import org.sleuthkit.autopsy.commonfilesearch.CommonFilesMetadata;
import org.sleuthkit.autopsy.commonfilesearch.DataSourceLoader; import org.sleuthkit.autopsy.commonfilesearch.DataSourceLoader;
import org.sleuthkit.autopsy.commonfilesearch.FileInstanceMetadata; import org.sleuthkit.autopsy.commonfilesearch.SleuthkitCaseFileInstanceMetadata;
import org.sleuthkit.autopsy.commonfilesearch.Md5Metadata; import org.sleuthkit.autopsy.commonfilesearch.Md5Metadata;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
@ -297,9 +297,9 @@ class InterCaseUtils {
for(Map.Entry<String, Md5Metadata> file : searchDomain.getMetadata().entrySet()){ for(Map.Entry<String, Md5Metadata> file : searchDomain.getMetadata().entrySet()){
Collection<FileInstanceMetadata> fileInstances = file.getValue().getMetadata(); Collection<SleuthkitCaseFileInstanceMetadata> fileInstances = file.getValue().getMetadata();
for(FileInstanceMetadata fileInstance : fileInstances){ for(SleuthkitCaseFileInstanceMetadata fileInstance : fileInstances){
} }

View File

@ -36,7 +36,7 @@ import org.sleuthkit.autopsy.casemodule.ImageDSProcessor;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.commonfilesearch.CommonFilesMetadata; import org.sleuthkit.autopsy.commonfilesearch.CommonFilesMetadata;
import org.sleuthkit.autopsy.commonfilesearch.DataSourceLoader; import org.sleuthkit.autopsy.commonfilesearch.DataSourceLoader;
import org.sleuthkit.autopsy.commonfilesearch.FileInstanceMetadata; import org.sleuthkit.autopsy.commonfilesearch.SleuthkitCaseFileInstanceMetadata;
import org.sleuthkit.autopsy.commonfilesearch.Md5Metadata; import org.sleuthkit.autopsy.commonfilesearch.Md5Metadata;
import org.sleuthkit.autopsy.testutils.CaseUtils; import org.sleuthkit.autopsy.testutils.CaseUtils;
import org.sleuthkit.autopsy.testutils.IngestUtils; import org.sleuthkit.autopsy.testutils.IngestUtils;
@ -187,7 +187,7 @@ class IntraCaseUtils {
Map<Long, String> instanceIdToDataSource = new HashMap<>(); Map<Long, String> instanceIdToDataSource = new HashMap<>();
for (Map.Entry<String, Md5Metadata> entry : metadata.getMetadata().entrySet()) { for (Map.Entry<String, Md5Metadata> entry : metadata.getMetadata().entrySet()) {
for (FileInstanceMetadata md : entry.getValue().getMetadata()) { for (SleuthkitCaseFileInstanceMetadata md : entry.getValue().getMetadata()) {
instanceIdToDataSource.put(md.getObjectId(), md.getDataSourceName()); instanceIdToDataSource.put(md.getObjectId(), md.getDataSourceName());
} }
} }