Merge pull request #687 from rcordovano/serialize_ingest_module_settings

Serialize ingest module settings
This commit is contained in:
Richard Cordovano 2014-04-24 10:39:09 -04:00
commit e223d25bb5
13 changed files with 126 additions and 62 deletions

View File

@ -46,6 +46,11 @@ public class SampleModuleIngestJobSettings implements IngestModuleIngestJobSetti
this.skipKnownFiles = skipKnownFiles;
}
@Override
public String getVersionNumber() {
return "1.0"; //NON-NLS
}
void setSkipKnownFiles(boolean enabled) {
skipKnownFiles = enabled;
}

View File

@ -18,11 +18,22 @@
*/
package org.sleuthkit.autopsy.ingest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import org.openide.util.io.NbObjectInputStream;
import org.openide.util.io.NbObjectOutputStream;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.datamodel.Content;
/**
@ -35,9 +46,13 @@ public final class IngestJobLauncher {
private static final String ENABLED_INGEST_MODULES_KEY = "Enabled_Ingest_Modules"; //NON-NLS
private static final String DISABLED_INGEST_MODULES_KEY = "Disabled_Ingest_Modules"; //NON-NLS
private static final String PARSE_UNALLOC_SPACE_KEY = "Process_Unallocated_Space"; //NON-NLS
private static final String MODULE_SETTINGS_FOLDER_PATH = new StringBuilder(PlatformUtil.getUserConfigDirectory()).append(File.separator).append("IngestModuleSettings").toString(); //NON-NLS
private static final String MODULE_SETTINGS_FILE_EXT = ".settings"; //NON-NLS
private static final Logger logger = Logger.getLogger(IngestJobLauncher.class.getName());
private final String launcherContext;
private String moduleSettingsFolderForContext = null;
private final List<String> warnings = new ArrayList<>();
private IngestJobConfigurationPanel ingestConfigPanel;
private IngestJobConfigurationPanel ingestConfigPanel = null;
/**
* Constructs an ingest job launcher that creates and persists an ingest job
@ -49,6 +64,8 @@ public final class IngestJobLauncher {
public IngestJobLauncher(String launcherContext) {
this.launcherContext = launcherContext;
createModuleSettingsFolderForContext();
// Get the ingest module factories discovered by the ingest module
// loader.
List<IngestModuleFactory> moduleFactories = IngestModuleFactoryLoader.getInstance().getIngestModuleFactories();
@ -84,10 +101,7 @@ public final class IngestJobLauncher {
// Create ingest module templates.
List<IngestModuleTemplate> moduleTemplates = new ArrayList<>();
for (IngestModuleFactory moduleFactory : moduleFactories) {
// NOTE: In the future, this code will be modified to get the
// module settings for the current context, if available, from
// storage; for now always use the defaults.
IngestModuleTemplate moduleTemplate = new IngestModuleTemplate(moduleFactory, moduleFactory.getDefaultIngestJobSettings());
IngestModuleTemplate moduleTemplate = new IngestModuleTemplate(moduleFactory, loadJobSettings(moduleFactory));
String moduleName = moduleTemplate.getModuleName();
if (enabledModuleNames.contains(moduleName)) {
moduleTemplate.setEnabled(true);
@ -119,6 +133,23 @@ public final class IngestJobLauncher {
ingestConfigPanel = new IngestJobConfigurationPanel(moduleTemplates, processUnallocatedSpace);
}
private void createModuleSettingsFolderForContext() {
try {
StringBuilder folderPath = new StringBuilder(MODULE_SETTINGS_FOLDER_PATH);
folderPath.append(File.separator);
folderPath.append(launcherContext);
folderPath.append(File.separator);
File folder = new File(folderPath.toString());
if (!folder.exists()) {
Files.createDirectories(folder.toPath());
}
moduleSettingsFolderForContext = folder.getAbsolutePath();
} catch (Exception ex) {
logger.log(Level.SEVERE, "Failed to create ingest module settings directory", ex);
JOptionPane.showMessageDialog(null, "Failed to create ingest module settings folder, cannot save settings.", "Ingest Job Initialization Failure", JOptionPane.ERROR_MESSAGE);
}
}
private HashSet<String> getModulesNamesFromSetting(String key, String defaultSetting) {
// Get the ingest modules setting from the user's config file.
// If there is no such setting yet, create the default setting.
@ -150,7 +181,47 @@ public final class IngestJobLauncher {
}
return moduleNames;
}
private IngestModuleIngestJobSettings loadJobSettings(IngestModuleFactory factory) {
IngestModuleIngestJobSettings settings = null;
File settingsFile = new File(getModuleSettingsFilePath(factory));
if (settingsFile.exists()) {
try (NbObjectInputStream in = new NbObjectInputStream(new FileInputStream(settingsFile.getAbsolutePath()))) {
settings = (IngestModuleIngestJobSettings) in.readObject();
} catch (IOException | ClassNotFoundException ex) {
String logMessage = String.format("Error loading ingest job settings for %s module for %s context, using defaults", factory.getModuleDisplayName(), launcherContext);
logger.log(Level.SEVERE, logMessage, ex);
String userMessage = String.format("Failed to load saved ingest job settings for %s module, using defaults.", factory.getModuleDisplayName());
JOptionPane.showMessageDialog(null, userMessage, "Ingest Job Settings", JOptionPane.WARNING_MESSAGE);
}
}
if (settings == null) {
settings = factory.getDefaultIngestJobSettings();
}
return settings;
}
private void saveJobSettings(IngestModuleFactory factory, IngestModuleIngestJobSettings settings) {
try {
try (NbObjectOutputStream out = new NbObjectOutputStream(new FileOutputStream(getModuleSettingsFilePath(factory)))) {
out.writeObject(settings);
}
} catch (IOException ex) {
String logMessage = String.format("Error saving ingest job settings for %s module for %s context", factory.getModuleDisplayName(), launcherContext);
logger.log(Level.SEVERE, logMessage, ex);
String userMessage = String.format("Failed to save ingest job settings for %s module.", factory.getModuleDisplayName());
JOptionPane.showMessageDialog(null, userMessage, "Ingest Job Settings", JOptionPane.WARNING_MESSAGE);
}
}
private String getModuleSettingsFilePath(IngestModuleFactory factory) {
StringBuilder filePath = new StringBuilder(this.moduleSettingsFolderForContext);
filePath.append(File.separator);
filePath.append(factory.getClass().getCanonicalName());
filePath.append(MODULE_SETTINGS_FILE_EXT);
return filePath.toString();
}
/**
* Gets any warnings generated when the persisted ingest job configuration
* for the specified context is retrieved and loaded.
@ -182,6 +253,7 @@ public final class IngestJobLauncher {
HashSet<String> enabledModuleNames = new HashSet<>();
HashSet<String> disabledModuleNames = new HashSet<>();
for (IngestModuleTemplate moduleTemplate : moduleTemplates) {
saveJobSettings(moduleTemplate.getModuleFactory(), moduleTemplate.getModuleSettings());
String moduleName = moduleTemplate.getModuleName();
if (moduleTemplate.isEnabled()) {
enabledModuleNames.add(moduleName);
@ -195,9 +267,6 @@ public final class IngestJobLauncher {
// Save the process unallocated space setting for the current context.
String processUnalloc = Boolean.toString(ingestConfigPanel.getProcessUnallocSpace());
ModuleSettings.setConfigSetting(launcherContext, PARSE_UNALLOC_SPACE_KEY, processUnalloc);
// NOTE: In the future, this code will be modified to persist the ingest
// options for each ingest module for the current launch context.
}
private static String makeCommaSeparatedList(HashSet<String> input) {
@ -214,7 +283,7 @@ public final class IngestJobLauncher {
csvList.append(list.get(list.size() - 1));
return csvList.toString();
}
/**
* Launches ingest jobs for one or more data sources using the ingest job
* configuration for the selected context.

View File

@ -26,4 +26,11 @@ import java.io.Serializable;
* between invocations of the application.
*/
public interface IngestModuleIngestJobSettings extends Serializable {
/**
* Returns the version number of the settings object.
*
* @return A version number string.
*/
String getVersionNumber();
}

View File

@ -33,6 +33,10 @@ final class IngestModuleTemplate {
this.settings = settings;
}
IngestModuleFactory getModuleFactory() {
return moduleFactory;
}
String getModuleName() {
return moduleFactory.getModuleDisplayName();
}

View File

@ -26,6 +26,11 @@ public final class NoIngestModuleIngestJobSettings implements IngestModuleIngest
private final String setting = "None"; //NON-NLS
@Override
public String getVersionNumber() {
return "1.0"; //NON-NLS
}
/**
* Gets the string used as an ingest options placeholder for serialization
* purposes.

View File

@ -36,6 +36,11 @@ final class FileExtMismatchDetectorModuleSettings implements IngestModuleIngestJ
this.skipFilesWithTextPlainMimeType = skipFilesWithTextPlainMimeType;
}
@Override
public String getVersionNumber() {
return "1.0"; //NON-NLS
}
void setSkipFilesWithNoExtension(boolean enabled) {
skipFilesWithNoExtension = enabled;
}

View File

@ -33,7 +33,12 @@ public class FileTypeIdModuleSettings implements IngestModuleIngestJobSettings {
FileTypeIdModuleSettings(boolean skipKnownFiles) {
this.skipKnownFiles = skipKnownFiles;
}
@Override
public String getVersionNumber() {
return "1.0"; //NON-NLS
}
void setSkipKnownFiles(boolean enabled) {
skipKnownFiles = enabled;
}

View File

@ -74,8 +74,6 @@ public class HashDbManager implements PropertyChangeListener {
private static final String CONFIG_FILE_NAME = "hashsets.xml"; //NON-NLS
private static final String XSD_FILE_NAME = "HashsetsSchema.xsd"; //NON-NLS
private static final String ENCODING = "UTF-8"; //NON-NLS
private static final String ALWAYS_CALCULATE_HASHES_ELEMENT = "hash_calculate"; //NON-NLS
private static final String VALUE_ATTRIBUTE = "value"; //NON-NLS
private static final String HASH_DATABASE_FILE_EXTENSON = "kdb"; //NON-NLS
private static HashDbManager instance = null;
private final String configFilePath = PlatformUtil.getUserConfigDirectory() + File.separator + CONFIG_FILE_NAME;
@ -83,7 +81,6 @@ public class HashDbManager implements PropertyChangeListener {
private List<HashDb> knownBadHashSets = new ArrayList<>();
private Set<String> hashSetNames = new HashSet<>();
private Set<String> hashSetPaths = new HashSet<>();
private boolean alwaysCalculateHashes = true;
PropertyChangeSupport changeSupport = new PropertyChangeSupport(HashDbManager.class);
private static final Logger logger = Logger.getLogger(HashDbManager.class.getName());
@ -465,22 +462,6 @@ public class HashDbManager implements PropertyChangeListener {
return updateableDbs;
}
/**
* Sets the value for the flag that indicates whether hashes should be
* calculated for content even if no hash databases are configured.
*/
synchronized void setAlwaysCalculateHashes(boolean alwaysCalculateHashes) {
this.alwaysCalculateHashes = alwaysCalculateHashes;
}
/**
* Gets the flag that indicates whether hashes should be calculated for
* content even if no hash databases are configured.
*/
synchronized boolean getAlwaysCalculateHashes() {
return alwaysCalculateHashes;
}
/**
* Saves the hash sets configuration. Note that the configuration is only
* saved on demand to support cancellation of configuration panels.
@ -529,11 +510,6 @@ public class HashDbManager implements PropertyChangeListener {
writeHashDbsToDisk(doc, rootEl, knownHashSets);
writeHashDbsToDisk(doc, rootEl, knownBadHashSets);
String calcValue = Boolean.toString(alwaysCalculateHashes);
Element setCalc = doc.createElement(ALWAYS_CALCULATE_HASHES_ELEMENT);
setCalc.setAttribute(VALUE_ATTRIBUTE, calcValue);
rootEl.appendChild(setCalc);
success = XMLUtil.saveDoc(HashDbManager.class, configFilePath, ENCODING, doc);
} catch (ParserConfigurationException ex) {
Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error saving hash databases", ex); //NON-NLS
@ -691,17 +667,6 @@ public class HashDbManager implements PropertyChangeListener {
}
}
// Get the element that stores the always calculate hashes flag.
NodeList calcList = root.getElementsByTagName(ALWAYS_CALCULATE_HASHES_ELEMENT);
if (calcList.getLength() > 0) {
Element calcEl = (Element) calcList.item(0); // Shouldn't be more than one.
final String value = calcEl.getAttribute(VALUE_ATTRIBUTE);
alwaysCalculateHashes = Boolean.parseBoolean(value);
} else {
Logger.getLogger(HashDbManager.class.getName()).log(Level.WARNING, " element "); //NON-NLS
alwaysCalculateHashes = true;
}
if (updatedSchema) {
String backupFilePath = configFilePath + ".v1_backup"; //NON-NLS
String messageBoxTitle = NbBundle.getMessage(this.getClass(),

View File

@ -59,11 +59,11 @@ public class HashLookupModuleFactory extends IngestModuleFactoryAdapter {
@Override
public IngestModuleIngestJobSettings getDefaultIngestJobSettings() {
// All available hash sets are enabled by default.
// All available hash sets are enabled and always calculate hashes is true by default.
HashDbManager hashDbManager = HashDbManager.getInstance();
List<String> knownHashSetNames = getHashSetNames(hashDbManager.getKnownFileHashSets());
List<String> knownBadHashSetNames = getHashSetNames(hashDbManager.getKnownBadFileHashSets());
return new HashLookupModuleSettings(hashDbManager.getAlwaysCalculateHashes(), knownHashSetNames, knownBadHashSetNames);
return new HashLookupModuleSettings(true, knownHashSetNames, knownBadHashSetNames);
}
private List<String> getHashSetNames(List<HashDbManager.HashDb> hashDbs) {

View File

@ -38,6 +38,11 @@ final class HashLookupModuleSettings implements IngestModuleIngestJobSettings {
this.namesOfEnabledKnownBadHashSets.addAll(namesOfEnabledKnownBadHashSets);
}
@Override
public String getVersionNumber() {
return "1.0"; //NON-NLS
}
boolean shouldCalculateHashes() {
return shouldCalculateHashes;
}

View File

@ -100,9 +100,6 @@
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="alwaysCalcHashesCheckboxActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane2">
<Properties>

View File

@ -49,7 +49,7 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe
HashLookupModuleSettingsPanel(HashLookupModuleSettings settings) {
initializeHashSetModels(settings);
initComponents();
customizeComponents();
customizeComponents(settings);
}
private void initializeHashSetModels(HashLookupModuleSettings settings) {
@ -65,10 +65,10 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe
}
}
private void customizeComponents() {
private void customizeComponents(HashLookupModuleSettings settings) {
customizeHashSetsTable(jScrollPane1, knownHashTable, knownHashSetsTableModel);
customizeHashSetsTable(jScrollPane2, knownBadHashTable, knownBadHashSetsTableModel);
alwaysCalcHashesCheckbox.setSelected(hashDbManager.getAlwaysCalculateHashes());
alwaysCalcHashesCheckbox.setSelected(settings.shouldCalculateHashes());
hashDbManager.addPropertyChangeListener(this);
}
@ -280,11 +280,6 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe
knownHashDbsLabel.setText(org.openide.util.NbBundle.getMessage(HashLookupModuleSettingsPanel.class, "HashLookupModuleSettingsPanel.knownHashDbsLabel.text")); // NOI18N
alwaysCalcHashesCheckbox.setText(org.openide.util.NbBundle.getMessage(HashLookupModuleSettingsPanel.class, "HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.text")); // NOI18N
alwaysCalcHashesCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
alwaysCalcHashesCheckboxActionPerformed(evt);
}
});
jScrollPane2.setBorder(javax.swing.BorderFactory.createEtchedBorder());
@ -336,9 +331,6 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe
);
}// </editor-fold>//GEN-END:initComponents
private void alwaysCalcHashesCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_alwaysCalcHashesCheckboxActionPerformed
hashDbManager.setAlwaysCalculateHashes(alwaysCalcHashesCheckbox.isSelected());
}//GEN-LAST:event_alwaysCalcHashesCheckboxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JCheckBox alwaysCalcHashesCheckbox;
private javax.swing.JScrollPane jScrollPane1;

View File

@ -34,6 +34,11 @@ final class KeywordSearchJobSettings implements IngestModuleIngestJobSettings {
this.namesOfEnabledKeywordLists.addAll(namesOfEnabledKeywordLists);
}
@Override
public String getVersionNumber() {
return "1.0"; //NON-NLS
}
boolean isKeywordListEnabled(String keywordListName) {
return namesOfEnabledKeywordLists.contains(keywordListName);
}