This commit is contained in:
Greg DiCristofaro 2023-07-07 09:56:10 -04:00
parent b67f14d424
commit 1ea7b215d2
3 changed files with 64 additions and 50 deletions

View File

@ -19,24 +19,29 @@
package org.sleuthkit.autopsy.casemodule;
import java.util.Map;
import org.sleuthkit.datamodel.ContentStream.ContentProvider;
import org.sleuthkit.datamodel.ContentStreamProvider;
/**
* A factory that generates a TSK ContentProvider.
* Interface that modules can implement to provide their own The Sleuth Kit
* ContentProvider implementations
*/
public interface FileContentProvider {
public interface AutopsyContentProvider {
/**
* Attempts to create a ContentProvider given the specified args. Returns
* null if arguments are invalid for this custom content provider.
*
* @param args The key value pair of arguments loaded from the .aut xml file.
* @param args The key value pair of arguments loaded from the .aut xml
* file.
* @return The created content provider or null if arguments are invalid.
*/
ContentProvider load(Map<String, Object> args);
ContentStreamProvider load(Map<String, Object> args);
/**
* Returns the uniquely identifying name of this FileContentProvider.
* Returns the uniquely identifying name of this FileContentProvider. This
* name will be stored in the .AUT file and used for lookup when the case is
* opened.
*
* @return The unique name.
*/
String getName();

View File

@ -143,7 +143,7 @@ import org.sleuthkit.autopsy.timeline.events.TimelineEventAddedEvent;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.CaseDbConnectionInfo;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentStream.ContentProvider;
import org.sleuthkit.datamodel.ContentStreamProvider;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.FileSystem;
@ -186,7 +186,6 @@ public class Case {
private static volatile Frame mainFrame;
private static volatile Case currentCase;
private final CaseMetadata metadata;
private final ContentProvider contentProvider;
private volatile ExecutorService caseActionExecutor;
private CoordinationService.Lock caseLock;
private SleuthkitCase caseDb;
@ -2070,10 +2069,9 @@ public class Case {
*/
private Case(CaseMetadata caseMetaData) {
metadata = caseMetaData;
this.contentProvider = caseMetaData.getContentProvider();
sleuthkitEventListener = new SleuthkitEventListener();
}
/**
* Performs a case action that involves creating or opening a case. If the
* case is a multi-user case, the action is done after acquiring a
@ -2737,15 +2735,20 @@ public class Case {
progressIndicator.progress(Bundle.Case_progressMessage_openingCaseDatabase());
try {
String databaseName = metadata.getCaseDatabaseName();
ContentStreamProvider contentProvider = loadContentProvider(
metadata.getContentProviderName(),
metadata.getContentProviderArgs());
if (CaseType.SINGLE_USER_CASE == metadata.getCaseType()) {
// only prefix with metadata directory if databaseName is a relative path
String fullDatabasePath = (new File(databaseName).isAbsolute())
? databaseName
: Paths.get(metadata.getCaseDirectory(), databaseName).toString();
caseDb = SleuthkitCase.openCase(fullDatabasePath, this.contentProvider);
caseDb = SleuthkitCase.openCase(fullDatabasePath, contentProvider);
} else if (UserPreferences.getIsMultiUserModeEnabled()) {
caseDb = SleuthkitCase.openCase(databaseName, UserPreferences.getDatabaseConnectionInfo(), metadata.getCaseDirectory(), this.contentProvider);
caseDb = SleuthkitCase.openCase(databaseName, UserPreferences.getDatabaseConnectionInfo(), metadata.getCaseDirectory(), contentProvider);
} else {
throw new CaseActionException(Bundle.Case_open_exception_multiUserCaseNotEnabled());
}
@ -2758,6 +2761,36 @@ public class Case {
throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotOpenCaseDatabase(ex.getLocalizedMessage()), ex);
}
}
/**
* Attempts to load a content provider for the provided arguments. Returns
* null if no content provider for the arguments can be identified.
*
* @param providerName The name of the content provider.
* @param args The arguments.
* @return The content provider or null if no content provider can be
* provisioned for the arguments
*/
private static ContentStreamProvider loadContentProvider(String providerName, Map<String, Object> args) {
Collection<? extends AutopsyContentProvider> customContentProviders = Lookup.getDefault().lookupAll(AutopsyContentProvider.class);
if (customContentProviders != null) {
for (AutopsyContentProvider customProvider : customContentProviders) {
// ensure the provider matches the name
if (customProvider == null || !StringUtils.equalsIgnoreCase(providerName, customProvider.getName())) {
continue;
}
ContentStreamProvider contentProvider = customProvider.load(args);
if (contentProvider != null) {
return contentProvider;
}
}
}
return null;
}
/**
* Opens the case-level services: the files manager, tags manager and

View File

@ -55,7 +55,6 @@ import org.apache.commons.lang3.tuple.Pair;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.coreutils.XMLUtil;
import org.sleuthkit.datamodel.ContentStream.ContentProvider;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
@ -143,7 +142,6 @@ public final class CaseMetadata {
private String createdDate;
private String createdByVersion;
private CaseMetadata originalMetadata = null; // For portable cases
private ContentProvider contentProvider;
private String contentProviderName;
private Map<String, Object> contentProviderArgs;
@ -201,7 +199,7 @@ public final class CaseMetadata {
createdByVersion = Version.getVersion();
createdDate = CaseMetadata.DATE_FORMAT.format(new Date());
this.originalMetadata = originalMetadata;
this.contentProvider = originalMetadata == null ? null : originalMetadata.contentProvider;
this.contentProviderName = originalMetadata == null ? null : originalMetadata.contentProviderName;
this.contentProviderArgs = originalMetadata == null ? null : originalMetadata.contentProviderArgs;
}
@ -241,11 +239,19 @@ public final class CaseMetadata {
}
/**
* @return The custom provider for content byte data or null if no custom
* provider.
* @return The custom provider name for content byte data or null if no
* custom provider.
*/
public ContentProvider getContentProvider() {
return contentProvider;
public String getContentProviderName() {
return this.contentProviderName;
}
/**
* @return The arguments for the custom provider for content byte data or
* null if no custom provider.
*/
public Map<String, Object> getContentProviderArgs() {
return contentProviderArgs;
}
/**
@ -604,11 +610,9 @@ public final class CaseMetadata {
this.contentProviderArgs = (contentProviderArgs instanceof Map) ?
(Map<String, Object>) contentProviderArgs :
Collections.singletonMap(CONTENT_PROVIDER_ARG_DEFAULT_KEY, contentProviderArgs);
this.contentProvider = loadContentProvider(contentProviderName, this.contentProviderArgs);
} else {
this.contentProviderArgs = null;
this.contentProviderName = null;
this.contentProvider = null;
}
/*
@ -774,34 +778,6 @@ public final class CaseMetadata {
el.setTextContent(arg.toString());
}
}
/**
* Attempts to load a content provider for the provided arguments. Returns
* null if no content provider for the arguments can be identified.
*
* @param providerName The name of the content provider.
* @param args The arguments.
* @return The content provider or null if no content provider can be
* provisioned for the arguments
*/
private ContentProvider loadContentProvider(String providerName, Map<String, Object> args) {
Collection<? extends FileContentProvider> customContentProviders = Lookup.getDefault().lookupAll(FileContentProvider.class);
if (customContentProviders != null) {
for (FileContentProvider customProvider : customContentProviders) {
// ensure the provider matches the name
if (customProvider == null || !StringUtils.equalsIgnoreCase(providerName, customProvider.getName())) {
continue;
}
ContentProvider contentProvider = customProvider.load(args);
if (contentProvider != null) {
return contentProvider;
}
}
}
return null;
}
/**
* Gets the text content of an XML element.