From 4658dac1c361d9be46246e26f1c058d273c75647 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 21 Nov 2014 00:36:12 -0500 Subject: [PATCH 01/27] Add class skeletons and new method skeletons for user-defined file type sigs --- .../filetypeid/FileTypeIdIngestModule.java | 226 ++++++++++-------- .../filetypeid/FileTypeIdModuleFactory.java | 55 ++++- .../filetypeid/FileTypeIdModuleSettings.java | 4 + .../FileTypeIdModuleSettingsPanel.java | 15 +- .../FileTypeIdOptionsPanelController.java | 96 ++++++++ .../filetypeid/FileTypeIdSettingsPanel.form | 28 +++ .../filetypeid/FileTypeIdSettingsPanel.java | 93 +++++++ 7 files changed, 410 insertions(+), 107 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java create mode 100644 Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form create mode 100644 Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java index 2abb69974a..df575fe18d 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java @@ -27,9 +27,6 @@ import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.autopsy.ingest.IngestMessage; import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData.FileKnown; import org.sleuthkit.datamodel.TskException; @@ -45,102 +42,11 @@ public class FileTypeIdIngestModule implements FileIngestModule { private static final Logger logger = Logger.getLogger(FileTypeIdIngestModule.class.getName()); private static final long MIN_FILE_SIZE = 512; private final FileTypeIdModuleSettings settings; - private long jobId; - + private long jobId; private static final HashMap totalsForIngestJobs = new HashMap<>(); private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter(); - private TikaFileTypeDetector tikaDetector = new TikaFileTypeDetector(); + private final TikaFileTypeDetector tikaDetector = new TikaFileTypeDetector(); - private static class IngestJobTotals { - long matchTime = 0; - long numFiles = 0; - } - - /** - * Update the match time total and increment num of files for this job - * @param ingestJobId - * @param matchTimeInc amount of time to add - */ - private static synchronized void addToTotals(long ingestJobId, long matchTimeInc) { - IngestJobTotals ingestJobTotals = totalsForIngestJobs.get(ingestJobId); - if (ingestJobTotals == null) { - ingestJobTotals = new IngestJobTotals(); - totalsForIngestJobs.put(ingestJobId, ingestJobTotals); - } - - ingestJobTotals.matchTime += matchTimeInc; - ingestJobTotals.numFiles++; - totalsForIngestJobs.put(ingestJobId, ingestJobTotals); - } - - FileTypeIdIngestModule(FileTypeIdModuleSettings settings) { - this.settings = settings; - } - - @Override - public void startUp(IngestJobContext context) throws IngestModuleException { - jobId = context.getJobId(); - refCounter.incrementAndGet(jobId); - } - - @Override - public ProcessResult process(AbstractFile abstractFile) { - // skip non-files - if ((abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) - || (abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)) { - - return ProcessResult.OK; - } - - if (settings.skipKnownFiles() && (abstractFile.getKnown() == FileKnown.KNOWN)) { - return ProcessResult.OK; - } - - if (abstractFile.getSize() < MIN_FILE_SIZE) { - return ProcessResult.OK; - } - - try { - long startTime = System.currentTimeMillis(); - tikaDetector.detectAndSave(abstractFile); - addToTotals(jobId, (System.currentTimeMillis() - startTime)); //add match time - return ProcessResult.OK; - } catch (TskException ex) { - logger.log(Level.WARNING, "Error matching file signature", ex); //NON-NLS - return ProcessResult.ERROR; - } catch (Exception e) { - logger.log(Level.WARNING, "Error matching file signature", e); //NON-NLS - return ProcessResult.ERROR; - } - } - - @Override - public void shutDown() { - // We only need to post the summary msg from the last module per job - if (refCounter.decrementAndGet(jobId) == 0) { - IngestJobTotals jobTotals; - synchronized(this) { - jobTotals = totalsForIngestJobs.remove(jobId); - } - if (jobTotals != null) { - StringBuilder detailsSb = new StringBuilder(); - detailsSb.append(""); //NON-NLS - detailsSb.append(""); //NON-NLS - detailsSb.append("\n"); //NON-NLS - detailsSb.append("\n"); //NON-NLS - detailsSb.append("
").append(FileTypeIdModuleFactory.getModuleName()).append("
") //NON-NLS - .append(NbBundle.getMessage(this.getClass(), "FileTypeIdIngestModule.complete.totalProcTime")) - .append("").append(jobTotals.matchTime).append("
") //NON-NLS - .append(NbBundle.getMessage(this.getClass(), "FileTypeIdIngestModule.complete.totalFiles")) - .append("").append(jobTotals.numFiles).append("
"); //NON-NLS - IngestServices.getInstance().postMessage(IngestMessage.createMessage(IngestMessage.MessageType.INFO, FileTypeIdModuleFactory.getModuleName(), - NbBundle.getMessage(this.getClass(), - "FileTypeIdIngestModule.complete.srvMsg.text"), - detailsSb.toString())); - } - } - } - /** * Validate if a given mime type is in the detector's registry. * @@ -157,4 +63,130 @@ public class FileTypeIdIngestModule implements FileIngestModule { TikaFileTypeDetector detector = new TikaFileTypeDetector(); return detector.isMimeTypeDetectable(mimeType); } -} \ No newline at end of file + + /** + * Creates an ingest module that detects the type of a file based on + * signature (magic) values. Posts results to the blackboard. + * + * @param settings The ingest module settings. + */ + FileTypeIdIngestModule(FileTypeIdModuleSettings settings) { + this.settings = settings; + } + + /** + * @inheritDoc + */ + @Override + public void startUp(IngestJobContext context) throws IngestModuleException { + jobId = context.getJobId(); + refCounter.incrementAndGet(jobId); + } + + /** + * @inheritDoc + */ + @Override + public ProcessResult process(AbstractFile abstractFile) { + /** + * Skip unallocated space and unused blocks files. + */ + if ((abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) + || (abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)) { + + return ProcessResult.OK; + } + + /** + * Skip known files if configured to do so. + */ + if (settings.skipKnownFiles() && (abstractFile.getKnown() == FileKnown.KNOWN)) { + return ProcessResult.OK; + } + + /** + * Filter out very small files to minimize false positives. + */ + // RJCTODO: Make this size a setting + if (abstractFile.getSize() < MIN_FILE_SIZE) { + return ProcessResult.OK; + } + + try { + long startTime = System.currentTimeMillis(); + + // RJCTODO: Add code here to use nay user-defined signstures first; + // if there is a match, post a intersting file hit, if the user has + // elected alerts + tikaDetector.detectAndSave(abstractFile); + + addToTotals(jobId, (System.currentTimeMillis() - startTime)); + return ProcessResult.OK; + } catch (TskException ex) { + logger.log(Level.WARNING, "Error matching file signature", ex); //NON-NLS + return ProcessResult.ERROR; + } catch (Exception e) { + logger.log(Level.WARNING, "Error matching file signature", e); //NON-NLS + return ProcessResult.ERROR; + } + } + + /** + * @inheritDoc + */ + @Override + public void shutDown() { + /** + * If this is the instance of this module for this ingest job, post a + * summary message to the ingest messages box. + */ + if (refCounter.decrementAndGet(jobId) == 0) { + IngestJobTotals jobTotals; + synchronized (this) { + jobTotals = totalsForIngestJobs.remove(jobId); + } + if (jobTotals != null) { + StringBuilder detailsSb = new StringBuilder(); + detailsSb.append(""); //NON-NLS + detailsSb.append(""); //NON-NLS + detailsSb.append("\n"); //NON-NLS + detailsSb.append("\n"); //NON-NLS + detailsSb.append("
").append(FileTypeIdModuleFactory.getModuleName()).append("
") //NON-NLS + .append(NbBundle.getMessage(this.getClass(), "FileTypeIdIngestModule.complete.totalProcTime")) + .append("").append(jobTotals.matchTime).append("
") //NON-NLS + .append(NbBundle.getMessage(this.getClass(), "FileTypeIdIngestModule.complete.totalFiles")) + .append("").append(jobTotals.numFiles).append("
"); //NON-NLS + IngestServices.getInstance().postMessage(IngestMessage.createMessage(IngestMessage.MessageType.INFO, FileTypeIdModuleFactory.getModuleName(), + NbBundle.getMessage(this.getClass(), + "FileTypeIdIngestModule.complete.srvMsg.text"), + detailsSb.toString())); + } + } + } + + /** + * Update the match time total and increment number of files processed for + * this ingest job. + * + * @param jobId The ingest job identifier. + * @param matchTimeInc Amount of time to add. + */ + private static synchronized void addToTotals(long jobId, long matchTimeInc) { + IngestJobTotals ingestJobTotals = totalsForIngestJobs.get(jobId); + if (ingestJobTotals == null) { + ingestJobTotals = new IngestJobTotals(); + totalsForIngestJobs.put(jobId, ingestJobTotals); + } + + ingestJobTotals.matchTime += matchTimeInc; + ingestJobTotals.numFiles++; + totalsForIngestJobs.put(jobId, ingestJobTotals); + } + + private static class IngestJobTotals { + + long matchTime = 0; + long numFiles = 0; + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java index 6688fd8027..73d1e140e5 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java @@ -24,69 +24,114 @@ import org.sleuthkit.autopsy.coreutils.Version; import org.sleuthkit.autopsy.ingest.FileIngestModule; import org.sleuthkit.autopsy.ingest.IngestModuleFactory; import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter; +import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; /** - * An factory that creates file ingest modules that determine the types of - * files. + * A factory that creates file ingest modules that determine the types of files. */ @ServiceProvider(service = IngestModuleFactory.class) public class FileTypeIdModuleFactory extends IngestModuleFactoryAdapter { + /** + * @inheritDoc + */ @Override public String getModuleDisplayName() { return getModuleName(); } + /** + * Gets the module display name. + * + * @return The name string. + */ static String getModuleName() { return NbBundle.getMessage(FileTypeIdIngestModule.class, "FileTypeIdIngestModule.moduleName.text"); } + /** + * @inheritDoc + */ @Override public String getModuleDescription() { return NbBundle.getMessage(FileTypeIdIngestModule.class, "FileTypeIdIngestModule.moduleDesc.text"); } + /** + * @inheritDoc + */ @Override public String getModuleVersionNumber() { return Version.getVersion(); } + /** + * @inheritDoc + */ + @Override + public boolean hasGlobalSettingsPanel() { + return true; + } + + /** + * @inheritDoc + */ + @Override + public IngestModuleGlobalSettingsPanel getGlobalSettingsPanel() { + return new FileTypeIdSettingsPanel(); + } + + /** + * @inheritDoc + */ @Override public IngestModuleIngestJobSettings getDefaultIngestJobSettings() { return new FileTypeIdModuleSettings(); } + /** + * @inheritDoc + */ @Override public boolean hasIngestJobSettingsPanel() { return true; } + /** + * @inheritDoc + */ @Override public IngestModuleIngestJobSettingsPanel getIngestJobSettingsPanel(IngestModuleIngestJobSettings settings) { assert settings instanceof FileTypeIdModuleSettings; if (!(settings instanceof FileTypeIdModuleSettings)) { throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), - "FileTypeIdModuleFactory.getIngestJobSettingsPanel.exception.msg")); - } + "FileTypeIdModuleFactory.getIngestJobSettingsPanel.exception.msg")); + } return new FileTypeIdModuleSettingsPanel((FileTypeIdModuleSettings) settings); } + /** + * @inheritDoc + */ @Override public boolean isFileIngestModuleFactory() { return true; } + /** + * @inheritDoc + */ @Override public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings settings) { assert settings instanceof FileTypeIdModuleSettings; if (!(settings instanceof FileTypeIdModuleSettings)) { throw new IllegalArgumentException( NbBundle.getMessage(this.getClass(), "FileTypeIdModuleFactory.createFileIngestModule.exception.msg")); - } + } return new FileTypeIdIngestModule((FileTypeIdModuleSettings) settings); } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java index c472596be4..31e077a875 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java @@ -23,6 +23,7 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; /** * Ingest job options for the file type identifier ingest module instances. */ +// @Deprecated This class is not for public use public class FileTypeIdModuleSettings implements IngestModuleIngestJobSettings { private static final long serialVersionUID = 1L; @@ -35,6 +36,9 @@ public class FileTypeIdModuleSettings implements IngestModuleIngestJobSettings { this.skipKnownFiles = skipKnownFiles; } + /** + * @inheritDoc + */ @Override public long getVersionNumber() { return serialVersionUID; diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettingsPanel.java index 3839d2c711..bf86217a50 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettingsPanel.java @@ -29,20 +29,25 @@ final class FileTypeIdModuleSettingsPanel extends IngestModuleIngestJobSettingsP private final FileTypeIdModuleSettings settings; - public FileTypeIdModuleSettingsPanel(FileTypeIdModuleSettings settings) { + // NOTE: This was declared public, but was inaccessible because the class is + // not public + FileTypeIdModuleSettingsPanel(FileTypeIdModuleSettings settings) { this.settings = settings; initComponents(); customizeComponents(); } - private void customizeComponents() { - skipKnownCheckBox.setSelected(settings.skipKnownFiles()); - } - + /** + * @inheritDoc + */ @Override public IngestModuleIngestJobSettings getSettings() { return settings; } + + private void customizeComponents() { + skipKnownCheckBox.setSelected(settings.skipKnownFiles()); + } /** * This method is called from within the constructor to initialize the form. diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java new file mode 100644 index 0000000000..4209dd9dc5 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java @@ -0,0 +1,96 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.modules.filetypeid; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import javax.swing.JComponent; +import javax.swing.SwingUtilities; +import org.netbeans.spi.options.OptionsPanelController; +import org.openide.util.HelpCtx; +import org.openide.util.Lookup; + +@OptionsPanelController.TopLevelRegistration( + categoryName = "#OptionsCategory_Name_FileTypeId", + iconBase = "org/sleuthkit/autopsy/corecomponents/display-options.png", + keywords = "#OptionsCategory_Keywords_FileTypeId", + keywordsCategory = "FileTypeId" +) +@org.openide.util.NbBundle.Messages({"OptionsCategory_Name_FileTypeId=FileTypeId", "OptionsCategory_Keywords_FileTypeId=FileTypeId"}) +public final class FileTypeIdOptionsPanelController extends OptionsPanelController { + + private FileTypeIdSettingsPanel panel; + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + private boolean changed; + + @Override + public void update() { + getPanel().load(); + changed = false; + } + + @Override + public void applyChanges() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + getPanel().store(); + changed = false; + } + }); + } + + @Override + public void cancel() { + // need not do anything special, if no changes have been persisted yet + } + + @Override + public boolean isValid() { + return getPanel().valid(); + } + + @Override + public boolean isChanged() { + return changed; + } + + @Override + public HelpCtx getHelpCtx() { + return null; // new HelpCtx("...ID") if you have a help set + } + + @Override + public JComponent getComponent(Lookup masterLookup) { + return getPanel(); + } + + @Override + public void addPropertyChangeListener(PropertyChangeListener l) { + pcs.addPropertyChangeListener(l); + } + + @Override + public void removePropertyChangeListener(PropertyChangeListener l) { + pcs.removePropertyChangeListener(l); + } + + private FileTypeIdSettingsPanel getPanel() { + if (panel == null) { + panel = new FileTypeIdSettingsPanel(); + } + return panel; + } + + void changed() { + if (!changed) { + changed = true; + pcs.firePropertyChange(OptionsPanelController.PROP_CHANGED, false, true); + } + pcs.firePropertyChange(OptionsPanelController.PROP_VALID, null, null); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form new file mode 100644 index 0000000000..4f9abb50dc --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form @@ -0,0 +1,28 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java new file mode 100644 index 0000000000..10a0291cfe --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java @@ -0,0 +1,93 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2014 Basis Technology Corp. + * Contact: carrier sleuthkit 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.modules.filetypeid; + +import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; + +/** + * RJCTODO + */ +class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { + + /** + * Creates... RJCTODO + */ + FileTypeIdSettingsPanel() { + initComponents(); + } + + /** + * @inheritDoc + */ + @Override + public void saveSettings() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + void load() { + // RJCTODO read settings and initialize GUI + // Example: + // someCheckBox.setSelected(Preferences.userNodeForPackage(FileTypeIdPanel.class).getBoolean("someFlag", false)); + // or for org.openide.util with API spec. version >= 7.4: + // someCheckBox.setSelected(NbPreferences.forModule(FileTypeIdPanel.class).getBoolean("someFlag", false)); + // or: + // someTextField.setText(SomeSystemOption.getDefault().getSomeStringProperty()); + } + + void store() { + // RJCTODO store modified settings + // Example: + // Preferences.userNodeForPackage(FileTypeIdPanel.class).putBoolean("someFlag", someCheckBox.isSelected()); + // or for org.openide.util with API spec. version >= 7.4: + // NbPreferences.forModule(FileTypeIdPanel.class).putBoolean("someFlag", someCheckBox.isSelected()); + // or: + // SomeSystemOption.getDefault().setSomeStringProperty(someTextField.getText()); + } + + boolean valid() { + // RJCTODO check whether form is consistent and complete + return true; + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 400, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 300, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + + + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables + +} From 60f33f61bb3bb320e3b9218e29a7e31e1d12c229 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 21 Nov 2014 07:57:04 -0500 Subject: [PATCH 02/27] Check in partial implementation of user defined file type sigs --- .../UserDefinedFileTypeDetector.java | 171 ++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeDetector.java diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeDetector.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeDetector.java new file mode 100644 index 0000000000..2adcada8cf --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeDetector.java @@ -0,0 +1,171 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2014 Basis Technology Corp. + * Contact: carrier sleuthkit 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.modules.filetypeid; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * RJCTODO + */ +class UserDefinedFileTypeDetector { + + private final List matchers; + private String detectedType; + + static UserDefinedFileTypeDetector createDetector(String sigFilePath) { + UserDefinedFileTypeDetector detector = new UserDefinedFileTypeDetector(); + detector.loadSignatures(sigFilePath); + return detector; + } + + /** + * RJCTODO + * + * @param sigFilePath + */ + UserDefinedFileTypeDetector() { + this.matchers = new ArrayList<>(); + } + + /** + * RJCTODO + */ + private void loadSignatures(String sigFilePath) { + // RJCTODO: Load signature file, creating + } + + /** + * + * @param file + * @return + */ + boolean detect(AbstractFile file) { + for (SignatureMatcher matcher : this.matchers) { + if (matcher.matched(file)) { + this.detectedType = matcher.getMatchType(); + return true; + } + } + this.detectedType = ""; // RJCTODO: Wrap this stuff in a class + return false; + } + + /** + * RJCTODO + * @return + */ + String getDetectedType() { + // RJCTODO + return ""; + } + + /** + * + */ + private static class SignatureMatcher { + + private final List matchers; + private final String matchType; + + /** + * RJCTODO + * + * @param matchType + */ + SignatureMatcher(String matchType) { + this.matchType = matchType; + this.matchers = new ArrayList<>(); + } + + /** + * RJCTODO + * + * @param file + * @return + */ + boolean matched(AbstractFile file) { + for (Matcher matcher : this.matchers) { + if (!matcher.matched(file)) { + return false; + } + } + return true; + } + + /** + * RJCTODO + * + * @return + */ + String getMatchType() { + return this.matchType; + } + + } + + private static interface Matcher { + + /** + * RJCTODO + * + * @param file + * @return + */ + boolean matched(AbstractFile file); + + } + + /** + * A signature matcher that looks for a sequence of bytes at a specified + * offset. + */ + private static class ByteMatcher implements Matcher { + + private final long offset; + private final byte[] signature; + private final byte[] buffer; + + private ByteMatcher(long offset, byte[] signature) { + this.offset = offset; + this.signature = signature; + this.buffer = new byte[signature.length]; + } + + /** + * @inheritDoc + */ + @Override + public boolean matched(AbstractFile file) { + try { + // RJCTODO: Confirm this logic + int bytesRead = file.read(this.buffer, offset, buffer.length); + return bytesRead == buffer.length ? Arrays.equals(this.buffer, this.signature) : false; + } catch (TskCoreException ex) { + // RJCTODO + return false; + } + } + + } + +} From cfc58077979dfe5d393202c4bb00cac0bb6078f0 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 21 Nov 2014 17:46:07 -0500 Subject: [PATCH 03/27] Check in incomplete editing of user defined file sigs feature --- .../modules/filetypeid/Bundle.properties | 12 + .../filetypeid/FileTypeIdSettingsPanel.form | 261 +++++++++++++++++- .../filetypeid/FileTypeIdSettingsPanel.java | 167 ++++++++++- .../UserDefinedFileTypeDetector.java | 171 ------------ .../UserDefinedFileTypeIdentifier.java | 81 ++++++ .../filetypeid/UserDefinedFileTypes.java | 173 ++++++++++++ 6 files changed, 687 insertions(+), 178 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeDetector.java create mode 100644 Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java create mode 100644 Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.java diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties index 1369d3d332..7ac88eec61 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties @@ -8,3 +8,15 @@ FileTypeIdIngestModule.complete.srvMsg.text=File Type Id Results FileTypeIdModuleFactory.getIngestJobSettingsPanel.exception.msg=Expected settings argument to be instanceof FileTypeIdModuleSettings FileTypeIdModuleFactory.createFileIngestModule.exception.msg=Expected settings argument to be instanceof FileTypeIdModuleSettings FileTypeIdModuleSettingsPanel.skipKnownCheckBox.text=Skip known files (NSRL) +FileTypeIdSettingsPanel.jTextField2.text= +FileTypeIdSettingsPanel.jButton1.text=New Type +FileTypeIdSettingsPanel.jButton2.text=DeleteType +FileTypeIdSettingsPanel.jButton3.text=Save Type +FileTypeIdSettingsPanel.mimeTypeTextField.text= +FileTypeIdSettingsPanel.mimeTypeLabel.text=Mime Type +FileTypeIdSettingsPanel.signatureTypeLabel.text=Signature Type +FileTypeIdSettingsPanel.signatureLabel.text=Signature +FileTypeIdSettingsPanel.offsetLabel.text=Offset +FileTypeIdSettingsPanel.offsetTextField.text= +FileTypeIdSettingsPanel.hexPrefixLabel.text=0x +FileTypeIdSettingsPanel.jTextArea1.text=Enter a MIME type and signature to be used to identify files of that type. If the signature is a byte sequence, enter the sequence using two hex values for each byte, e.g., EEF0. diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form index 4f9abb50dc..27806b6718 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form @@ -1,6 +1,10 @@ -
+ + + + + @@ -16,13 +20,264 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java index 10a0291cfe..8e5018d3e8 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java @@ -30,6 +30,7 @@ class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { */ FileTypeIdSettingsPanel() { initComponents(); + } /** @@ -39,7 +40,7 @@ class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { public void saveSettings() { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - + void load() { // RJCTODO read settings and initialize GUI // Example: @@ -61,7 +62,6 @@ class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { } boolean valid() { - // RJCTODO check whether form is consistent and complete return true; } @@ -74,20 +74,179 @@ class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { // //GEN-BEGIN:initComponents private void initComponents() { + buttonGroup1 = new javax.swing.ButtonGroup(); + jScrollPane1 = new javax.swing.JScrollPane(); + jList1 = new javax.swing.JList(); + jSeparator1 = new javax.swing.JSeparator(); + mimeTypeLabel = new javax.swing.JLabel(); + mimeTypeTextField = new javax.swing.JTextField(); + signatureTypeLabel = new javax.swing.JLabel(); + jTextField2 = new javax.swing.JTextField(); + offsetLabel = new javax.swing.JLabel(); + offsetTextField = new javax.swing.JTextField(); + jButton1 = new javax.swing.JButton(); + jButton2 = new javax.swing.JButton(); + jButton3 = new javax.swing.JButton(); + hexPrefixLabel = new javax.swing.JLabel(); + signatureTypeComboBox = new javax.swing.JComboBox(); + signatureLabel = new javax.swing.JLabel(); + jScrollPane2 = new javax.swing.JScrollPane(); + jTextArea1 = new javax.swing.JTextArea(); + + jScrollPane1.setViewportView(jList1); + + jSeparator1.setOrientation(javax.swing.SwingConstants.VERTICAL); + + org.openide.awt.Mnemonics.setLocalizedText(mimeTypeLabel, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.mimeTypeLabel.text")); // NOI18N + + mimeTypeTextField.setText(org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.mimeTypeTextField.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(signatureTypeLabel, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.signatureTypeLabel.text")); // NOI18N + + jTextField2.setText(org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.jTextField2.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(offsetLabel, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.offsetLabel.text")); // NOI18N + + offsetTextField.setText(org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.offsetTextField.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.jButton1.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jButton2, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.jButton2.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jButton3, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.jButton3.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(hexPrefixLabel, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.hexPrefixLabel.text")); // NOI18N + + signatureTypeComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Bytes (Hex)", "String", " " })); + + org.openide.awt.Mnemonics.setLocalizedText(signatureLabel, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.signatureLabel.text")); // NOI18N + + jTextArea1.setEditable(false); + jTextArea1.setColumns(20); + jTextArea1.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N + jTextArea1.setLineWrap(true); + jTextArea1.setRows(5); + jTextArea1.setText(org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.jTextArea1.text")); // NOI18N + jTextArea1.setWrapStyleWord(true); + jScrollPane2.setViewportView(jTextArea1); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 400, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addGap(26, 26, 26) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(10, 10, 10) + .addComponent(jButton1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jButton2)) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(37, 37, 37) + .addComponent(jButton3) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(layout.createSequentialGroup() + .addGap(18, 18, 18) + .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 13, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addComponent(signatureTypeLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(signatureTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 82, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(signatureLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(hexPrefixLabel) + .addGap(2, 2, 2)) + .addGroup(layout.createSequentialGroup() + .addComponent(offsetLabel) + .addGap(44, 44, 44))) + .addGap(5, 5, 5) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(offsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 84, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jTextField2, javax.swing.GroupLayout.PREFERRED_SIZE, 178, javax.swing.GroupLayout.PREFERRED_SIZE))))) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addGap(6, 6, 6) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 260, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createSequentialGroup() + .addComponent(mimeTypeLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(mimeTypeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 181, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGap(0, 0, Short.MAX_VALUE))) + .addContainerGap()))) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 300, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addGap(16, 16, 16) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 219, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createSequentialGroup() + .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(mimeTypeLabel) + .addComponent(mimeTypeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(signatureTypeLabel) + .addComponent(signatureTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jTextField2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(hexPrefixLabel) + .addComponent(signatureLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(offsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(offsetLabel)) + .addGap(12, 12, 12))) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addGroup(layout.createSequentialGroup() + .addGap(18, 18, 18) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jButton1) + .addComponent(jButton2))) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jButton3)))) + .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 260, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.ButtonGroup buttonGroup1; + private javax.swing.JLabel hexPrefixLabel; + private javax.swing.JButton jButton1; + private javax.swing.JButton jButton2; + private javax.swing.JButton jButton3; + private javax.swing.JList jList1; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JScrollPane jScrollPane2; + private javax.swing.JSeparator jSeparator1; + private javax.swing.JTextArea jTextArea1; + private javax.swing.JTextField jTextField2; + private javax.swing.JLabel mimeTypeLabel; + private javax.swing.JTextField mimeTypeTextField; + private javax.swing.JLabel offsetLabel; + private javax.swing.JTextField offsetTextField; + private javax.swing.JLabel signatureLabel; + private javax.swing.JComboBox signatureTypeComboBox; + private javax.swing.JLabel signatureTypeLabel; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeDetector.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeDetector.java deleted file mode 100644 index 2adcada8cf..0000000000 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeDetector.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2014 Basis Technology Corp. - * Contact: carrier sleuthkit 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.modules.filetypeid; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * RJCTODO - */ -class UserDefinedFileTypeDetector { - - private final List matchers; - private String detectedType; - - static UserDefinedFileTypeDetector createDetector(String sigFilePath) { - UserDefinedFileTypeDetector detector = new UserDefinedFileTypeDetector(); - detector.loadSignatures(sigFilePath); - return detector; - } - - /** - * RJCTODO - * - * @param sigFilePath - */ - UserDefinedFileTypeDetector() { - this.matchers = new ArrayList<>(); - } - - /** - * RJCTODO - */ - private void loadSignatures(String sigFilePath) { - // RJCTODO: Load signature file, creating - } - - /** - * - * @param file - * @return - */ - boolean detect(AbstractFile file) { - for (SignatureMatcher matcher : this.matchers) { - if (matcher.matched(file)) { - this.detectedType = matcher.getMatchType(); - return true; - } - } - this.detectedType = ""; // RJCTODO: Wrap this stuff in a class - return false; - } - - /** - * RJCTODO - * @return - */ - String getDetectedType() { - // RJCTODO - return ""; - } - - /** - * - */ - private static class SignatureMatcher { - - private final List matchers; - private final String matchType; - - /** - * RJCTODO - * - * @param matchType - */ - SignatureMatcher(String matchType) { - this.matchType = matchType; - this.matchers = new ArrayList<>(); - } - - /** - * RJCTODO - * - * @param file - * @return - */ - boolean matched(AbstractFile file) { - for (Matcher matcher : this.matchers) { - if (!matcher.matched(file)) { - return false; - } - } - return true; - } - - /** - * RJCTODO - * - * @return - */ - String getMatchType() { - return this.matchType; - } - - } - - private static interface Matcher { - - /** - * RJCTODO - * - * @param file - * @return - */ - boolean matched(AbstractFile file); - - } - - /** - * A signature matcher that looks for a sequence of bytes at a specified - * offset. - */ - private static class ByteMatcher implements Matcher { - - private final long offset; - private final byte[] signature; - private final byte[] buffer; - - private ByteMatcher(long offset, byte[] signature) { - this.offset = offset; - this.signature = signature; - this.buffer = new byte[signature.length]; - } - - /** - * @inheritDoc - */ - @Override - public boolean matched(AbstractFile file) { - try { - // RJCTODO: Confirm this logic - int bytesRead = file.read(this.buffer, offset, buffer.length); - return bytesRead == buffer.length ? Arrays.equals(this.buffer, this.signature) : false; - } catch (TskCoreException ex) { - // RJCTODO - return false; - } - } - - } - -} diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java new file mode 100644 index 0000000000..d96d7b4f5f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java @@ -0,0 +1,81 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2014 Basis Technology Corp. + * Contact: carrier sleuthkit 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.modules.filetypeid; + +import java.util.ArrayList; +import java.util.List; +import org.sleuthkit.datamodel.AbstractFile; + +/** + * Does file type identification with user-defined file type signatures. + */ +class UserDefinedFileTypeIdentifier { + + private static final String USER_DEFINITIONS_FILE = "UserFileTypeDefinitions.xml"; + private static final String AUTOPSY_DEFINITIONS_FILE = "AutopsyFileTypeDefinitions.xml"; + private final List signatures; + + /** + * Creates an object that does file type identification with user-defined + * file type signatures. + * + * @param sigFilePath A path to a signature definitions file. + */ + static UserDefinedFileTypeIdentifier createDetector(String sigFilePath) { + UserDefinedFileTypeIdentifier detector = new UserDefinedFileTypeIdentifier(); + detector.loadSignatures(sigFilePath); + return detector; + } + + /** + * Create an object that does file type identification with user-defined + * file type signatures. + */ + private UserDefinedFileTypeIdentifier() { + this.signatures = new ArrayList<>(); + } + + /** + * Loads a set of user-defined file type signatures from a file. + * + * @param sigFilePath The path to the signature definitions file. + */ + private void loadSignatures(String sigFilePath) { + // RJCTODO: Load signature file, creating + } + + /** + * Attempts to identify a file using the set of user-defined file type + * signatures. + * + * @param file The file to type. + * @return A MIME type string or the empty string if identification fails. + */ + String identify(AbstractFile file) { + String type = ""; + for (UserDefinedFileTypes.FileSignature signature : this.signatures) { + if (signature.containedIn(file)) { + type = signature.getMimeType(); + break; + } + } + return type; + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.java new file mode 100644 index 0000000000..fcd275a89f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.java @@ -0,0 +1,173 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2014 Basis Technology Corp. + * Contact: carrier sleuthkit 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.modules.filetypeid; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.XMLUtil; +import org.sleuthkit.autopsy.externalresults.ExternalResultsXMLParser; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.TskCoreException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +/** + * RJCTODO + */ +public class UserDefinedFileTypes { + + private static final String ROOT_FILE_TYPES_ELEMENT = "fileTypes"; // NON-NLS + private static final String FILE_TYPE_ELEMENT = "fileType"; // NON-NLS + private static final String MIME_TYPE_ELEMENT = "mimeType"; // NON-NLS + private static final String SIGNATURE_ELEMENT = "signature"; // NON-NLS + private static final String OFFSET_ELEMENT = "offset"; + + /** + * An association between a MIME type and a signature within a file. + */ + static interface FileSignature { + + /** + * Gets the MIME type associated with this signature. + * + * @return The MIME type string. + */ + String getMimeType(); + + /** + * Determines whether or not a file contains the signature. + * + * @param file The file to test. + * @return True or false. + */ + boolean containedIn(AbstractFile file); + + } + + /** + * An association between a MIME type and a byte signature at a specified + * offset within a file. + */ + static class ByteSignature implements FileSignature { + + private final String mimeType; + private final byte[] signatureBytes; + private final long offset; + private final byte[] buffer; + + /** + * Creates an association between a MIME type and a byte signature at a + * specified offset. + * + * @param mimeType The MIME type string. + * @param signatureBytes The bytes of the signature. + * @param offset The offset of the signature within a file. + */ + private ByteSignature(String mimeType, byte[] signatureBytes, long offset) { + this.mimeType = mimeType; + this.signatureBytes = signatureBytes; + this.offset = offset; + this.buffer = new byte[signatureBytes.length]; + } + + /** + * @inheritDoc + */ + @Override + public String getMimeType() { + return this.mimeType; + } + + /** + * @inheritDoc + */ + @Override + public boolean containedIn(AbstractFile file) { + try { + int bytesRead = file.read(this.buffer, offset, buffer.length); + return bytesRead == buffer.length ? Arrays.equals(this.buffer, this.signatureBytes) : false; + } catch (TskCoreException ex) { + return false; + } + } + + } + + /** + * Provides a mechanism for persisting user-defined file types. + */ + static class Writer { + + /** + * Reads user-defined file type definitions from a file. + * + * @param signatures A collection of file signatures. + * @param filePath The path to the file. + */ + static void writeFileTypes(List signatures, String filePath) { + + } + + } + + /** + * Provides a method for reading persisted user-defined file types. + */ + static class Reader { + + /** + * Reads user-defined file type definitions from a file. + * + * @param filePath The path to the file. + * @return A collection of file signatures. + */ + static List readFileTypes(String filePath) { + // RJCTODO: + try { + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + Document doc = builder.parse(new FileInputStream(filePath)); + final Document doc = XMLUtil.loadDoc(ExternalResultsXMLParser.class, this.resultsFilePath, XSD_FILE); + if (doc != null) { + final Element rootElem = doc.getDocumentElement(); + if (rootElem != null && rootElem.getNodeName().equals(ExternalResultsXMLParser.TagNames.ROOT_ELEM.toString())) { + + } catch (ParserConfigurationException e) { + } catch (SAXException e) { + } catch (IOException e) { + } + + + + + return Collections.emptyList(); + } + + } + +} From 2ace5b2fbbe152447a3d03278d78906df2c4d33c Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 24 Nov 2014 16:58:59 -0500 Subject: [PATCH 04/27] Checdk in work on user defined file types --- .../modules/filetypeid/Bundle.properties | 3 +- .../filetypeid/FileTypeIdSettingsPanel.form | 47 ++-- .../filetypeid/FileTypeIdSettingsPanel.java | 40 ++-- .../UserDefinedFileTypeIdentifier.java | 4 +- .../filetypeid/UserDefinedFileTypes.java | 220 +++++++++++++++--- 5 files changed, 254 insertions(+), 60 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties index 7ac88eec61..58978a9b5d 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties @@ -19,4 +19,5 @@ FileTypeIdSettingsPanel.signatureLabel.text=Signature FileTypeIdSettingsPanel.offsetLabel.text=Offset FileTypeIdSettingsPanel.offsetTextField.text= FileTypeIdSettingsPanel.hexPrefixLabel.text=0x -FileTypeIdSettingsPanel.jTextArea1.text=Enter a MIME type and signature to be used to identify files of that type. If the signature is a byte sequence, enter the sequence using two hex values for each byte, e.g., EEF0. +FileTypeIdSettingsPanel.jTextArea1.text=Enter a MIME type and signature to be used to identify files of that type. If the signature is a byte sequence, enter the sequence using two hex values for each byte, e.g., EEF0 is a two byte signature. +FileTypeIdSettingsPanel.postHitCheckBox.text=Post interesting file hit when found diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form index 27806b6718..efb8311caf 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form @@ -40,25 +40,25 @@ - + - + - + - + - + @@ -69,18 +69,25 @@ - - - - - - - + + + + + + + + + + + + + + @@ -96,11 +103,11 @@ - + - + - + @@ -121,7 +128,8 @@ - + + @@ -279,5 +287,12 @@ + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java index 8e5018d3e8..c0ffdbfd3b 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java @@ -18,7 +18,9 @@ */ package org.sleuthkit.autopsy.modules.filetypeid; +import java.util.List; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; +import org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypes.FileTypeSignature; /** * RJCTODO @@ -42,6 +44,8 @@ class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { } void load() { + List fileTypeSignatures; + // RJCTODO read settings and initialize GUI // Example: // someCheckBox.setSelected(Preferences.userNodeForPackage(FileTypeIdPanel.class).getBoolean("someFlag", false)); @@ -92,6 +96,7 @@ class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { signatureLabel = new javax.swing.JLabel(); jScrollPane2 = new javax.swing.JScrollPane(); jTextArea1 = new javax.swing.JTextArea(); + postHitCheckBox = new javax.swing.JCheckBox(); jScrollPane1.setViewportView(jList1); @@ -130,6 +135,8 @@ class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { jTextArea1.setWrapStyleWord(true); jScrollPane2.setViewportView(jTextArea1); + org.openide.awt.Mnemonics.setLocalizedText(postHitCheckBox, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.postHitCheckBox.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -151,8 +158,8 @@ class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { .addGroup(layout.createSequentialGroup() .addGap(18, 18, 18) .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 13, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addGroup(layout.createSequentialGroup() @@ -173,15 +180,20 @@ class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { .addGap(5, 5, 5) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(offsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 84, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jTextField2, javax.swing.GroupLayout.PREFERRED_SIZE, 178, javax.swing.GroupLayout.PREFERRED_SIZE))))) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addGap(6, 6, 6) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 260, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(layout.createSequentialGroup() + .addComponent(jTextField2, javax.swing.GroupLayout.PREFERRED_SIZE, 178, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addGap(2, 2, 2) .addComponent(mimeTypeLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(mimeTypeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 181, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(mimeTypeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 181, javax.swing.GroupLayout.PREFERRED_SIZE)))) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(6, 6, 6) + .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 260, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(postHitCheckBox))) .addGap(0, 0, Short.MAX_VALUE))) .addContainerGap()))) ); @@ -191,11 +203,11 @@ class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { .addGap(16, 16, 16) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 219, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(layout.createSequentialGroup() + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(18, 18, 18) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(mimeTypeLabel) .addComponent(mimeTypeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) @@ -212,7 +224,8 @@ class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(offsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(offsetLabel)) - .addGap(12, 12, 12))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(postHitCheckBox))) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addGroup(layout.createSequentialGroup() .addGap(18, 18, 18) @@ -244,6 +257,7 @@ class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { private javax.swing.JTextField mimeTypeTextField; private javax.swing.JLabel offsetLabel; private javax.swing.JTextField offsetTextField; + private javax.swing.JCheckBox postHitCheckBox; private javax.swing.JLabel signatureLabel; private javax.swing.JComboBox signatureTypeComboBox; private javax.swing.JLabel signatureTypeLabel; diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java index d96d7b4f5f..860a6b65cf 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java @@ -29,7 +29,7 @@ class UserDefinedFileTypeIdentifier { private static final String USER_DEFINITIONS_FILE = "UserFileTypeDefinitions.xml"; private static final String AUTOPSY_DEFINITIONS_FILE = "AutopsyFileTypeDefinitions.xml"; - private final List signatures; + private final List signatures; /** * Creates an object that does file type identification with user-defined @@ -69,7 +69,7 @@ class UserDefinedFileTypeIdentifier { */ String identify(AbstractFile file) { String type = ""; - for (UserDefinedFileTypes.FileSignature signature : this.signatures) { + for (UserDefinedFileTypes.FileTypeSignature signature : this.signatures) { if (signature.containedIn(file)) { type = signature.getMimeType(); break; diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.java index fcd275a89f..690433b416 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.java @@ -18,39 +18,62 @@ */ package org.sleuthkit.autopsy.modules.filetypeid; +import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.logging.Level; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.XMLUtil; -import org.sleuthkit.autopsy.externalresults.ExternalResultsXMLParser; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.w3c.dom.NodeList; import org.xml.sax.SAXException; +import javax.xml.bind.DatatypeConverter; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.sleuthkit.autopsy.coreutils.XMLUtil; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; /** * RJCTODO */ public class UserDefinedFileTypes { + private static final String USER_DEFINED_TYPE_DEFINITIONS_FILE = "UserFileTypeDefinitions.xml"; // NON-NLS private static final String ROOT_FILE_TYPES_ELEMENT = "fileTypes"; // NON-NLS private static final String FILE_TYPE_ELEMENT = "fileType"; // NON-NLS private static final String MIME_TYPE_ELEMENT = "mimeType"; // NON-NLS private static final String SIGNATURE_ELEMENT = "signature"; // NON-NLS private static final String OFFSET_ELEMENT = "offset"; + private static final String ENCODING = "UTF-8"; //NON-NLS // RJCTODO: Is this right? + + /** + * Reads the user-defined file type definitions from the user-defined file + * types file. + * + * @return A list of file type signature + */ + synchronized static List getUserDefinedFileTypeSignatures() { + Path filePath = Paths.get(PlatformUtil.getUserConfigDirectory(), UserDefinedFileTypes.USER_DEFINED_TYPE_DEFINITIONS_FILE); + String filePathString = filePath.toAbsolutePath().toString(); + File file = new File(filePathString); + if (file.exists() && file.canRead()) { + return UserDefinedFileTypes.Reader.readFileTypes(filePathString); + } + return Collections.emptyList(); + } /** * An association between a MIME type and a signature within a file. */ - static interface FileSignature { + static interface FileTypeSignature { /** * Gets the MIME type associated with this signature. @@ -59,6 +82,20 @@ public class UserDefinedFileTypes { */ String getMimeType(); + /** + * RJCTODO + * + * @return + */ + byte[] getSignatureBytes(); + + /** + * RJCTODO + * + * @return + */ + long getOffset(); + /** * Determines whether or not a file contains the signature. * @@ -73,7 +110,7 @@ public class UserDefinedFileTypes { * An association between a MIME type and a byte signature at a specified * offset within a file. */ - static class ByteSignature implements FileSignature { + static class ByteSignature implements FileTypeSignature { private final String mimeType; private final byte[] signatureBytes; @@ -103,6 +140,22 @@ public class UserDefinedFileTypes { return this.mimeType; } + /** + * @inheritDoc + */ + @Override + public byte[] getSignatureBytes() { + return this.signatureBytes; + } + + /** + * @inheritDoc + */ + @Override + public long getOffset() { + return this.offset; + } + /** * @inheritDoc */ @@ -117,7 +170,40 @@ public class UserDefinedFileTypes { } } - + + /** + * RJCTODO + */ + static class AsciiStringSignature implements FileTypeSignature { + + /** + * @inheritDoc + */ + @Override + public String getMimeType() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public byte[] getSignatureBytes() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public long getOffset() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + /** + * @inheritDoc + */ + @Override + public boolean containedIn(AbstractFile file) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + } + /** * Provides a mechanism for persisting user-defined file types. */ @@ -129,10 +215,39 @@ public class UserDefinedFileTypes { * @param signatures A collection of file signatures. * @param filePath The path to the file. */ - static void writeFileTypes(List signatures, String filePath) { + static void writeFileTypes(List signatures, String filePath) { + try { + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + Document doc = builder.newDocument(); + Element rootElem = doc.createElement(UserDefinedFileTypes.ROOT_FILE_TYPES_ELEMENT); + doc.appendChild(rootElem); + for (FileTypeSignature signature : signatures) { + UserDefinedFileTypes.Writer.writeFileType(signature, rootElem, doc); + } + if (!XMLUtil.saveDoc(HashDbManager.class, filePath, UserDefinedFileTypes.ENCODING, doc)) { + // RJCTODO + } + } catch (ParserConfigurationException ex) { + } } - + + static void writeFileType(FileTypeSignature signature, Element rootElem, Document doc) { + Element mimeTypeElem = doc.createElement(UserDefinedFileTypes.MIME_TYPE_ELEMENT); + mimeTypeElem.setTextContent(signature.getMimeType()); + Element sigElem = doc.createElement(UserDefinedFileTypes.SIGNATURE_ELEMENT); + sigElem.setTextContent(DatatypeConverter.printHexBinary(signature.getSignatureBytes())); + Element offsetElem = doc.createElement(UserDefinedFileTypes.OFFSET_ELEMENT); + offsetElem.setTextContent(DatatypeConverter.printLong(signature.getOffset())); + Element fileTypeElem = doc.createElement(UserDefinedFileTypes.FILE_TYPE_ELEMENT); + fileTypeElem.appendChild(mimeTypeElem); + fileTypeElem.appendChild(sigElem); + fileTypeElem.appendChild(offsetElem); + rootElem.appendChild(fileTypeElem); + // RJCTODO: Surely there are some exceptions that could be thrown here? + } + } /** @@ -146,28 +261,77 @@ public class UserDefinedFileTypes { * @param filePath The path to the file. * @return A collection of file signatures. */ - static List readFileTypes(String filePath) { - // RJCTODO: - try { - DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = builderFactory.newDocumentBuilder(); - Document doc = builder.parse(new FileInputStream(filePath)); - final Document doc = XMLUtil.loadDoc(ExternalResultsXMLParser.class, this.resultsFilePath, XSD_FILE); - if (doc != null) { - final Element rootElem = doc.getDocumentElement(); - if (rootElem != null && rootElem.getNodeName().equals(ExternalResultsXMLParser.TagNames.ROOT_ELEM.toString())) { - - } catch (ParserConfigurationException e) { - } catch (SAXException e) { - } catch (IOException e) { - } - - - - + static List readFileTypes(String filePath) { + try { + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + Document doc = builder.parse(new FileInputStream(filePath)); + if (doc != null) { + Element rootElem = doc.getDocumentElement(); + if (rootElem != null && rootElem.getNodeName().equals(UserDefinedFileTypes.ROOT_FILE_TYPES_ELEMENT)) { + return UserDefinedFileTypes.Reader.parseFileTypes(rootElem); + } + } + } catch (ParserConfigurationException | SAXException | IOException e) { + // RJCTODO: + } return Collections.emptyList(); } + /** + * RJCTODO + * + * @param rootElem + * @return + */ + private static List parseFileTypes(Element rootElem) { + List signatures = new ArrayList<>(); + NodeList fileTypeElems = rootElem.getElementsByTagName(UserDefinedFileTypes.FILE_TYPE_ELEMENT); + for (int i = 0; i < fileTypeElems.getLength(); ++i) { + Element fileTypeElem = (Element) fileTypeElems.item(i); + UserDefinedFileTypes.Reader.tryParseSignature(fileTypeElem, signatures); + } + return signatures; + } + + /** + * RJCTODO + * + * @param fileTypeElem + * @param signatures + */ + private static void tryParseSignature(Element fileTypeElem, List signatures) { + try { + String mimeType = ""; + byte[] signature = null; + long offset = -1; + NodeList childElems = fileTypeElem.getElementsByTagName(UserDefinedFileTypes.FILE_TYPE_ELEMENT); + for (int i = 0; i < childElems.getLength(); ++i) { + Element childElem = (Element) childElems.item(i); + switch (childElem.getTagName()) { + case MIME_TYPE_ELEMENT: + mimeType = childElem.getTextContent(); + break; + case SIGNATURE_ELEMENT: + signature = DatatypeConverter.parseHexBinary(childElem.getTextContent()); + break; + case OFFSET_ELEMENT: + offset = DatatypeConverter.parseLong(childElem.getTextContent()); + break; + default: + break; + } + } + if (!mimeType.isEmpty() && null != signature && signature.length > 0 && offset >= 0) { + signatures.add(new ByteSignature(mimeType, signature, offset)); + } + } catch (NumberFormatException ex) { + // RJCTODO: Log error + } catch (IllegalArgumentException ex) { + // RJCTODO: Log error + } + } + } } From 475430f9aa19f68e0634a3297287dc7f2e71c04e Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 28 Nov 2014 15:01:44 -0500 Subject: [PATCH 05/27] Updates before accidental deletion of work --- .../filetypeid/FileTypeIdSettingsPanel.form | 8 +- .../filetypeid/FileTypeIdSettingsPanel.java | 98 +++-- .../UserDefinedFileTypeIdentifier.java | 30 +- .../filetypeid/UserDefinedFileTypes.java | 335 +----------------- 4 files changed, 84 insertions(+), 387 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form index efb8311caf..d20e8f8683 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form @@ -29,7 +29,7 @@ - + @@ -104,7 +104,7 @@ - + @@ -154,14 +154,14 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java index c0ffdbfd3b..af160cd19b 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java @@ -18,21 +18,28 @@ */ package org.sleuthkit.autopsy.modules.filetypeid; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import javax.swing.DefaultListModel; +import javax.swing.ListModel; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; -import org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypes.FileTypeSignature; /** - * RJCTODO + * A panel to allow a user to make custom file type definitions. */ -class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { +final class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { + +// private final HashMap fileTypeDefs; +// private final ListModel fileTypesListModel; /** - * Creates... RJCTODO + * Creates a panel to allow a user to make custom file type definitions. */ FileTypeIdSettingsPanel() { + this.fileTypeDefs = new HashMap<>(); initComponents(); - } /** @@ -40,35 +47,48 @@ class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { */ @Override public void saveSettings() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + this.store(); } - - void load() { - List fileTypeSignatures; - - // RJCTODO read settings and initialize GUI - // Example: - // someCheckBox.setSelected(Preferences.userNodeForPackage(FileTypeIdPanel.class).getBoolean("someFlag", false)); - // or for org.openide.util with API spec. version >= 7.4: - // someCheckBox.setSelected(NbPreferences.forModule(FileTypeIdPanel.class).getBoolean("someFlag", false)); - // or: - // someTextField.setText(SomeSystemOption.getDefault().getSomeStringProperty()); - } - - void store() { - // RJCTODO store modified settings - // Example: - // Preferences.userNodeForPackage(FileTypeIdPanel.class).putBoolean("someFlag", someCheckBox.isSelected()); - // or for org.openide.util with API spec. version >= 7.4: - // NbPreferences.forModule(FileTypeIdPanel.class).putBoolean("someFlag", someCheckBox.isSelected()); - // or: - // SomeSystemOption.getDefault().setSomeStringProperty(someTextField.getText()); - } - - boolean valid() { - return true; - } + /** + * RJCTODO + */ + void load() { +// try { +// this.fileTypeDefs.clear(); +// DefaultListModel fileTypesListModel = new DefaultListModel<>(); +// for (FileTypeDefinition fileTypeDef : FileTypeDefinitionsManager.getFileTypeDefinitions()) { +// this.fileTypeDefs.put(fileTypeDef.getTypeName(), fileTypeDef); +// fileTypesListModel.addElement(fileTypeDef.getTypeName()); +// } +// this.typesList.setModel(fileTypesListModel); +// } catch (IOException ex) { +// // RJCTODO +// } + } + + /** + * RJCTODO + */ + void store() { +// try { +// ListModel fileTypesListModel = this.typesList.getModel(); +// List newFileTypeDefs = new ArrayList<>(); +// for (int i = 0; i < fileTypesListModel.getSize(); ++i) { +// String typeName = fileTypesListModel.getElementAt(i); +// newFileTypeDefs.add(this.fileTypeDefs.get(typeName)); +// } +// FileTypeDefinitionsManager.setFileTypeDefinitions(newFileTypeDefs); +// } catch (IOException ex) { +// // RJCTODO +// } + } + + boolean valid() { + // RJCTODO + return true; + } + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -79,8 +99,8 @@ class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { private void initComponents() { buttonGroup1 = new javax.swing.ButtonGroup(); - jScrollPane1 = new javax.swing.JScrollPane(); - jList1 = new javax.swing.JList(); + typesScrollPane = new javax.swing.JScrollPane(); + typesList = new javax.swing.JList(); jSeparator1 = new javax.swing.JSeparator(); mimeTypeLabel = new javax.swing.JLabel(); mimeTypeTextField = new javax.swing.JTextField(); @@ -98,7 +118,7 @@ class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { jTextArea1 = new javax.swing.JTextArea(); postHitCheckBox = new javax.swing.JCheckBox(); - jScrollPane1.setViewportView(jList1); + typesScrollPane.setViewportView(typesList); jSeparator1.setOrientation(javax.swing.SwingConstants.VERTICAL); @@ -149,7 +169,7 @@ class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { .addComponent(jButton1) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jButton2)) - .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)) + .addComponent(typesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(37, 37, 37) @@ -204,7 +224,7 @@ class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 219, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(typesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 219, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(18, 18, 18) @@ -247,8 +267,6 @@ class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { private javax.swing.JButton jButton1; private javax.swing.JButton jButton2; private javax.swing.JButton jButton3; - private javax.swing.JList jList1; - private javax.swing.JScrollPane jScrollPane1; private javax.swing.JScrollPane jScrollPane2; private javax.swing.JSeparator jSeparator1; private javax.swing.JTextArea jTextArea1; @@ -261,6 +279,8 @@ class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { private javax.swing.JLabel signatureLabel; private javax.swing.JComboBox signatureTypeComboBox; private javax.swing.JLabel signatureTypeLabel; + private javax.swing.JList typesList; + private javax.swing.JScrollPane typesScrollPane; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java index 860a6b65cf..5e9e7047c1 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java @@ -23,19 +23,17 @@ import java.util.List; import org.sleuthkit.datamodel.AbstractFile; /** - * Does file type identification with user-defined file type signatures. + * Does file type identification with user-defined file type fileTypeDefs. */ class UserDefinedFileTypeIdentifier { - private static final String USER_DEFINITIONS_FILE = "UserFileTypeDefinitions.xml"; - private static final String AUTOPSY_DEFINITIONS_FILE = "AutopsyFileTypeDefinitions.xml"; - private final List signatures; + private final List fileTypeDefs; /** * Creates an object that does file type identification with user-defined - * file type signatures. + file type fileTypeDefs. * - * @param sigFilePath A path to a signature definitions file. + * @param sigFilePath A path to a fileTypeDef definitions file. */ static UserDefinedFileTypeIdentifier createDetector(String sigFilePath) { UserDefinedFileTypeIdentifier detector = new UserDefinedFileTypeIdentifier(); @@ -45,33 +43,35 @@ class UserDefinedFileTypeIdentifier { /** * Create an object that does file type identification with user-defined - * file type signatures. + file type fileTypeDefs. */ private UserDefinedFileTypeIdentifier() { - this.signatures = new ArrayList<>(); + this.fileTypeDefs = new ArrayList<>(); } /** - * Loads a set of user-defined file type signatures from a file. + * Loads a set of user-defined file type fileTypeDefs from a file. * - * @param sigFilePath The path to the signature definitions file. + * @param sigFilePath The path to the fileTypeDef definitions file. */ private void loadSignatures(String sigFilePath) { - // RJCTODO: Load signature file, creating + // RJCTODO: Load fileTypeDef file, creating } /** * Attempts to identify a file using the set of user-defined file type - * signatures. + fileTypeDefs. * * @param file The file to type. * @return A MIME type string or the empty string if identification fails. */ String identify(AbstractFile file) { String type = ""; - for (UserDefinedFileTypes.FileTypeSignature signature : this.signatures) { - if (signature.containedIn(file)) { - type = signature.getMimeType(); + for (FileTypeDefinitionsManager.FileTypeDefinition fileTypeDef : this.fileTypeDefs) { + if (fileTypeDef.matches(file)) { + type = fileTypeDef.getTypeName(); + // RJCTODO: Add attribute to GEN IBNFO artifact? + // RJCTODO: Handle alert here? break; } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.java index 690433b416..4c2ca9044f 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.java @@ -1,337 +1,14 @@ /* - * Autopsy Forensic Browser - * - * Copyright 2014 Basis Technology Corp. - * Contact: carrier sleuthkit 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. + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. */ package org.sleuthkit.autopsy.modules.filetypeid; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.TskCoreException; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; -import javax.xml.bind.DatatypeConverter; -import org.sleuthkit.autopsy.coreutils.PlatformUtil; -import org.sleuthkit.autopsy.coreutils.XMLUtil; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; - /** - * RJCTODO + * + * @author rcordovano */ public class UserDefinedFileTypes { - - private static final String USER_DEFINED_TYPE_DEFINITIONS_FILE = "UserFileTypeDefinitions.xml"; // NON-NLS - private static final String ROOT_FILE_TYPES_ELEMENT = "fileTypes"; // NON-NLS - private static final String FILE_TYPE_ELEMENT = "fileType"; // NON-NLS - private static final String MIME_TYPE_ELEMENT = "mimeType"; // NON-NLS - private static final String SIGNATURE_ELEMENT = "signature"; // NON-NLS - private static final String OFFSET_ELEMENT = "offset"; - private static final String ENCODING = "UTF-8"; //NON-NLS // RJCTODO: Is this right? - - /** - * Reads the user-defined file type definitions from the user-defined file - * types file. - * - * @return A list of file type signature - */ - synchronized static List getUserDefinedFileTypeSignatures() { - Path filePath = Paths.get(PlatformUtil.getUserConfigDirectory(), UserDefinedFileTypes.USER_DEFINED_TYPE_DEFINITIONS_FILE); - String filePathString = filePath.toAbsolutePath().toString(); - File file = new File(filePathString); - if (file.exists() && file.canRead()) { - return UserDefinedFileTypes.Reader.readFileTypes(filePathString); - } - return Collections.emptyList(); - } - - /** - * An association between a MIME type and a signature within a file. - */ - static interface FileTypeSignature { - - /** - * Gets the MIME type associated with this signature. - * - * @return The MIME type string. - */ - String getMimeType(); - - /** - * RJCTODO - * - * @return - */ - byte[] getSignatureBytes(); - - /** - * RJCTODO - * - * @return - */ - long getOffset(); - - /** - * Determines whether or not a file contains the signature. - * - * @param file The file to test. - * @return True or false. - */ - boolean containedIn(AbstractFile file); - - } - - /** - * An association between a MIME type and a byte signature at a specified - * offset within a file. - */ - static class ByteSignature implements FileTypeSignature { - - private final String mimeType; - private final byte[] signatureBytes; - private final long offset; - private final byte[] buffer; - - /** - * Creates an association between a MIME type and a byte signature at a - * specified offset. - * - * @param mimeType The MIME type string. - * @param signatureBytes The bytes of the signature. - * @param offset The offset of the signature within a file. - */ - private ByteSignature(String mimeType, byte[] signatureBytes, long offset) { - this.mimeType = mimeType; - this.signatureBytes = signatureBytes; - this.offset = offset; - this.buffer = new byte[signatureBytes.length]; - } - - /** - * @inheritDoc - */ - @Override - public String getMimeType() { - return this.mimeType; - } - - /** - * @inheritDoc - */ - @Override - public byte[] getSignatureBytes() { - return this.signatureBytes; - } - - /** - * @inheritDoc - */ - @Override - public long getOffset() { - return this.offset; - } - - /** - * @inheritDoc - */ - @Override - public boolean containedIn(AbstractFile file) { - try { - int bytesRead = file.read(this.buffer, offset, buffer.length); - return bytesRead == buffer.length ? Arrays.equals(this.buffer, this.signatureBytes) : false; - } catch (TskCoreException ex) { - return false; - } - } - - } - - /** - * RJCTODO - */ - static class AsciiStringSignature implements FileTypeSignature { - - /** - * @inheritDoc - */ - @Override - public String getMimeType() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public byte[] getSignatureBytes() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public long getOffset() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - /** - * @inheritDoc - */ - @Override - public boolean containedIn(AbstractFile file) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - } - - /** - * Provides a mechanism for persisting user-defined file types. - */ - static class Writer { - - /** - * Reads user-defined file type definitions from a file. - * - * @param signatures A collection of file signatures. - * @param filePath The path to the file. - */ - static void writeFileTypes(List signatures, String filePath) { - try { - DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = builderFactory.newDocumentBuilder(); - Document doc = builder.newDocument(); - Element rootElem = doc.createElement(UserDefinedFileTypes.ROOT_FILE_TYPES_ELEMENT); - doc.appendChild(rootElem); - for (FileTypeSignature signature : signatures) { - UserDefinedFileTypes.Writer.writeFileType(signature, rootElem, doc); - } - if (!XMLUtil.saveDoc(HashDbManager.class, filePath, UserDefinedFileTypes.ENCODING, doc)) { - // RJCTODO - } - } catch (ParserConfigurationException ex) { - } - - } - - static void writeFileType(FileTypeSignature signature, Element rootElem, Document doc) { - Element mimeTypeElem = doc.createElement(UserDefinedFileTypes.MIME_TYPE_ELEMENT); - mimeTypeElem.setTextContent(signature.getMimeType()); - Element sigElem = doc.createElement(UserDefinedFileTypes.SIGNATURE_ELEMENT); - sigElem.setTextContent(DatatypeConverter.printHexBinary(signature.getSignatureBytes())); - Element offsetElem = doc.createElement(UserDefinedFileTypes.OFFSET_ELEMENT); - offsetElem.setTextContent(DatatypeConverter.printLong(signature.getOffset())); - Element fileTypeElem = doc.createElement(UserDefinedFileTypes.FILE_TYPE_ELEMENT); - fileTypeElem.appendChild(mimeTypeElem); - fileTypeElem.appendChild(sigElem); - fileTypeElem.appendChild(offsetElem); - rootElem.appendChild(fileTypeElem); - // RJCTODO: Surely there are some exceptions that could be thrown here? - } - - } - - /** - * Provides a method for reading persisted user-defined file types. - */ - static class Reader { - - /** - * Reads user-defined file type definitions from a file. - * - * @param filePath The path to the file. - * @return A collection of file signatures. - */ - static List readFileTypes(String filePath) { - try { - DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = builderFactory.newDocumentBuilder(); - Document doc = builder.parse(new FileInputStream(filePath)); - if (doc != null) { - Element rootElem = doc.getDocumentElement(); - if (rootElem != null && rootElem.getNodeName().equals(UserDefinedFileTypes.ROOT_FILE_TYPES_ELEMENT)) { - return UserDefinedFileTypes.Reader.parseFileTypes(rootElem); - } - } - } catch (ParserConfigurationException | SAXException | IOException e) { - // RJCTODO: - } - return Collections.emptyList(); - } - - /** - * RJCTODO - * - * @param rootElem - * @return - */ - private static List parseFileTypes(Element rootElem) { - List signatures = new ArrayList<>(); - NodeList fileTypeElems = rootElem.getElementsByTagName(UserDefinedFileTypes.FILE_TYPE_ELEMENT); - for (int i = 0; i < fileTypeElems.getLength(); ++i) { - Element fileTypeElem = (Element) fileTypeElems.item(i); - UserDefinedFileTypes.Reader.tryParseSignature(fileTypeElem, signatures); - } - return signatures; - } - - /** - * RJCTODO - * - * @param fileTypeElem - * @param signatures - */ - private static void tryParseSignature(Element fileTypeElem, List signatures) { - try { - String mimeType = ""; - byte[] signature = null; - long offset = -1; - NodeList childElems = fileTypeElem.getElementsByTagName(UserDefinedFileTypes.FILE_TYPE_ELEMENT); - for (int i = 0; i < childElems.getLength(); ++i) { - Element childElem = (Element) childElems.item(i); - switch (childElem.getTagName()) { - case MIME_TYPE_ELEMENT: - mimeType = childElem.getTextContent(); - break; - case SIGNATURE_ELEMENT: - signature = DatatypeConverter.parseHexBinary(childElem.getTextContent()); - break; - case OFFSET_ELEMENT: - offset = DatatypeConverter.parseLong(childElem.getTextContent()); - break; - default: - break; - } - } - if (!mimeType.isEmpty() && null != signature && signature.length > 0 && offset >= 0) { - signatures.add(new ByteSignature(mimeType, signature, offset)); - } - } catch (NumberFormatException ex) { - // RJCTODO: Log error - } catch (IllegalArgumentException ex) { - // RJCTODO: Log error - } - } - - } - + } From a333d97c05e1cfa815b8530cae945f49692872c5 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Sat, 29 Nov 2014 14:09:28 -0500 Subject: [PATCH 06/27] Continue work on user defined file types feature --- .../sleuthkit/autopsy/coreutils/XMLUtil.java | 12 + .../autopsy/modules/filetypeid/FileType.java | 152 ++++++++ .../filetypeid/FileTypeIdSettingsPanel.java | 60 ++-- .../UserDefinedFileTypeIdentifier.java | 49 +-- .../filetypeid/UserDefinedFileTypes.java | 338 +++++++++++++++++- .../filetypeid/UserDefinedFileTypes.xsd | 50 +++ 6 files changed, 594 insertions(+), 67 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java create mode 100644 Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.xsd diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/XMLUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/XMLUtil.java index a997f01dd5..dc12e3bd2c 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/XMLUtil.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/XMLUtil.java @@ -54,6 +54,18 @@ import org.xml.sax.SAXException; */ public class XMLUtil { + /** + * Creates a W3C DOM document. + * + * @return The document object. + * @throws ParserConfigurationException + */ + public static Document createDoc() throws ParserConfigurationException { + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + return builder.newDocument(); + } + /** * Utility to validate XML files against pre-defined schema files. * diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java new file mode 100644 index 0000000000..d4fc484673 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java @@ -0,0 +1,152 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.modules.filetypeid; + +import java.util.Arrays; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Represents a named file type characterized by a file signature. + */ +class FileType { + + private final String typeName; + private final Signature signature; + private final boolean alert; + + /** + * Creates a representation of a named file type characterized by a file + * signature. + * + * @param typeName The name of the file type. + * @param signature The signature that characterizes the file type. + * @param alert A flag indicating whether the user wishes to be alerted when + * a file matching this type is encountered. + */ + FileType(String typeName, Signature signature, boolean alert) { + this.typeName = typeName; + this.signature = signature; + this.alert = alert; + } + + /** + * Gets the name associated with this file type. + * + * @return The type name. + */ + String getTypeName() { + return this.typeName; + } + + /** + * Gets the signature associated with this file type. + * + * @return The file signature. + */ + Signature getSignature() { + return this.signature; + } + + /** + * Determines whether or not a given file is an instance of this file type. + * + * @param file The file to test + * @return True or false. + */ + boolean matches(AbstractFile file) { + return this.signature.containedIn(file); + } + + /** + * Indicates whether or not an alert is desired if a file of this type is + * encountered. + * + * @return True or false. + */ + boolean alertOnMatch() { + return this.alert; + } + + /** + * Represents a file signature consisting of a sequence of bytes at a + * specific offset within a file. + */ + static class Signature { + + /** + * The way the signature byte sequence should be interpreted. + */ + enum Type { + + RAW, ASCII + }; + + private final byte[] signatureBytes; + private final long offset; + private final Type type; + + /** + * Creates a representation of a file signature consisting of a sequence + * of bytes at a specific offset within a file. + * + * @param signatureBytes The signature bytes + * @param offset The offset of the signature bytes. + * @param type The interpretation of the signature bytes (e.g., raw + * bytes, an ASCII string). + */ + Signature(byte[] signatureBytes, long offset, Type type) { + this.signatureBytes = signatureBytes; + this.offset = offset; + this.type = type; + } + + /** + * Gets the byte sequence of the signature. + * + * @return The byte sequence as an array of bytes. + */ + byte[] getSignatureBytes() { + return Arrays.copyOf(this.signatureBytes, this.signatureBytes.length); + } + + /** + * Gets the offset of the signature. + * + * @return The offset. + */ + long getOffset() { + return this.offset; + } + + /** + * Gets the interpretation of the byte sequence for the signature. + * + * @return The signature type. + */ + Type getType() { + return this.type; + } + + /** + * Determines whether or not the signature is contained within a given + * file. + * + * @param file The file to test + * @return True or false. + */ + boolean containedIn(AbstractFile file) { + try { + byte[] buffer = new byte[this.signatureBytes.length]; + int bytesRead = file.read(buffer, offset, this.signatureBytes.length); + return ((bytesRead == this.signatureBytes.length) && (Arrays.equals(buffer, this.signatureBytes))); + } catch (TskCoreException ex) { + return false; + } + } + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java index af160cd19b..ec6598b838 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java @@ -18,27 +18,28 @@ */ package org.sleuthkit.autopsy.modules.filetypeid; -import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import javax.swing.DefaultListModel; import javax.swing.ListModel; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; +//import org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypes.FileType; +import org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypes.UserDefinedFileTypesException; /** * A panel to allow a user to make custom file type definitions. */ final class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { - -// private final HashMap fileTypeDefs; + + private final HashMap fileTypes; // private final ListModel fileTypesListModel; /** * Creates a panel to allow a user to make custom file type definitions. */ FileTypeIdSettingsPanel() { - this.fileTypeDefs = new HashMap<>(); + this.fileTypes = new HashMap<>(); initComponents(); } @@ -49,41 +50,44 @@ final class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { public void saveSettings() { this.store(); } - + /** * RJCTODO */ void load() { -// try { -// this.fileTypeDefs.clear(); -// DefaultListModel fileTypesListModel = new DefaultListModel<>(); -// for (FileTypeDefinition fileTypeDef : FileTypeDefinitionsManager.getFileTypeDefinitions()) { -// this.fileTypeDefs.put(fileTypeDef.getTypeName(), fileTypeDef); -// fileTypesListModel.addElement(fileTypeDef.getTypeName()); -// } -// this.typesList.setModel(fileTypesListModel); -// } catch (IOException ex) { -// // RJCTODO -// } + try { + this.fileTypes.clear(); + DefaultListModel fileTypesListModel = new DefaultListModel<>(); + for (FileType fileType : UserDefinedFileTypes.getFileTypes()) { + this.fileTypes.put(fileType.getTypeName(), fileType); + fileTypesListModel.addElement(fileType.getTypeName()); + } + this.typesList.setModel(fileTypesListModel); + } catch (UserDefinedFileTypesException ex) { + // RJCTODO + } } /** * RJCTODO */ void store() { -// try { -// ListModel fileTypesListModel = this.typesList.getModel(); -// List newFileTypeDefs = new ArrayList<>(); -// for (int i = 0; i < fileTypesListModel.getSize(); ++i) { -// String typeName = fileTypesListModel.getElementAt(i); -// newFileTypeDefs.add(this.fileTypeDefs.get(typeName)); -// } -// FileTypeDefinitionsManager.setFileTypeDefinitions(newFileTypeDefs); -// } catch (IOException ex) { -// // RJCTODO -// } + try { + ListModel fileTypesListModel = this.typesList.getModel(); + List newFileTypes = new ArrayList<>(); + for (int i = 0; i < fileTypesListModel.getSize(); ++i) { + String typeName = fileTypesListModel.getElementAt(i); + newFileTypes.add(this.fileTypes.get(typeName)); + } + UserDefinedFileTypes.setFileTypes(newFileTypes); + } catch (UserDefinedFileTypesException ex) { + // RJCTODO + } } - + + /** + * RJCTODO + */ boolean valid() { // RJCTODO return true; diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java index 5e9e7047c1..5a5ad78f31 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java @@ -23,55 +23,40 @@ import java.util.List; import org.sleuthkit.datamodel.AbstractFile; /** - * Does file type identification with user-defined file type fileTypeDefs. + * Does file type identification with user-defined file types. */ -class UserDefinedFileTypeIdentifier { +final class UserDefinedFileTypeIdentifier { - private final List fileTypeDefs; + private final List fileTypes; /** * Creates an object that does file type identification with user-defined - file type fileTypeDefs. - * - * @param sigFilePath A path to a fileTypeDef definitions file. + * file types. Does not load the file type definitions. */ - static UserDefinedFileTypeIdentifier createDetector(String sigFilePath) { - UserDefinedFileTypeIdentifier detector = new UserDefinedFileTypeIdentifier(); - detector.loadSignatures(sigFilePath); - return detector; + UserDefinedFileTypeIdentifier() { + this.fileTypes = new ArrayList<>(); } /** - * Create an object that does file type identification with user-defined - file type fileTypeDefs. + * Loads the set of user-defined file types. */ - private UserDefinedFileTypeIdentifier() { - this.fileTypeDefs = new ArrayList<>(); - } - - /** - * Loads a set of user-defined file type fileTypeDefs from a file. - * - * @param sigFilePath The path to the fileTypeDef definitions file. - */ - private void loadSignatures(String sigFilePath) { - // RJCTODO: Load fileTypeDef file, creating + void loadFileTypes() throws UserDefinedFileTypes.UserDefinedFileTypesException { + this.fileTypes.clear(); + this.fileTypes.addAll(UserDefinedFileTypes.getFileTypes()); } /** * Attempts to identify a file using the set of user-defined file type - fileTypeDefs. + * file types. * * @param file The file to type. - * @return A MIME type string or the empty string if identification fails. + * @return A FileType object or null if identification fails. */ - String identify(AbstractFile file) { - String type = ""; - for (FileTypeDefinitionsManager.FileTypeDefinition fileTypeDef : this.fileTypeDefs) { - if (fileTypeDef.matches(file)) { - type = fileTypeDef.getTypeName(); - // RJCTODO: Add attribute to GEN IBNFO artifact? - // RJCTODO: Handle alert here? + FileType identify(AbstractFile file) { + FileType type = null; + for (FileType fileType : this.fileTypes) { + if (fileType.matches(file)) { + type = fileType; break; } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.java index 4c2ca9044f..84bc4f8778 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.java @@ -1,14 +1,338 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2014 Basis Technology Corp. + * Contact: carrier sleuthkit 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.modules.filetypeid; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import javax.xml.parsers.ParserConfigurationException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import javax.xml.bind.DatatypeConverter; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.sleuthkit.autopsy.coreutils.XMLUtil; +import org.sleuthkit.autopsy.modules.filetypeid.FileType.Signature; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; + /** - * - * @author rcordovano + * Allows a user to define named file types characterized by file signatures. */ -public class UserDefinedFileTypes { - +final class UserDefinedFileTypes { + + private static final Logger logger = Logger.getLogger(UserDefinedFileTypes.class.getName()); + private static final String FILE_TYPE_DEFINITIONS_SCHEMA_FILE = "FileTypeDefinitions.xsd"; // NON-NLS + private static final String USER_DEFINED_TYPE_DEFINITIONS_FILE = "UserFileTypeDefinitions.xml"; // NON-NLS + private static final String AUTOPSY_TYPE_DEFINITIONS_FILE = "AutopsyFileTypeDefinitions.xml"; // NON-NLS + private static final String FILE_TYPES_TAG_NAME = "filetypes"; // NON-NLS + private static final String FILE_TYPE_TAG_NAME = "filetype"; // NON-NLS + private static final String ALERT_ATTRIBUTE = "alert"; // NON-NLS + private static final String TYPE_NAME_TAG_NAME = "typename"; // NON-NLS + private static final String SIGNATURE_TAG_NAME = "signature"; // NON-NLS + private static final String SIGNATURE_TYPE_ATTRIBUTE = "type"; // NON-NLS + private static final String BYTES_TAG_NAME = "bytes"; // NON-NLS + private static final String OFFSET_TAG_NAME = "offset"; // NON-NLS + private static final String ENCODING = "UTF-8"; //NON-NLS // RJCTODO: Is this right? + + static { + UserDefinedFileTypes.writePredefinedTypes(); + } + + /** + * Writes the predefined file types definition file. + */ + private static void writePredefinedTypes() { + try { + Path filePath = Paths.get(PlatformUtil.getUserConfigDirectory(), UserDefinedFileTypes.USER_DEFINED_TYPE_DEFINITIONS_FILE); + String filePathString = filePath.toAbsolutePath().toString(); + List fileTypes = new ArrayList<>(); // RJCTODO + UserDefinedFileTypes.writeFileTypes(fileTypes, filePathString); + } catch (UserDefinedFileTypesException ex) { + // RJCTODO + } + } + + /** + * Gets the user-defined file types. + * + * @return A list of file types, possibly empty + */ + synchronized static List getFileTypes() throws UserDefinedFileTypesException { + Map fileTypes = new HashMap<>(); + UserDefinedFileTypes.readFileTypes(fileTypes, UserDefinedFileTypes.AUTOPSY_TYPE_DEFINITIONS_FILE); + UserDefinedFileTypes.readFileTypes(fileTypes, UserDefinedFileTypes.USER_DEFINED_TYPE_DEFINITIONS_FILE); + return new ArrayList(fileTypes.values()); + } + + /** + * Reads file type definitions from a file into a map of type names to file + * types. File types already loaded into the map will be overwritten by file + * types from the file if the type name is the same. + * + * @param fileTypes The map of type names to file type objects. + * @param fileName The file from which to read the file type definitions. + */ + private static void readFileTypes(Map fileTypes, String fileName) throws UserDefinedFileTypesException { + Path filePath = Paths.get(PlatformUtil.getUserConfigDirectory(), fileName); + String filePathString = filePath.toAbsolutePath().toString(); + File file = new File(filePathString); + if (file.exists() && file.canRead()) { + for (FileType fileType : UserDefinedFileTypes.XMLReader.readFileTypes(filePathString)) { + fileTypes.put(fileType.getTypeName(), fileType); + } + } + } + + /** + * Sets the user-defined file types. + * + * @param fileTypes The file type definitions. + * @throws UserDefinedFileTypesException + */ + synchronized static void setFileTypes(List fileTypes) throws UserDefinedFileTypesException { + Path filePath = Paths.get(PlatformUtil.getUserConfigDirectory(), UserDefinedFileTypes.USER_DEFINED_TYPE_DEFINITIONS_FILE); + String filePathString = filePath.toAbsolutePath().toString(); + UserDefinedFileTypes.writeFileTypes(fileTypes, filePathString); + } + + /** + * Writes a set of file type definitions to a given file. + * + * @param fileTypes The file types. + * @param filePaht The destination file. + * @throws UserDefinedFileTypesException + */ + private static void writeFileTypes(List fileTypes, String filePath) throws UserDefinedFileTypesException { + try { + UserDefinedFileTypes.XMLWriter.writeFileTypes(fileTypes, filePath); + } catch (ParserConfigurationException | IOException ex) { + UserDefinedFileTypes.logger.log(Level.SEVERE, "Failed to write file types file", ex); + throw new UserDefinedFileTypesException(ex.getLocalizedMessage()); // RJCTODO: Create a bundled message + } + } + + /** + * Provides a mechanism for writing a set of file type definitions to an XML + * file. + */ + private static class XMLWriter { + + /** + * Writes a set of file type definitions to an XML file. + * + * @param signatures A collection of file types. + * @param filePath The path to the destination file. + */ + private static void writeFileTypes(List fileTypes, String filePath) throws ParserConfigurationException, IOException { + Document doc = XMLUtil.createDoc(); + Element fileTypesElem = doc.createElement(UserDefinedFileTypes.FILE_TYPES_TAG_NAME); + doc.appendChild(fileTypesElem); + for (FileType fileType : fileTypes) { + Element fileTypeElem = UserDefinedFileTypes.XMLWriter.createFileTypeElement(fileType, doc); + fileTypesElem.appendChild(fileTypeElem); + } + if (!XMLUtil.saveDoc(HashDbManager.class, filePath, UserDefinedFileTypes.ENCODING, doc)) { + throw new IOException("Could not save user defined file types"); + } + } + + /** + * Creates an XML representation of a file type. + * + * @param fileType The file type object. + * @param doc The DOM document to use to create the XML. + * @return An XML element. + */ + private static Element createFileTypeElement(FileType fileType, Document doc) { + /** + * Create a file type element with an alert attribute. + */ + Element fileTypeElem = doc.createElement(UserDefinedFileTypes.FILE_TYPE_TAG_NAME); + fileTypeElem.setAttribute(UserDefinedFileTypes.ALERT_ATTRIBUTE, Boolean.toString(fileType.alertOnMatch())); + + /** + * Add a type name child element. + */ + Element typeNameElem = doc.createElement(UserDefinedFileTypes.TYPE_NAME_TAG_NAME); + typeNameElem.setTextContent(fileType.getTypeName()); + fileTypeElem.appendChild(typeNameElem); + + /** + * Add a signature child element with a type attribute. + */ + Signature signature = fileType.getSignature(); + Element signatureElem = doc.createElement(UserDefinedFileTypes.SIGNATURE_TAG_NAME); + signatureElem.setAttribute(UserDefinedFileTypes.SIGNATURE_TYPE_ATTRIBUTE, signature.getType().toString()); + fileTypeElem.appendChild(signatureElem); + + /** + * Add a bytes child element to the signature element. + */ + Element bytesElem = doc.createElement(UserDefinedFileTypes.BYTES_TAG_NAME); + bytesElem.setTextContent(DatatypeConverter.printHexBinary(signature.getSignatureBytes())); + signatureElem.appendChild(bytesElem); + + /** + * Add an offset child element to the signature element. + */ + Element offsetElem = doc.createElement(UserDefinedFileTypes.OFFSET_TAG_NAME); + offsetElem.setTextContent(DatatypeConverter.printLong(signature.getOffset())); + signatureElem.appendChild(offsetElem); + + return fileTypeElem; + } + } + + /** + * Provides a mechanism for reading a set of file type definitions from an + * XML file. + */ + private static class XMLReader { + + /** + * Reads a set of file type definitions from an XML file. + * + * @param filePath The path to the file. + * @return A collection of file types. + */ + private static List readFileTypes(String filePath) throws UserDefinedFileTypesException { + List fileTypes = new ArrayList<>(); + Path xsdPath = Paths.get(PlatformUtil.getUserConfigDirectory(), UserDefinedFileTypes.FILE_TYPE_DEFINITIONS_SCHEMA_FILE); + String xsdPathString = xsdPath.toAbsolutePath().toString(); + File file = new File(xsdPathString); + if (file.exists() && file.canRead()) { + Document doc = XMLUtil.loadDoc(UserDefinedFileTypes.XMLReader.class, filePath, xsdPathString); + if (doc != null) { + Element fileTypesElem = doc.getDocumentElement(); + if (fileTypesElem != null && fileTypesElem.getNodeName().equals(UserDefinedFileTypes.FILE_TYPES_TAG_NAME)) { + NodeList fileTypeElems = fileTypesElem.getElementsByTagName(UserDefinedFileTypes.FILE_TYPE_TAG_NAME); + for (int i = 0; i < fileTypeElems.getLength(); ++i) { + Element fileTypeElem = (Element) fileTypeElems.item(i); + FileType fileType = UserDefinedFileTypes.XMLReader.parseFileType(fileTypeElem); + fileTypes.add(fileType); + } + } + } + } + return fileTypes; + } + + /** + * Parse a file type definition from a file type XML element. + * + * @param fileTypeElem The XML element. + * @return A file type object. + * @throws UserDefinedFileTypesException + */ + private static FileType parseFileType(Element fileTypeElem) throws UserDefinedFileTypesException { + /** + * Get the alert attribute. + */ + String alertAttribute = fileTypeElem.getAttribute(UserDefinedFileTypes.ALERT_ATTRIBUTE); + boolean alert = Boolean.parseBoolean(alertAttribute); + + /** + * Get the type name child element. + */ + String typeName = UserDefinedFileTypes.getChildElementTextContent(fileTypeElem, UserDefinedFileTypes.TYPE_NAME_TAG_NAME); + + /** + * Get the signature child element. + */ + Element signatureElem; + NodeList signatureElems = fileTypeElem.getElementsByTagName(UserDefinedFileTypes.SIGNATURE_TAG_NAME); + signatureElem = (Element) signatureElems.item(0); + + /** + * Get the signature type attribute from the signature child + * element. + */ + String sigTypeAttribute = signatureElem.getAttribute(typeName); + Signature.Type signatureType = Signature.Type.valueOf(sigTypeAttribute); + + /** + * Get the signature bytes. + */ + String sigBytesString = UserDefinedFileTypes.getChildElementTextContent(signatureElem, UserDefinedFileTypes.TYPE_NAME_TAG_NAME); + byte[] signatureBytes = DatatypeConverter.parseHexBinary(sigBytesString); + + /** + * Get the offset. + */ + String offsetString = UserDefinedFileTypes.getChildElementTextContent(signatureElem, UserDefinedFileTypes.OFFSET_TAG_NAME); + long offset = DatatypeConverter.parseLong(offsetString); + + /** + * Put it all together. + */ + Signature signature = new Signature(signatureBytes, offset, signatureType); + return new FileType(typeName, signature, alert); + } + } + + /** + * Gets the text content of a single child element. + * + * @param elem The parent element. + * @param tagName The tag name of the child element. + * @return The text content. + * @throws UserDefinedFileTypesException + */ + private static String getChildElementTextContent(Element elem, String tagName) throws UserDefinedFileTypesException { + /** + * The checks here are essentially "sanity checks" since the XML was + * already validated using the XSD file. + */ + String textContent = ""; + NodeList childElems = elem.getElementsByTagName(tagName); + if (childElems.getLength() > 0) { + Element childElem = (Element) childElems.item(0); + textContent = childElem.getTextContent(); + if (textContent.isEmpty()) { + UserDefinedFileTypes.logger.log(Level.SEVERE, "File type {0} child element missing text content", tagName); // NON-NLS + } + } else { + UserDefinedFileTypes.logger.log(Level.SEVERE, "File type element missing {0} child element", tagName); // NON-NLS + } + if (textContent.isEmpty()) { + throw new UserDefinedFileTypes.UserDefinedFileTypesException("Error reading file type definitions file, see log for details"); // RJCTODO: Bundle + } + return textContent; + } + + /** + * An exception type to conflate more implementation-details-specific + * exception types (which are logged by this class) into a single generic + * type. + */ + static class UserDefinedFileTypesException extends Exception { + + UserDefinedFileTypesException(String message) { + super(message); + } + } + } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.xsd b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.xsd new file mode 100644 index 0000000000..2512542294 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.xsd @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From f94ec08dc9a4611997c0d1a7834c3c5a78043c4e Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Sun, 30 Nov 2014 12:27:29 -0500 Subject: [PATCH 07/27] Changing file types management code from static to singleton --- .../modules/filetypeid/Bundle.properties | 8 +- .../autopsy/modules/filetypeid/FileType.java | 52 +- .../FileTypeIdOptionsPanelController.java | 5 +- .../filetypeid/FileTypeIdSettingsPanel.form | 32 +- .../filetypeid/FileTypeIdSettingsPanel.java | 125 +++-- .../UserDefinedFileTypeIdentifier.java | 23 +- .../filetypeid/UserDefinedFileTypes.java | 338 ------------ .../filetypeid/UserDefinedFileTypes.xsd | 51 +- .../UserDefinedFileTypesManager.java | 511 ++++++++++++++++++ 9 files changed, 671 insertions(+), 474 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.java create mode 100644 Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties index 58978a9b5d..8df981383f 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties @@ -8,10 +8,6 @@ FileTypeIdIngestModule.complete.srvMsg.text=File Type Id Results FileTypeIdModuleFactory.getIngestJobSettingsPanel.exception.msg=Expected settings argument to be instanceof FileTypeIdModuleSettings FileTypeIdModuleFactory.createFileIngestModule.exception.msg=Expected settings argument to be instanceof FileTypeIdModuleSettings FileTypeIdModuleSettingsPanel.skipKnownCheckBox.text=Skip known files (NSRL) -FileTypeIdSettingsPanel.jTextField2.text= -FileTypeIdSettingsPanel.jButton1.text=New Type -FileTypeIdSettingsPanel.jButton2.text=DeleteType -FileTypeIdSettingsPanel.jButton3.text=Save Type FileTypeIdSettingsPanel.mimeTypeTextField.text= FileTypeIdSettingsPanel.mimeTypeLabel.text=Mime Type FileTypeIdSettingsPanel.signatureTypeLabel.text=Signature Type @@ -21,3 +17,7 @@ FileTypeIdSettingsPanel.offsetTextField.text= FileTypeIdSettingsPanel.hexPrefixLabel.text=0x FileTypeIdSettingsPanel.jTextArea1.text=Enter a MIME type and signature to be used to identify files of that type. If the signature is a byte sequence, enter the sequence using two hex values for each byte, e.g., EEF0 is a two byte signature. FileTypeIdSettingsPanel.postHitCheckBox.text=Post interesting file hit when found +FileTypeIdSettingsPanel.newTypeButton.text=New Type +FileTypeIdSettingsPanel.deleteTypeButton.text=DeleteType +FileTypeIdSettingsPanel.saveTypeButton.text=Save Type +FileTypeIdSettingsPanel.signatureTextField.text= diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java index d4fc484673..98b174b46f 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java @@ -1,18 +1,33 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2014 Basis Technology Corp. + * Contact: carrier sleuthkit 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.modules.filetypeid; import java.util.Arrays; +import java.util.logging.Level; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; /** * Represents a named file type characterized by a file signature. */ -class FileType { +final class FileType { private final String typeName; private final Signature signature; @@ -27,9 +42,9 @@ class FileType { * @param alert A flag indicating whether the user wishes to be alerted when * a file matching this type is encountered. */ - FileType(String typeName, Signature signature, boolean alert) { + FileType(String typeName, final Signature signature, boolean alert) { this.typeName = typeName; - this.signature = signature; + this.signature = new Signature(signature.getSignatureBytes(), signature.getOffset(), signature.getType()); this.alert = alert; } @@ -48,16 +63,16 @@ class FileType { * @return The file signature. */ Signature getSignature() { - return this.signature; + return new Signature(this.signature.getSignatureBytes(), this.signature.getOffset(), this.signature.getType()); } /** * Determines whether or not a given file is an instance of this file type. * - * @param file The file to test + * @param file The file to test. * @return True or false. */ - boolean matches(AbstractFile file) { + boolean matches(final AbstractFile file) { return this.signature.containedIn(file); } @@ -72,10 +87,12 @@ class FileType { } /** - * Represents a file signature consisting of a sequence of bytes at a - * specific offset within a file. + * A file signature consisting of a sequence of bytes at a specific offset + * within a file. */ - static class Signature { + static final class Signature { + + private static final Logger logger = Logger.getLogger(Signature.class.getName()); /** * The way the signature byte sequence should be interpreted. @@ -90,16 +107,16 @@ class FileType { private final Type type; /** - * Creates a representation of a file signature consisting of a sequence - * of bytes at a specific offset within a file. + * Creates a file signature consisting of a sequence of bytes at a + * specific offset within a file. * * @param signatureBytes The signature bytes * @param offset The offset of the signature bytes. * @param type The interpretation of the signature bytes (e.g., raw * bytes, an ASCII string). */ - Signature(byte[] signatureBytes, long offset, Type type) { - this.signatureBytes = signatureBytes; + Signature(final byte[] signatureBytes, long offset, Type type) { + this.signatureBytes = Arrays.copyOf(signatureBytes, signatureBytes.length); this.offset = offset; this.type = type; } @@ -138,12 +155,13 @@ class FileType { * @param file The file to test * @return True or false. */ - boolean containedIn(AbstractFile file) { + boolean containedIn(final AbstractFile file) { try { byte[] buffer = new byte[this.signatureBytes.length]; int bytesRead = file.read(buffer, offset, this.signatureBytes.length); return ((bytesRead == this.signatureBytes.length) && (Arrays.equals(buffer, this.signatureBytes))); } catch (TskCoreException ex) { + Signature.logger.log(Level.WARNING, "Error reading from file with objId = " + file.getId(), ex); return false; } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java index 4209dd9dc5..44c7730c1a 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java @@ -45,12 +45,11 @@ public final class FileTypeIdOptionsPanelController extends OptionsPanelControll @Override public void cancel() { - // need not do anything special, if no changes have been persisted yet } @Override public boolean isValid() { - return getPanel().valid(); + return true; } @Override @@ -60,7 +59,7 @@ public final class FileTypeIdOptionsPanelController extends OptionsPanelControll @Override public HelpCtx getHelpCtx() { - return null; // new HelpCtx("...ID") if you have a help set + return null; } @Override diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form index d20e8f8683..d8ad98b738 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form @@ -25,16 +25,16 @@ - + - + - + @@ -66,7 +66,7 @@ - + @@ -119,7 +119,7 @@ - + @@ -136,13 +136,13 @@ - - + + - + @@ -196,10 +196,10 @@ - + - + @@ -217,24 +217,24 @@ - + - + - + - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java index ec6598b838..595a32397e 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java @@ -18,28 +18,28 @@ */ package org.sleuthkit.autopsy.modules.filetypeid; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import javax.swing.DefaultListModel; -import javax.swing.ListModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; -//import org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypes.FileType; -import org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypes.UserDefinedFileTypesException; +import org.sleuthkit.autopsy.modules.filetypeid.FileType.Signature; +import org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException; /** * A panel to allow a user to make custom file type definitions. */ -final class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { +final class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { - private final HashMap fileTypes; -// private final ListModel fileTypesListModel; + private final HashMap fileTypes = new HashMap<>(); + private final HashMap changedFileTypes = new HashMap<>(); + private final HashMap deletedFileTypes = new HashMap<>(); /** * Creates a panel to allow a user to make custom file type definitions. */ FileTypeIdSettingsPanel() { - this.fileTypes = new HashMap<>(); initComponents(); } @@ -52,47 +52,60 @@ final class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { } /** - * RJCTODO + * Populates the child components. */ - void load() { - try { - this.fileTypes.clear(); - DefaultListModel fileTypesListModel = new DefaultListModel<>(); - for (FileType fileType : UserDefinedFileTypes.getFileTypes()) { - this.fileTypes.put(fileType.getTypeName(), fileType); - fileTypesListModel.addElement(fileType.getTypeName()); - } - this.typesList.setModel(fileTypesListModel); - } catch (UserDefinedFileTypesException ex) { - // RJCTODO + @Override + public void load() { + fileTypes.clear(); + DefaultListModel fileTypesListModel = new DefaultListModel<>(); + for (FileType fileType : UserDefinedFileTypesManager.getInstance().getFileTypes()) { + fileTypes.put(fileType.getTypeName(), fileType); + fileTypesListModel.addElement(fileType.getTypeName()); + } + typesList.setModel(fileTypesListModel); + + typesList.addListSelectionListener(new TypesListSelectionListener()); + + if (!fileTypesListModel.isEmpty()) { + typesList.setSelectedIndex(0); } } /** - * RJCTODO + * Stores any changes to the user-defined types. */ - void store() { + @Override + public void store() { try { - ListModel fileTypesListModel = this.typesList.getModel(); - List newFileTypes = new ArrayList<>(); - for (int i = 0; i < fileTypesListModel.getSize(); ++i) { - String typeName = fileTypesListModel.getElementAt(i); - newFileTypes.add(this.fileTypes.get(typeName)); - } - UserDefinedFileTypes.setFileTypes(newFileTypes); + UserDefinedFileTypesManager fileTypesManager = UserDefinedFileTypesManager.getInstance(); + fileTypesManager.addFileTypes(changedFileTypes.values()); + fileTypesManager.deleteFileTypes(deletedFileTypes.values()); } catch (UserDefinedFileTypesException ex) { // RJCTODO } } - /** - * RJCTODO - */ - boolean valid() { - // RJCTODO - return true; + private class TypesListSelectionListener implements ListSelectionListener { + + @Override + public void valueChanged(ListSelectionEvent e) { + if (e.getValueIsAdjusting() == false) { + if (typesList.getSelectedIndex() == -1) { + deleteTypeButton.setEnabled(false); + + } else { + String typeName = (String) typesList.getSelectedValue(); + FileType fileType = fileTypes.get(typeName); + Signature signature = fileType.getSignature(); + mimeTypeTextField.setText(typeName); + offsetTextField.setText(Long.toString(signature.getOffset())); + deleteTypeButton.setEnabled(true); + } + } + } } + // RJCTODO: Consider fixing OptinsPanel interface or writing story /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -109,12 +122,12 @@ final class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { mimeTypeLabel = new javax.swing.JLabel(); mimeTypeTextField = new javax.swing.JTextField(); signatureTypeLabel = new javax.swing.JLabel(); - jTextField2 = new javax.swing.JTextField(); + signatureTextField = new javax.swing.JTextField(); offsetLabel = new javax.swing.JLabel(); offsetTextField = new javax.swing.JTextField(); - jButton1 = new javax.swing.JButton(); - jButton2 = new javax.swing.JButton(); - jButton3 = new javax.swing.JButton(); + newTypeButton = new javax.swing.JButton(); + deleteTypeButton = new javax.swing.JButton(); + saveTypeButton = new javax.swing.JButton(); hexPrefixLabel = new javax.swing.JLabel(); signatureTypeComboBox = new javax.swing.JComboBox(); signatureLabel = new javax.swing.JLabel(); @@ -132,17 +145,17 @@ final class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { org.openide.awt.Mnemonics.setLocalizedText(signatureTypeLabel, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.signatureTypeLabel.text")); // NOI18N - jTextField2.setText(org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.jTextField2.text")); // NOI18N + signatureTextField.setText(org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.signatureTextField.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(offsetLabel, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.offsetLabel.text")); // NOI18N offsetTextField.setText(org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.offsetTextField.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.jButton1.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(newTypeButton, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.newTypeButton.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jButton2, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.jButton2.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(deleteTypeButton, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.deleteTypeButton.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jButton3, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.jButton3.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(saveTypeButton, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.saveTypeButton.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(hexPrefixLabel, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.hexPrefixLabel.text")); // NOI18N @@ -170,14 +183,14 @@ final class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(10, 10, 10) - .addComponent(jButton1) + .addComponent(newTypeButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jButton2)) + .addComponent(deleteTypeButton)) .addComponent(typesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(37, 37, 37) - .addComponent(jButton3) + .addComponent(saveTypeButton) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() .addGap(18, 18, 18) @@ -204,7 +217,7 @@ final class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { .addGap(5, 5, 5) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(offsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 84, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jTextField2, javax.swing.GroupLayout.PREFERRED_SIZE, 178, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(signatureTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 178, javax.swing.GroupLayout.PREFERRED_SIZE))) .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() .addGap(2, 2, 2) .addComponent(mimeTypeLabel) @@ -241,7 +254,7 @@ final class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { .addComponent(signatureTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jTextField2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(signatureTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(hexPrefixLabel) .addComponent(signatureLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) @@ -254,11 +267,11 @@ final class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { .addGroup(layout.createSequentialGroup() .addGap(18, 18, 18) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jButton1) - .addComponent(jButton2))) + .addComponent(newTypeButton) + .addComponent(deleteTypeButton))) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jButton3)))) + .addComponent(saveTypeButton)))) .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 260, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); @@ -267,20 +280,20 @@ final class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup buttonGroup1; + private javax.swing.JButton deleteTypeButton; private javax.swing.JLabel hexPrefixLabel; - private javax.swing.JButton jButton1; - private javax.swing.JButton jButton2; - private javax.swing.JButton jButton3; private javax.swing.JScrollPane jScrollPane2; private javax.swing.JSeparator jSeparator1; private javax.swing.JTextArea jTextArea1; - private javax.swing.JTextField jTextField2; private javax.swing.JLabel mimeTypeLabel; private javax.swing.JTextField mimeTypeTextField; + private javax.swing.JButton newTypeButton; private javax.swing.JLabel offsetLabel; private javax.swing.JTextField offsetTextField; private javax.swing.JCheckBox postHitCheckBox; + private javax.swing.JButton saveTypeButton; private javax.swing.JLabel signatureLabel; + private javax.swing.JTextField signatureTextField; private javax.swing.JComboBox signatureTypeComboBox; private javax.swing.JLabel signatureTypeLabel; private javax.swing.JList typesList; diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java index 5a5ad78f31..c573b366b9 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java @@ -20,39 +20,34 @@ package org.sleuthkit.autopsy.modules.filetypeid; import java.util.ArrayList; import java.util.List; +import org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException; import org.sleuthkit.datamodel.AbstractFile; /** - * Does file type identification with user-defined file types. + * Does file type identification for user-defined file types. */ final class UserDefinedFileTypeIdentifier { private final List fileTypes; /** - * Creates an object that does file type identification with user-defined - * file types. Does not load the file type definitions. + * Creates an object that can do file type identification for user-defined + * file types. */ UserDefinedFileTypeIdentifier() { this.fileTypes = new ArrayList<>(); + List fileTypeDefs = UserDefinedFileTypesManager.getInstance().getFileTypes(); + this.fileTypes.addAll(fileTypeDefs); } /** - * Loads the set of user-defined file types. - */ - void loadFileTypes() throws UserDefinedFileTypes.UserDefinedFileTypesException { - this.fileTypes.clear(); - this.fileTypes.addAll(UserDefinedFileTypes.getFileTypes()); - } - - /** - * Attempts to identify a file using the set of user-defined file type - * file types. + * Attempts to identify a file using the set of user-defined file type file + * types. * * @param file The file to type. * @return A FileType object or null if identification fails. */ - FileType identify(AbstractFile file) { + FileType identify(final AbstractFile file) { FileType type = null; for (FileType fileType : this.fileTypes) { if (fileType.matches(file)) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.java deleted file mode 100644 index 84bc4f8778..0000000000 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.java +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2014 Basis Technology Corp. - * Contact: carrier sleuthkit 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.modules.filetypeid; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import javax.xml.parsers.ParserConfigurationException; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import javax.xml.bind.DatatypeConverter; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.PlatformUtil; -import org.sleuthkit.autopsy.coreutils.XMLUtil; -import org.sleuthkit.autopsy.modules.filetypeid.FileType.Signature; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; - -/** - * Allows a user to define named file types characterized by file signatures. - */ -final class UserDefinedFileTypes { - - private static final Logger logger = Logger.getLogger(UserDefinedFileTypes.class.getName()); - private static final String FILE_TYPE_DEFINITIONS_SCHEMA_FILE = "FileTypeDefinitions.xsd"; // NON-NLS - private static final String USER_DEFINED_TYPE_DEFINITIONS_FILE = "UserFileTypeDefinitions.xml"; // NON-NLS - private static final String AUTOPSY_TYPE_DEFINITIONS_FILE = "AutopsyFileTypeDefinitions.xml"; // NON-NLS - private static final String FILE_TYPES_TAG_NAME = "filetypes"; // NON-NLS - private static final String FILE_TYPE_TAG_NAME = "filetype"; // NON-NLS - private static final String ALERT_ATTRIBUTE = "alert"; // NON-NLS - private static final String TYPE_NAME_TAG_NAME = "typename"; // NON-NLS - private static final String SIGNATURE_TAG_NAME = "signature"; // NON-NLS - private static final String SIGNATURE_TYPE_ATTRIBUTE = "type"; // NON-NLS - private static final String BYTES_TAG_NAME = "bytes"; // NON-NLS - private static final String OFFSET_TAG_NAME = "offset"; // NON-NLS - private static final String ENCODING = "UTF-8"; //NON-NLS // RJCTODO: Is this right? - - static { - UserDefinedFileTypes.writePredefinedTypes(); - } - - /** - * Writes the predefined file types definition file. - */ - private static void writePredefinedTypes() { - try { - Path filePath = Paths.get(PlatformUtil.getUserConfigDirectory(), UserDefinedFileTypes.USER_DEFINED_TYPE_DEFINITIONS_FILE); - String filePathString = filePath.toAbsolutePath().toString(); - List fileTypes = new ArrayList<>(); // RJCTODO - UserDefinedFileTypes.writeFileTypes(fileTypes, filePathString); - } catch (UserDefinedFileTypesException ex) { - // RJCTODO - } - } - - /** - * Gets the user-defined file types. - * - * @return A list of file types, possibly empty - */ - synchronized static List getFileTypes() throws UserDefinedFileTypesException { - Map fileTypes = new HashMap<>(); - UserDefinedFileTypes.readFileTypes(fileTypes, UserDefinedFileTypes.AUTOPSY_TYPE_DEFINITIONS_FILE); - UserDefinedFileTypes.readFileTypes(fileTypes, UserDefinedFileTypes.USER_DEFINED_TYPE_DEFINITIONS_FILE); - return new ArrayList(fileTypes.values()); - } - - /** - * Reads file type definitions from a file into a map of type names to file - * types. File types already loaded into the map will be overwritten by file - * types from the file if the type name is the same. - * - * @param fileTypes The map of type names to file type objects. - * @param fileName The file from which to read the file type definitions. - */ - private static void readFileTypes(Map fileTypes, String fileName) throws UserDefinedFileTypesException { - Path filePath = Paths.get(PlatformUtil.getUserConfigDirectory(), fileName); - String filePathString = filePath.toAbsolutePath().toString(); - File file = new File(filePathString); - if (file.exists() && file.canRead()) { - for (FileType fileType : UserDefinedFileTypes.XMLReader.readFileTypes(filePathString)) { - fileTypes.put(fileType.getTypeName(), fileType); - } - } - } - - /** - * Sets the user-defined file types. - * - * @param fileTypes The file type definitions. - * @throws UserDefinedFileTypesException - */ - synchronized static void setFileTypes(List fileTypes) throws UserDefinedFileTypesException { - Path filePath = Paths.get(PlatformUtil.getUserConfigDirectory(), UserDefinedFileTypes.USER_DEFINED_TYPE_DEFINITIONS_FILE); - String filePathString = filePath.toAbsolutePath().toString(); - UserDefinedFileTypes.writeFileTypes(fileTypes, filePathString); - } - - /** - * Writes a set of file type definitions to a given file. - * - * @param fileTypes The file types. - * @param filePaht The destination file. - * @throws UserDefinedFileTypesException - */ - private static void writeFileTypes(List fileTypes, String filePath) throws UserDefinedFileTypesException { - try { - UserDefinedFileTypes.XMLWriter.writeFileTypes(fileTypes, filePath); - } catch (ParserConfigurationException | IOException ex) { - UserDefinedFileTypes.logger.log(Level.SEVERE, "Failed to write file types file", ex); - throw new UserDefinedFileTypesException(ex.getLocalizedMessage()); // RJCTODO: Create a bundled message - } - } - - /** - * Provides a mechanism for writing a set of file type definitions to an XML - * file. - */ - private static class XMLWriter { - - /** - * Writes a set of file type definitions to an XML file. - * - * @param signatures A collection of file types. - * @param filePath The path to the destination file. - */ - private static void writeFileTypes(List fileTypes, String filePath) throws ParserConfigurationException, IOException { - Document doc = XMLUtil.createDoc(); - Element fileTypesElem = doc.createElement(UserDefinedFileTypes.FILE_TYPES_TAG_NAME); - doc.appendChild(fileTypesElem); - for (FileType fileType : fileTypes) { - Element fileTypeElem = UserDefinedFileTypes.XMLWriter.createFileTypeElement(fileType, doc); - fileTypesElem.appendChild(fileTypeElem); - } - if (!XMLUtil.saveDoc(HashDbManager.class, filePath, UserDefinedFileTypes.ENCODING, doc)) { - throw new IOException("Could not save user defined file types"); - } - } - - /** - * Creates an XML representation of a file type. - * - * @param fileType The file type object. - * @param doc The DOM document to use to create the XML. - * @return An XML element. - */ - private static Element createFileTypeElement(FileType fileType, Document doc) { - /** - * Create a file type element with an alert attribute. - */ - Element fileTypeElem = doc.createElement(UserDefinedFileTypes.FILE_TYPE_TAG_NAME); - fileTypeElem.setAttribute(UserDefinedFileTypes.ALERT_ATTRIBUTE, Boolean.toString(fileType.alertOnMatch())); - - /** - * Add a type name child element. - */ - Element typeNameElem = doc.createElement(UserDefinedFileTypes.TYPE_NAME_TAG_NAME); - typeNameElem.setTextContent(fileType.getTypeName()); - fileTypeElem.appendChild(typeNameElem); - - /** - * Add a signature child element with a type attribute. - */ - Signature signature = fileType.getSignature(); - Element signatureElem = doc.createElement(UserDefinedFileTypes.SIGNATURE_TAG_NAME); - signatureElem.setAttribute(UserDefinedFileTypes.SIGNATURE_TYPE_ATTRIBUTE, signature.getType().toString()); - fileTypeElem.appendChild(signatureElem); - - /** - * Add a bytes child element to the signature element. - */ - Element bytesElem = doc.createElement(UserDefinedFileTypes.BYTES_TAG_NAME); - bytesElem.setTextContent(DatatypeConverter.printHexBinary(signature.getSignatureBytes())); - signatureElem.appendChild(bytesElem); - - /** - * Add an offset child element to the signature element. - */ - Element offsetElem = doc.createElement(UserDefinedFileTypes.OFFSET_TAG_NAME); - offsetElem.setTextContent(DatatypeConverter.printLong(signature.getOffset())); - signatureElem.appendChild(offsetElem); - - return fileTypeElem; - } - } - - /** - * Provides a mechanism for reading a set of file type definitions from an - * XML file. - */ - private static class XMLReader { - - /** - * Reads a set of file type definitions from an XML file. - * - * @param filePath The path to the file. - * @return A collection of file types. - */ - private static List readFileTypes(String filePath) throws UserDefinedFileTypesException { - List fileTypes = new ArrayList<>(); - Path xsdPath = Paths.get(PlatformUtil.getUserConfigDirectory(), UserDefinedFileTypes.FILE_TYPE_DEFINITIONS_SCHEMA_FILE); - String xsdPathString = xsdPath.toAbsolutePath().toString(); - File file = new File(xsdPathString); - if (file.exists() && file.canRead()) { - Document doc = XMLUtil.loadDoc(UserDefinedFileTypes.XMLReader.class, filePath, xsdPathString); - if (doc != null) { - Element fileTypesElem = doc.getDocumentElement(); - if (fileTypesElem != null && fileTypesElem.getNodeName().equals(UserDefinedFileTypes.FILE_TYPES_TAG_NAME)) { - NodeList fileTypeElems = fileTypesElem.getElementsByTagName(UserDefinedFileTypes.FILE_TYPE_TAG_NAME); - for (int i = 0; i < fileTypeElems.getLength(); ++i) { - Element fileTypeElem = (Element) fileTypeElems.item(i); - FileType fileType = UserDefinedFileTypes.XMLReader.parseFileType(fileTypeElem); - fileTypes.add(fileType); - } - } - } - } - return fileTypes; - } - - /** - * Parse a file type definition from a file type XML element. - * - * @param fileTypeElem The XML element. - * @return A file type object. - * @throws UserDefinedFileTypesException - */ - private static FileType parseFileType(Element fileTypeElem) throws UserDefinedFileTypesException { - /** - * Get the alert attribute. - */ - String alertAttribute = fileTypeElem.getAttribute(UserDefinedFileTypes.ALERT_ATTRIBUTE); - boolean alert = Boolean.parseBoolean(alertAttribute); - - /** - * Get the type name child element. - */ - String typeName = UserDefinedFileTypes.getChildElementTextContent(fileTypeElem, UserDefinedFileTypes.TYPE_NAME_TAG_NAME); - - /** - * Get the signature child element. - */ - Element signatureElem; - NodeList signatureElems = fileTypeElem.getElementsByTagName(UserDefinedFileTypes.SIGNATURE_TAG_NAME); - signatureElem = (Element) signatureElems.item(0); - - /** - * Get the signature type attribute from the signature child - * element. - */ - String sigTypeAttribute = signatureElem.getAttribute(typeName); - Signature.Type signatureType = Signature.Type.valueOf(sigTypeAttribute); - - /** - * Get the signature bytes. - */ - String sigBytesString = UserDefinedFileTypes.getChildElementTextContent(signatureElem, UserDefinedFileTypes.TYPE_NAME_TAG_NAME); - byte[] signatureBytes = DatatypeConverter.parseHexBinary(sigBytesString); - - /** - * Get the offset. - */ - String offsetString = UserDefinedFileTypes.getChildElementTextContent(signatureElem, UserDefinedFileTypes.OFFSET_TAG_NAME); - long offset = DatatypeConverter.parseLong(offsetString); - - /** - * Put it all together. - */ - Signature signature = new Signature(signatureBytes, offset, signatureType); - return new FileType(typeName, signature, alert); - } - } - - /** - * Gets the text content of a single child element. - * - * @param elem The parent element. - * @param tagName The tag name of the child element. - * @return The text content. - * @throws UserDefinedFileTypesException - */ - private static String getChildElementTextContent(Element elem, String tagName) throws UserDefinedFileTypesException { - /** - * The checks here are essentially "sanity checks" since the XML was - * already validated using the XSD file. - */ - String textContent = ""; - NodeList childElems = elem.getElementsByTagName(tagName); - if (childElems.getLength() > 0) { - Element childElem = (Element) childElems.item(0); - textContent = childElem.getTextContent(); - if (textContent.isEmpty()) { - UserDefinedFileTypes.logger.log(Level.SEVERE, "File type {0} child element missing text content", tagName); // NON-NLS - } - } else { - UserDefinedFileTypes.logger.log(Level.SEVERE, "File type element missing {0} child element", tagName); // NON-NLS - } - if (textContent.isEmpty()) { - throw new UserDefinedFileTypes.UserDefinedFileTypesException("Error reading file type definitions file, see log for details"); // RJCTODO: Bundle - } - return textContent; - } - - /** - * An exception type to conflate more implementation-details-specific - * exception types (which are logged by this class) into a single generic - * type. - */ - static class UserDefinedFileTypesException extends Exception { - - UserDefinedFileTypesException(String message) { - super(message); - } - } - -} diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.xsd b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.xsd index 2512542294..aa8e053534 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.xsd +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.xsd @@ -15,36 +15,35 @@ - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java new file mode 100644 index 0000000000..257e740ecf --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java @@ -0,0 +1,511 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2014 Basis Technology Corp. + * Contact: carrier sleuthkit 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.modules.filetypeid; + +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import javax.xml.parsers.ParserConfigurationException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import javax.xml.bind.DatatypeConverter; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.sleuthkit.autopsy.coreutils.XMLUtil; +import org.sleuthkit.autopsy.modules.filetypeid.FileType.Signature; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; + +/** + * Manages user-defined file types characterized by type names (e.g., MIME type) + * and signatures. + */ +final class UserDefinedFileTypesManager { + + private static final Logger logger = Logger.getLogger(UserDefinedFileTypesManager.class.getName()); + private static final String FILE_TYPE_DEFINITIONS_SCHEMA_FILE = "FileTypeDefinitions.xsd"; // NON-NLS + private static final String USER_DEFINED_TYPE_DEFINITIONS_FILE = "UserFileTypeDefinitions.xml"; // NON-NLS + private static final String PROPERTIES_FILE_NAME = "UserFileTypeDefinitions"; //NON_NLS + private static final String DELETED_PREDEFINED_TYPES_KEY = "DeletedPredefinedTypes"; //NON_NLS + private static final String FILE_TYPES_TAG_NAME = "filetypes"; // NON-NLS + private static final String FILE_TYPE_TAG_NAME = "filetype"; // NON-NLS + private static final String ALERT_ATTRIBUTE = "alert"; // NON-NLS + private static final String TYPE_NAME_TAG_NAME = "typename"; // NON-NLS + private static final String SIGNATURE_TAG_NAME = "signature"; // NON-NLS + private static final String SIGNATURE_TYPE_ATTRIBUTE = "type"; // NON-NLS + private static final String BYTES_TAG_NAME = "bytes"; // NON-NLS + private static final String OFFSET_TAG_NAME = "offset"; // NON-NLS + private static final String ENCODING = "UTF-8"; //NON-NLS + private static final String ASCII_ENCODING = "US-ASCII"; //NON-NLS + private static UserDefinedFileTypesManager instance; + private final Map predefinedFileTypes = new HashMap<>(); + private final Map userDefinedFileTypes = new HashMap<>(); + private final Map fileTypes = new HashMap<>(); + + /** + * Gets the user-defined file types manager. + * + * @return A singleton UserDefinedFileTypesManager object. + */ + synchronized static UserDefinedFileTypesManager getInstance() { + if (instance == null) { + instance = new UserDefinedFileTypesManager(); + } + return instance; + } + + /** + * Creates a manager of user-defined file types characterized by type names + * (e.g., MIME type) and signatures. + */ + private UserDefinedFileTypesManager() { + createFileTypesForTesting(); + createStandardPredefinedFileTypes(); + removeDeletedPredefinedFileTypes(); + initializeUserDefinedFileTypes(); + } + + /** + * Adds file types useful for testing this class to the in-memory mapping of + * file type names to predefined file types. + */ + private void createFileTypesForTesting() { + /** + * RJCTODO: This code should be moved into a unit test. + */ + if (true) { + /** + * Create a file type that should match $MBR in Small2 image. + */ + this.predefinedFileTypes.put("predefinedRAW", new FileType("predefinedRAW", new Signature(new byte[]{(byte) 0x66, (byte) 0x73, (byte) 0x00}, 8L, FileType.Signature.Type.RAW), true)); + + /** + * Create a file type that should match test.txt in the Small2 + * image. + */ + try { + this.predefinedFileTypes.put("predefinedASCII", new FileType("predefinedASCII", new Signature("hello".getBytes(ASCII_ENCODING), 0L, FileType.Signature.Type.ASCII), true)); + } catch (UnsupportedEncodingException ex) { + logger.log(Level.SEVERE, "Unable to create 'predefinedASCII' predefined file type definition", ex); //NON-NLS + } + } + } + + /** + * Adds standard predefined file types to the in-memory mapping of file type + * names to predefined file types. + */ + private void createStandardPredefinedFileTypes() { + } + + /** + * Removes predefined file types deleted by the user from the in-memory + * mapping of file type names to predefined file types. + */ + private void removeDeletedPredefinedFileTypes() { + String deletedTypes = ModuleSettings.getConfigSetting(PROPERTIES_FILE_NAME, DELETED_PREDEFINED_TYPES_KEY); + if (null != deletedTypes) { + for (String typeName : deletedTypes.split(", ")) { + this.predefinedFileTypes.remove(typeName); + } + } + } + + /** + * Reads user-defined file types into an in-memory mapping of file type + * names to file types. + */ + private void initializeUserDefinedFileTypes() { + try { + /** + * Read the user-defined types from the backing XML file. + */ + String filePath = getFileTypeDefinitionsFilePath(USER_DEFINED_TYPE_DEFINITIONS_FILE); + File file = new File(filePath); + if (file.exists() && file.canRead()) { + for (FileType fileType : XMLReader.readFileTypes(filePath)) { + userDefinedFileTypes.put(fileType.getTypeName(), fileType); + } + } + + /** + * Combine the predefined and user-defined file types, with + * user-defined file types taking precedence over any predefined + * file types with the same type name. + */ + fileTypes.putAll(predefinedFileTypes); + fileTypes.putAll(userDefinedFileTypes); + + } catch (InvalidXMLException ex) { + // RJCTODO: + } + } + + /** + * Gets the file types. + * + * @return A mapping of file type names to file types, possibly empty. + */ + synchronized List getFileTypes() { + /** + * It is safe to return references to the internal file type objects + * because they are immutable. + */ + return new ArrayList<>(this.fileTypes.values()); + } + + /** + * Adds a new file type definition, overwriting any file type with the same + * type name that already exists. + * + * @param fileType The file type to add. + * @throws + * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException + */ + synchronized void addFileType(FileType fileType) throws UserDefinedFileTypesException { + List newFileTypes = new ArrayList<>(); + newFileTypes.add(fileType); + addFileTypes(newFileTypes); + } + + /** + * Adds a set of new file types, overwriting any file types with the same + * type names that already exist. + * + * @param newFileTypes The file types to add. + * @throws + * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException + */ + synchronized void addFileTypes(Collection newFileTypes) throws UserDefinedFileTypesException { + for (FileType fileType : newFileTypes) { + deleteFromPredefinedTypes(fileType); + userDefinedFileTypes.put(fileType.getTypeName(), fileType); + fileTypes.put(fileType.getTypeName(), fileType); + } + saveUserDefinedTypes(); + } + + /** + * Deletes a file type. + * + * @param fileType The file type to delete. + * @throws + * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException + */ + synchronized void deleteFileType(FileType fileType) throws UserDefinedFileTypesException { + List deletedFileTypes = new ArrayList<>(); + deletedFileTypes.add(fileType); + deleteFileTypes(deletedFileTypes); + } + + /** + * Deletes a set of file types. + * + * @param deletedFileTypes The file types to delete. + * @throws + * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException + */ + synchronized void deleteFileTypes(Collection deletedFileTypes) throws UserDefinedFileTypesException { + for (FileType fileType : deletedFileTypes) { + deleteFromPredefinedTypes(fileType); + userDefinedFileTypes.remove(fileType.getTypeName(), fileType); + fileTypes.remove(fileType.getTypeName(), fileType); + } + saveUserDefinedTypes(); + } + + /** + * Removes a file type, if present, from the in-memory mapping of predefined + * file types and marks the predefined file type as deleted by the user. + * + * @param fileType The file type to delete. + */ + private void deleteFromPredefinedTypes(FileType fileType) { + if (predefinedFileTypes.containsKey(fileType.getTypeName())) { + predefinedFileTypes.remove(fileType.getTypeName()); + String deletedTypesSetting = ModuleSettings.getConfigSetting(PROPERTIES_FILE_NAME, DELETED_PREDEFINED_TYPES_KEY); + if (null != deletedTypesSetting) { + List deletedTypes = Arrays.asList(deletedTypesSetting.split(", ")); + if (!deletedTypes.contains(fileType.getTypeName())) { + deletedTypesSetting += "," + fileType.getTypeName(); + ModuleSettings.setConfigSetting(PROPERTIES_FILE_NAME, DELETED_PREDEFINED_TYPES_KEY, deletedTypesSetting); + } + } else { + ModuleSettings.setConfigSetting(PROPERTIES_FILE_NAME, DELETED_PREDEFINED_TYPES_KEY, fileType.getTypeName()); + } + } + } + + /** + * Persist the user-defined file type definitions. + * + * @throws + * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException + */ + private void saveUserDefinedTypes() throws UserDefinedFileTypesException { + String filePath = getFileTypeDefinitionsFilePath(USER_DEFINED_TYPE_DEFINITIONS_FILE); + writeFileTypes(userDefinedFileTypes.values(), filePath); + } + + /** + * Writes a set of file type definitions to a given file. + * + * @param fileTypes The file types. + * @param filePath The destination file. + * @throws UserDefinedFileTypesException + */ + private static void writeFileTypes(Collection fileTypes, String filePath) throws UserDefinedFileTypesException { + try { + XMLWriter.writeFileTypes(fileTypes, filePath); + } catch (ParserConfigurationException | IOException ex) { + UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Failed to write file types file", ex); + throw new UserDefinedFileTypesException(ex.getLocalizedMessage()); // RJCTODO: Create a bundled message + } + } + + /** + * Gets the absolute path of a file type definitions file. + * + * @param fileName The name of the file. + * @return The absolute path to the file. + */ + private static String getFileTypeDefinitionsFilePath(String fileName) { + Path filePath = Paths.get(PlatformUtil.getUserConfigDirectory(), fileName); + return filePath.toAbsolutePath().toString(); + } + + /** + * Provides a mechanism for writing a set of file type definitions to an XML + * file. + */ + private static class XMLWriter { + + /** + * Writes a set of file type definitions to an XML file. + * + * @param signatures A collection of file types. + * @param filePath The path to the destination file. + */ + private static void writeFileTypes(Collection fileTypes, String filePath) throws ParserConfigurationException, IOException { + Document doc = XMLUtil.createDoc(); + Element fileTypesElem = doc.createElement(UserDefinedFileTypesManager.FILE_TYPES_TAG_NAME); + doc.appendChild(fileTypesElem); + for (FileType fileType : fileTypes) { + Element fileTypeElem = UserDefinedFileTypesManager.XMLWriter.createFileTypeElement(fileType, doc); + fileTypesElem.appendChild(fileTypeElem); + } + if (!XMLUtil.saveDoc(HashDbManager.class, filePath, UserDefinedFileTypesManager.ENCODING, doc)) { + // RJCTODO: If time permits add XMLUtil that properly throws and deprecate this one + throw new IOException("Error saving user defined file types, see log for details"); // NON-NLS + } + } + + /** + * Creates an XML representation of a file type. + * + * @param fileType The file type object. + * @param doc The DOM document to use to create the XML. + * @return An XML element. + */ + private static Element createFileTypeElement(FileType fileType, Document doc) { + /** + * Create a file type element with an alert attribute. + */ + Element fileTypeElem = doc.createElement(UserDefinedFileTypesManager.FILE_TYPE_TAG_NAME); + fileTypeElem.setAttribute(UserDefinedFileTypesManager.ALERT_ATTRIBUTE, Boolean.toString(fileType.alertOnMatch())); + + /** + * Add a type name child element. + */ + Element typeNameElem = doc.createElement(UserDefinedFileTypesManager.TYPE_NAME_TAG_NAME); + typeNameElem.setTextContent(fileType.getTypeName()); + fileTypeElem.appendChild(typeNameElem); + + /** + * Add a signature child element with a type attribute. + */ + Signature signature = fileType.getSignature(); + Element signatureElem = doc.createElement(UserDefinedFileTypesManager.SIGNATURE_TAG_NAME); + signatureElem.setAttribute(UserDefinedFileTypesManager.SIGNATURE_TYPE_ATTRIBUTE, signature.getType().toString()); + fileTypeElem.appendChild(signatureElem); + + /** + * Add a bytes child element to the signature element. + */ + Element bytesElem = doc.createElement(UserDefinedFileTypesManager.BYTES_TAG_NAME); + bytesElem.setTextContent(DatatypeConverter.printHexBinary(signature.getSignatureBytes())); + signatureElem.appendChild(bytesElem); + + /** + * Add an offset child element to the signature element. + */ + Element offsetElem = doc.createElement(UserDefinedFileTypesManager.OFFSET_TAG_NAME); + offsetElem.setTextContent(DatatypeConverter.printLong(signature.getOffset())); + signatureElem.appendChild(offsetElem); + + return fileTypeElem; + } + } + + /** + * Provides a mechanism for reading a set of file type definitions from an + * XML file. + */ + private static class XMLReader { + + /** + * Reads a set of file type definitions from an XML file. + * + * @param filePath The path to the file. + * @return A collection of file types. + */ + private static List readFileTypes(String filePath) throws InvalidXMLException { + List fileTypes = new ArrayList<>(); + Path xsdPath = Paths.get(PlatformUtil.getUserConfigDirectory(), UserDefinedFileTypesManager.FILE_TYPE_DEFINITIONS_SCHEMA_FILE); + String xsdPathString = xsdPath.toAbsolutePath().toString(); + File file = new File(xsdPathString); + if (file.exists() && file.canRead()) { + Document doc = XMLUtil.loadDoc(UserDefinedFileTypesManager.XMLReader.class, filePath, xsdPathString); + if (doc != null) { + Element fileTypesElem = doc.getDocumentElement(); + if (fileTypesElem != null && fileTypesElem.getNodeName().equals(UserDefinedFileTypesManager.FILE_TYPES_TAG_NAME)) { + NodeList fileTypeElems = fileTypesElem.getElementsByTagName(UserDefinedFileTypesManager.FILE_TYPE_TAG_NAME); + for (int i = 0; i < fileTypeElems.getLength(); ++i) { + Element fileTypeElem = (Element) fileTypeElems.item(i); + FileType fileType = UserDefinedFileTypesManager.XMLReader.parseFileType(fileTypeElem); + fileTypes.add(fileType); + } + } + } + } + return fileTypes; + } + + /** + * Parse a file type definition from a file type XML element. + * + * @param fileTypeElem The XML element. + * @return A file type object. + * @throws UserDefinedFileTypesException + */ + private static FileType parseFileType(Element fileTypeElem) throws InvalidXMLException { + /** + * Get the alert attribute. + */ + String alertAttribute = fileTypeElem.getAttribute(UserDefinedFileTypesManager.ALERT_ATTRIBUTE); + boolean alert = Boolean.parseBoolean(alertAttribute); + + /** + * Get the type name child element. + */ + String typeName = UserDefinedFileTypesManager.getChildElementTextContent(fileTypeElem, UserDefinedFileTypesManager.TYPE_NAME_TAG_NAME); + + /** + * Get the signature child element. + */ + Element signatureElem; + NodeList signatureElems = fileTypeElem.getElementsByTagName(UserDefinedFileTypesManager.SIGNATURE_TAG_NAME); + signatureElem = (Element) signatureElems.item(0); + + /** + * Get the signature (interpretation) type attribute from the + * signature child element. + */ + String sigTypeAttribute = signatureElem.getAttribute(UserDefinedFileTypesManager.SIGNATURE_TYPE_ATTRIBUTE); + Signature.Type signatureType = Signature.Type.valueOf(sigTypeAttribute); + + /** + * Get the signature bytes. + */ + String sigBytesString = UserDefinedFileTypesManager.getChildElementTextContent(signatureElem, UserDefinedFileTypesManager.TYPE_NAME_TAG_NAME); + byte[] signatureBytes = DatatypeConverter.parseHexBinary(sigBytesString); + + /** + * Get the offset. + */ + String offsetString = UserDefinedFileTypesManager.getChildElementTextContent(signatureElem, UserDefinedFileTypesManager.OFFSET_TAG_NAME); + long offset = DatatypeConverter.parseLong(offsetString); + + /** + * Put it all together. + */ + Signature signature = new Signature(signatureBytes, offset, signatureType); + return new FileType(typeName, signature, alert); + } + } + + /** + * Gets the text content of a single child element. + * + * @param elem The parent element. + * @param tagName The tag name of the child element. + * @return The text content. + * @throws UserDefinedFileTypesException + */ + private static String getChildElementTextContent(Element elem, String tagName) throws InvalidXMLException { + /** + * The checks here are essentially "sanity checks" since the XML was + * already validated using the XSD file. + */ + NodeList childElems = elem.getElementsByTagName(tagName); + if (childElems.getLength() > 0) { + Element childElem = (Element) childElems.item(0); + String textContent = childElem.getTextContent(); + if (!textContent.isEmpty()) { + return textContent; + } else { + throw new InvalidXMLException("File type " + tagName + " child element missing text content"); // NON-NLS + } + } else { + throw new InvalidXMLException("File type element missing " + tagName + " child element"); // NON-NLS + } + } + + /** + * RJCTODO + */ + static class InvalidXMLException extends Exception { + + InvalidXMLException(String message) { + super(message); + } + } + + /** + * Used to translate more implementation-details-specific exceptions (which + * are logged by this class) into more generic exceptions. + */ + static class UserDefinedFileTypesException extends Exception { + + UserDefinedFileTypesException(String message) { + super(message); + } + } + +} From 5da64cc76e5d94461bc4ff359b3a681f8acb3ebb Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 2 Dec 2014 13:42:13 -0500 Subject: [PATCH 08/27] Make predefined user types hidden, not deletable (part 1) --- .../UserDefinedFileTypeIdentifier.java | 1 - .../UserDefinedFileTypesManager.java | 133 +++++++----------- 2 files changed, 52 insertions(+), 82 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java index c573b366b9..f7dac840ca 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java @@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.modules.filetypeid; import java.util.ArrayList; import java.util.List; -import org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException; import org.sleuthkit.datamodel.AbstractFile; /** diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java index 257e740ecf..ee0f601bf2 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java @@ -24,7 +24,6 @@ import java.io.UnsupportedEncodingException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -36,7 +35,6 @@ import org.w3c.dom.Element; import org.w3c.dom.NodeList; import javax.xml.bind.DatatypeConverter; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.XMLUtil; import org.sleuthkit.autopsy.modules.filetypeid.FileType.Signature; @@ -51,8 +49,6 @@ final class UserDefinedFileTypesManager { private static final Logger logger = Logger.getLogger(UserDefinedFileTypesManager.class.getName()); private static final String FILE_TYPE_DEFINITIONS_SCHEMA_FILE = "FileTypeDefinitions.xsd"; // NON-NLS private static final String USER_DEFINED_TYPE_DEFINITIONS_FILE = "UserFileTypeDefinitions.xml"; // NON-NLS - private static final String PROPERTIES_FILE_NAME = "UserFileTypeDefinitions"; //NON_NLS - private static final String DELETED_PREDEFINED_TYPES_KEY = "DeletedPredefinedTypes"; //NON_NLS private static final String FILE_TYPES_TAG_NAME = "filetypes"; // NON-NLS private static final String FILE_TYPE_TAG_NAME = "filetype"; // NON-NLS private static final String ALERT_ATTRIBUTE = "alert"; // NON-NLS @@ -71,7 +67,7 @@ final class UserDefinedFileTypesManager { /** * Gets the user-defined file types manager. * - * @return A singleton UserDefinedFileTypesManager object. + * @return A singleton user-defined file types manager. */ synchronized static UserDefinedFileTypesManager getInstance() { if (instance == null) { @@ -85,55 +81,57 @@ final class UserDefinedFileTypesManager { * (e.g., MIME type) and signatures. */ private UserDefinedFileTypesManager() { - createFileTypesForTesting(); - createStandardPredefinedFileTypes(); - removeDeletedPredefinedFileTypes(); - initializeUserDefinedFileTypes(); - } - - /** - * Adds file types useful for testing this class to the in-memory mapping of - * file type names to predefined file types. - */ - private void createFileTypesForTesting() { - /** - * RJCTODO: This code should be moved into a unit test. - */ - if (true) { - /** - * Create a file type that should match $MBR in Small2 image. - */ - this.predefinedFileTypes.put("predefinedRAW", new FileType("predefinedRAW", new Signature(new byte[]{(byte) 0x66, (byte) 0x73, (byte) 0x00}, 8L, FileType.Signature.Type.RAW), true)); - - /** - * Create a file type that should match test.txt in the Small2 - * image. - */ - try { - this.predefinedFileTypes.put("predefinedASCII", new FileType("predefinedASCII", new Signature("hello".getBytes(ASCII_ENCODING), 0L, FileType.Signature.Type.ASCII), true)); - } catch (UnsupportedEncodingException ex) { - logger.log(Level.SEVERE, "Unable to create 'predefinedASCII' predefined file type definition", ex); //NON-NLS - } - } + loadPredefinedFileTypes(); + loadUserDefinedFileTypes(); } /** * Adds standard predefined file types to the in-memory mapping of file type * names to predefined file types. */ - private void createStandardPredefinedFileTypes() { - } + private void loadPredefinedFileTypes() { + // RJCTODO: Remove + /** + * Create a file type that should match $MBR in Small2 image. + */ + this.fileTypes.put("predefinedRAW", new FileType("predefinedRAW", new Signature(new byte[]{(byte) 0x66, (byte) 0x73, (byte) 0x00}, 8L, FileType.Signature.Type.RAW), true)); - /** - * Removes predefined file types deleted by the user from the in-memory - * mapping of file type names to predefined file types. - */ - private void removeDeletedPredefinedFileTypes() { - String deletedTypes = ModuleSettings.getConfigSetting(PROPERTIES_FILE_NAME, DELETED_PREDEFINED_TYPES_KEY); - if (null != deletedTypes) { - for (String typeName : deletedTypes.split(", ")) { - this.predefinedFileTypes.remove(typeName); - } + /** + * Create a file type that should match test.txt in the Small2 image. + */ + // RJCTODO: Remove + try { + this.fileTypes.put("predefinedASCII", new FileType("predefinedASCII", new Signature("hello".getBytes(ASCII_ENCODING), 0L, FileType.Signature.Type.ASCII), true)); + } catch (UnsupportedEncodingException ex) { + logger.log(Level.SEVERE, "Unable to create 'predefinedASCII' predefined file type definition", ex); //NON-NLS + } + + try { + // RJCTODO: Remove this code from TikaFileTypeDetector.java +// try { +// byte buf[]; +// int len = abstractFile.read(buffer, 0, BUFFER_SIZE); +// if (len < BUFFER_SIZE) { +// buf = new byte[len]; +// System.arraycopy(buffer, 0, buf, 0, len); +// } else { +// buf = buffer; +// } +// +// // the xml detection in Tika tries to parse the entire file and throws exceptions +// // for files that are not valid XML +// try { +// String tagHeader = new String(buf, 0, 5); +// if (tagHeader.equals(" newFileTypes) throws UserDefinedFileTypesException { for (FileType fileType : newFileTypes) { - deleteFromPredefinedTypes(fileType); userDefinedFileTypes.put(fileType.getTypeName(), fileType); fileTypes.put(fileType.getTypeName(), fileType); } @@ -233,35 +227,12 @@ final class UserDefinedFileTypesManager { */ synchronized void deleteFileTypes(Collection deletedFileTypes) throws UserDefinedFileTypesException { for (FileType fileType : deletedFileTypes) { - deleteFromPredefinedTypes(fileType); userDefinedFileTypes.remove(fileType.getTypeName(), fileType); fileTypes.remove(fileType.getTypeName(), fileType); } saveUserDefinedTypes(); } - /** - * Removes a file type, if present, from the in-memory mapping of predefined - * file types and marks the predefined file type as deleted by the user. - * - * @param fileType The file type to delete. - */ - private void deleteFromPredefinedTypes(FileType fileType) { - if (predefinedFileTypes.containsKey(fileType.getTypeName())) { - predefinedFileTypes.remove(fileType.getTypeName()); - String deletedTypesSetting = ModuleSettings.getConfigSetting(PROPERTIES_FILE_NAME, DELETED_PREDEFINED_TYPES_KEY); - if (null != deletedTypesSetting) { - List deletedTypes = Arrays.asList(deletedTypesSetting.split(", ")); - if (!deletedTypes.contains(fileType.getTypeName())) { - deletedTypesSetting += "," + fileType.getTypeName(); - ModuleSettings.setConfigSetting(PROPERTIES_FILE_NAME, DELETED_PREDEFINED_TYPES_KEY, deletedTypesSetting); - } - } else { - ModuleSettings.setConfigSetting(PROPERTIES_FILE_NAME, DELETED_PREDEFINED_TYPES_KEY, fileType.getTypeName()); - } - } - } - /** * Persist the user-defined file type definitions. * From a75ebe8028a9bc69dfef101e79b9b16bd7d796c7 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 4 Dec 2014 18:46:17 -0500 Subject: [PATCH 09/27] Commit version of file types manager with fine grained-control, simpler will be better --- .../modules/filetypeid/Bundle.properties | 30 ++-- .../modules/filetypeid/Bundle_ja.properties | 20 +-- ...orm => FileTypeIdGlobalSettingsPanel.form} | 26 ++-- ...ava => FileTypeIdGlobalSettingsPanel.java} | 30 ++-- ... => FileTypeIdIngestJobSettingsPanel.form} | 4 +- ... => FileTypeIdIngestJobSettingsPanel.java} | 8 +- .../filetypeid/FileTypeIdModuleFactory.java | 4 +- .../FileTypeIdOptionsPanelController.java | 6 +- .../UserDefinedFileTypesManager.java | 144 ++++++++++-------- 9 files changed, 145 insertions(+), 127 deletions(-) rename Core/src/org/sleuthkit/autopsy/modules/filetypeid/{FileTypeIdSettingsPanel.form => FileTypeIdGlobalSettingsPanel.form} (87%) rename Core/src/org/sleuthkit/autopsy/modules/filetypeid/{FileTypeIdSettingsPanel.java => FileTypeIdGlobalSettingsPanel.java} (90%) rename Core/src/org/sleuthkit/autopsy/modules/filetypeid/{FileTypeIdModuleSettingsPanel.form => FileTypeIdIngestJobSettingsPanel.form} (87%) rename Core/src/org/sleuthkit/autopsy/modules/filetypeid/{FileTypeIdModuleSettingsPanel.java => FileTypeIdIngestJobSettingsPanel.java} (89%) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties index 8df981383f..4481e95ab3 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties @@ -1,5 +1,4 @@ OpenIDE-Module-Name=FileTypeId -FileTypeIdModuleSettingsPanel.skipKnownCheckBox.toolTipText=Depending on how many files have known hashes, checking this box will improve the speed of file type identification. FileTypeIdIngestModule.moduleName.text=File Type Identification FileTypeIdIngestModule.moduleDesc.text=Matches file types based on binary signatures. FileTypeIdIngestModule.complete.totalProcTime=Total Processing Time @@ -7,17 +6,18 @@ FileTypeIdIngestModule.complete.totalFiles=Total Files Processed FileTypeIdIngestModule.complete.srvMsg.text=File Type Id Results FileTypeIdModuleFactory.getIngestJobSettingsPanel.exception.msg=Expected settings argument to be instanceof FileTypeIdModuleSettings FileTypeIdModuleFactory.createFileIngestModule.exception.msg=Expected settings argument to be instanceof FileTypeIdModuleSettings -FileTypeIdModuleSettingsPanel.skipKnownCheckBox.text=Skip known files (NSRL) -FileTypeIdSettingsPanel.mimeTypeTextField.text= -FileTypeIdSettingsPanel.mimeTypeLabel.text=Mime Type -FileTypeIdSettingsPanel.signatureTypeLabel.text=Signature Type -FileTypeIdSettingsPanel.signatureLabel.text=Signature -FileTypeIdSettingsPanel.offsetLabel.text=Offset -FileTypeIdSettingsPanel.offsetTextField.text= -FileTypeIdSettingsPanel.hexPrefixLabel.text=0x -FileTypeIdSettingsPanel.jTextArea1.text=Enter a MIME type and signature to be used to identify files of that type. If the signature is a byte sequence, enter the sequence using two hex values for each byte, e.g., EEF0 is a two byte signature. -FileTypeIdSettingsPanel.postHitCheckBox.text=Post interesting file hit when found -FileTypeIdSettingsPanel.newTypeButton.text=New Type -FileTypeIdSettingsPanel.deleteTypeButton.text=DeleteType -FileTypeIdSettingsPanel.saveTypeButton.text=Save Type -FileTypeIdSettingsPanel.signatureTextField.text= +FileTypeIdIngestJobSettingsPanel.skipKnownCheckBox.toolTipText=Depending on how many files have known hashes, checking this box will improve the speed of file type identification. +FileTypeIdIngestJobSettingsPanel.skipKnownCheckBox.text=Skip known files (NSRL) +FileTypeIdGlobalSettingsPanel.hexPrefixLabel.text=0x +FileTypeIdGlobalSettingsPanel.saveTypeButton.text=Save Type +FileTypeIdGlobalSettingsPanel.deleteTypeButton.text=DeleteType +FileTypeIdGlobalSettingsPanel.newTypeButton.text=New Type +FileTypeIdGlobalSettingsPanel.offsetTextField.text= +FileTypeIdGlobalSettingsPanel.offsetLabel.text=Offset +FileTypeIdGlobalSettingsPanel.postHitCheckBox.text=Post interesting file hit when found +FileTypeIdGlobalSettingsPanel.signatureTextField.text= +FileTypeIdGlobalSettingsPanel.jTextArea1.text=Enter a MIME type and signature to be used to identify files of that type. If the signature is a byte sequence, enter the sequence using two hex values for each byte, e.g., EEF0 is a two byte signature. +FileTypeIdGlobalSettingsPanel.signatureTypeLabel.text=Signature Type +FileTypeIdGlobalSettingsPanel.mimeTypeTextField.text= +FileTypeIdGlobalSettingsPanel.signatureLabel.text=Signature +FileTypeIdGlobalSettingsPanel.mimeTypeLabel.text=Mime Type diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle_ja.properties index a12d0e7cd8..ee53301d77 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle_ja.properties @@ -1,10 +1,10 @@ -OpenIDE-Module-Name=\u30D5\u30A1\u30A4\u30EB\u30BF\u30A4\u30D7\u306E\u7279\u5B9A -FileTypeIdModuleSettingsPanel.skipKnownCheckBox.toolTipText=\u65E2\u77E5\u306E\u30CF\u30C3\u30B7\u30E5\u5024\u3092\u6301\u3064\u30D5\u30A1\u30A4\u30EB\u6570\u306B\u3088\u3063\u3066\u306F\u3001\u3053\u306E\u30DC\u30C3\u30AF\u30B9\u3092\u9078\u629E\u3059\u308B\u306E\u306B\u3088\u308A\u3001\u30D5\u30A1\u30A4\u30EB\u30BF\u30A4\u30D7\u306E\u7279\u5B9A\u3092\u52A0\u901F\u3057\u307E\u3059\u3002 -FileTypeIdIngestModule.moduleName.text=\u30D5\u30A1\u30A4\u30EB\u30BF\u30A4\u30D7\u306E\u7279\u5B9A -FileTypeIdIngestModule.moduleDesc.text=\u30D0\u30A4\u30CA\u30EA\u7F72\u540D\u306B\u57FA\u3065\u3044\u3066\u30D5\u30A1\u30A4\u30EB\u30BF\u30A4\u30D7\u3092\u4E00\u81F4\u3059\u308B\u3002 -FileTypeIdIngestModule.complete.totalProcTime=\u5408\u8A08\u51E6\u7406\u6642\u9593 -FileTypeIdIngestModule.complete.totalFiles=\u5408\u8A08\u51E6\u7406\u30D5\u30A1\u30A4\u30EB\u6570 -FileTypeIdIngestModule.complete.srvMsg.text=\u30D5\u30A1\u30A4\u30EB\u30BF\u30A4\u30D7\u7279\u5B9A\u306E\u7D50\u679C -FileTypeIdModuleSettingsPanel.skipKnownCheckBox.text=\u65E2\u77E5\u30D5\u30A1\u30A4\u30EB\uFF08NSRL\uFF09\u3092\u30B9\u30AD\u30C3\u30D7 -FileTypeIdModuleFactory.getIngestJobSettingsPanel.exception.msg=\u8A2D\u5B9A\u3092\u884C\u3046\u70BA\u306E\u60F3\u5B9A\u3055\u308C\u308B\u5F15\u6570\u306Finstanceof FileTypeIdModuleSettings\u3067\u3059\u3002 -FileTypeIdModuleFactory.createFileIngestModule.exception.msg=\u8A2D\u5B9A\u3092\u884C\u3046\u70BA\u306E\u60F3\u5B9A\u3055\u308C\u308B\u5F15\u6570\u306Finstanceof FileTypeIdModuleSettings\u3067\u3059\u3002 \ No newline at end of file +OpenIDE-Module-Name=\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7\u306e\u7279\u5b9a +FileTypeIdIngestModule.moduleName.text=\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7\u306e\u7279\u5b9a +FileTypeIdIngestModule.moduleDesc.text=\u30d0\u30a4\u30ca\u30ea\u7f72\u540d\u306b\u57fa\u3065\u3044\u3066\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7\u3092\u4e00\u81f4\u3059\u308b\u3002 +FileTypeIdIngestModule.complete.totalProcTime=\u5408\u8a08\u51e6\u7406\u6642\u9593 +FileTypeIdIngestModule.complete.totalFiles=\u5408\u8a08\u51e6\u7406\u30d5\u30a1\u30a4\u30eb\u6570 +FileTypeIdIngestModule.complete.srvMsg.text=\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7\u7279\u5b9a\u306e\u7d50\u679c +FileTypeIdModuleFactory.getIngestJobSettingsPanel.exception.msg=\u8a2d\u5b9a\u3092\u884c\u3046\u70ba\u306e\u60f3\u5b9a\u3055\u308c\u308b\u5f15\u6570\u306finstanceof FileTypeIdModuleSettings\u3067\u3059\u3002 +FileTypeIdModuleFactory.createFileIngestModule.exception.msg=\u8a2d\u5b9a\u3092\u884c\u3046\u70ba\u306e\u60f3\u5b9a\u3055\u308c\u308b\u5f15\u6570\u306finstanceof FileTypeIdModuleSettings\u3067\u3059\u3002 +FileTypeIdIngestJobSettingsPanel.skipKnownCheckBox.toolTipText=\u65e2\u77e5\u306e\u30cf\u30c3\u30b7\u30e5\u5024\u3092\u6301\u3064\u30d5\u30a1\u30a4\u30eb\u6570\u306b\u3088\u3063\u3066\u306f\u3001\u3053\u306e\u30dc\u30c3\u30af\u30b9\u3092\u9078\u629e\u3059\u308b\u306e\u306b\u3088\u308a\u3001\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7\u306e\u7279\u5b9a\u3092\u52a0\u901f\u3057\u307e\u3059\u3002 +FileTypeIdIngestJobSettingsPanel.skipKnownCheckBox.text=\u65e2\u77e5\u30d5\u30a1\u30a4\u30eb\uff08NSRL\uff09\u3092\u30b9\u30ad\u30c3\u30d7 diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form similarity index 87% rename from Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form rename to Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form index d8ad98b738..fd6d2250d3 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form @@ -178,70 +178,70 @@ - + - + - + - + - + - + - + - + - + - + @@ -259,7 +259,7 @@ - + @@ -280,7 +280,7 @@ - + @@ -290,7 +290,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java similarity index 90% rename from Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java rename to Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java index 595a32397e..e9b0060653 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -30,7 +30,7 @@ import org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.User /** * A panel to allow a user to make custom file type definitions. */ -final class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { +final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { private final HashMap fileTypes = new HashMap<>(); private final HashMap changedFileTypes = new HashMap<>(); @@ -39,7 +39,7 @@ final class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel impl /** * Creates a panel to allow a user to make custom file type definitions. */ - FileTypeIdSettingsPanel() { + FileTypeIdGlobalSettingsPanel() { initComponents(); } @@ -139,40 +139,40 @@ final class FileTypeIdSettingsPanel extends IngestModuleGlobalSettingsPanel impl jSeparator1.setOrientation(javax.swing.SwingConstants.VERTICAL); - org.openide.awt.Mnemonics.setLocalizedText(mimeTypeLabel, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.mimeTypeLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(mimeTypeLabel, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.mimeTypeLabel.text")); // NOI18N - mimeTypeTextField.setText(org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.mimeTypeTextField.text")); // NOI18N + mimeTypeTextField.setText(org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.mimeTypeTextField.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(signatureTypeLabel, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.signatureTypeLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(signatureTypeLabel, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.signatureTypeLabel.text")); // NOI18N - signatureTextField.setText(org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.signatureTextField.text")); // NOI18N + signatureTextField.setText(org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.signatureTextField.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(offsetLabel, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.offsetLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(offsetLabel, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.offsetLabel.text")); // NOI18N - offsetTextField.setText(org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.offsetTextField.text")); // NOI18N + offsetTextField.setText(org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.offsetTextField.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(newTypeButton, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.newTypeButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(newTypeButton, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.newTypeButton.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(deleteTypeButton, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.deleteTypeButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(deleteTypeButton, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.deleteTypeButton.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(saveTypeButton, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.saveTypeButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(saveTypeButton, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.saveTypeButton.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(hexPrefixLabel, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.hexPrefixLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hexPrefixLabel, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.hexPrefixLabel.text")); // NOI18N signatureTypeComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Bytes (Hex)", "String", " " })); - org.openide.awt.Mnemonics.setLocalizedText(signatureLabel, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.signatureLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(signatureLabel, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.signatureLabel.text")); // NOI18N jTextArea1.setEditable(false); jTextArea1.setColumns(20); jTextArea1.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N jTextArea1.setLineWrap(true); jTextArea1.setRows(5); - jTextArea1.setText(org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.jTextArea1.text")); // NOI18N + jTextArea1.setText(org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.jTextArea1.text")); // NOI18N jTextArea1.setWrapStyleWord(true); jScrollPane2.setViewportView(jTextArea1); - org.openide.awt.Mnemonics.setLocalizedText(postHitCheckBox, org.openide.util.NbBundle.getMessage(FileTypeIdSettingsPanel.class, "FileTypeIdSettingsPanel.postHitCheckBox.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(postHitCheckBox, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.postHitCheckBox.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.form similarity index 87% rename from Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettingsPanel.form rename to Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.form index 60dfbc7cd3..7a24e05f05 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.form @@ -38,10 +38,10 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.java similarity index 89% rename from Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettingsPanel.java rename to Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.java index bf86217a50..f31380379d 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.java @@ -25,13 +25,13 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; * UI component used to set ingest job options for file type identifier ingest * modules. */ -final class FileTypeIdModuleSettingsPanel extends IngestModuleIngestJobSettingsPanel { +final class FileTypeIdIngestJobSettingsPanel extends IngestModuleIngestJobSettingsPanel { private final FileTypeIdModuleSettings settings; // NOTE: This was declared public, but was inaccessible because the class is // not public - FileTypeIdModuleSettingsPanel(FileTypeIdModuleSettings settings) { + FileTypeIdIngestJobSettingsPanel(FileTypeIdModuleSettings settings) { this.settings = settings; initComponents(); customizeComponents(); @@ -61,8 +61,8 @@ final class FileTypeIdModuleSettingsPanel extends IngestModuleIngestJobSettingsP skipKnownCheckBox = new javax.swing.JCheckBox(); skipKnownCheckBox.setSelected(true); - skipKnownCheckBox.setText(org.openide.util.NbBundle.getMessage(FileTypeIdModuleSettingsPanel.class, "FileTypeIdModuleSettingsPanel.skipKnownCheckBox.text")); // NOI18N - skipKnownCheckBox.setToolTipText(org.openide.util.NbBundle.getMessage(FileTypeIdModuleSettingsPanel.class, "FileTypeIdModuleSettingsPanel.skipKnownCheckBox.toolTipText")); // NOI18N + skipKnownCheckBox.setText(org.openide.util.NbBundle.getMessage(FileTypeIdIngestJobSettingsPanel.class, "FileTypeIdIngestJobSettingsPanel.skipKnownCheckBox.text")); // NOI18N + skipKnownCheckBox.setToolTipText(org.openide.util.NbBundle.getMessage(FileTypeIdIngestJobSettingsPanel.class, "FileTypeIdIngestJobSettingsPanel.skipKnownCheckBox.toolTipText")); // NOI18N skipKnownCheckBox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { skipKnownCheckBoxActionPerformed(evt); diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java index 73d1e140e5..dbd54351cc 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java @@ -82,7 +82,7 @@ public class FileTypeIdModuleFactory extends IngestModuleFactoryAdapter { */ @Override public IngestModuleGlobalSettingsPanel getGlobalSettingsPanel() { - return new FileTypeIdSettingsPanel(); + return new FileTypeIdGlobalSettingsPanel(); } /** @@ -111,7 +111,7 @@ public class FileTypeIdModuleFactory extends IngestModuleFactoryAdapter { throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), "FileTypeIdModuleFactory.getIngestJobSettingsPanel.exception.msg")); } - return new FileTypeIdModuleSettingsPanel((FileTypeIdModuleSettings) settings); + return new FileTypeIdIngestJobSettingsPanel((FileTypeIdModuleSettings) settings); } /** diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java index 44c7730c1a..45d24b9db4 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java @@ -22,7 +22,7 @@ import org.openide.util.Lookup; @org.openide.util.NbBundle.Messages({"OptionsCategory_Name_FileTypeId=FileTypeId", "OptionsCategory_Keywords_FileTypeId=FileTypeId"}) public final class FileTypeIdOptionsPanelController extends OptionsPanelController { - private FileTypeIdSettingsPanel panel; + private FileTypeIdGlobalSettingsPanel panel; private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); private boolean changed; @@ -77,9 +77,9 @@ public final class FileTypeIdOptionsPanelController extends OptionsPanelControll pcs.removePropertyChangeListener(l); } - private FileTypeIdSettingsPanel getPanel() { + private FileTypeIdGlobalSettingsPanel getPanel() { if (panel == null) { - panel = new FileTypeIdSettingsPanel(); + panel = new FileTypeIdGlobalSettingsPanel(); } return panel; } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java index ee0f601bf2..c3f177a4c9 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java @@ -25,6 +25,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -47,21 +48,35 @@ import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; final class UserDefinedFileTypesManager { private static final Logger logger = Logger.getLogger(UserDefinedFileTypesManager.class.getName()); - private static final String FILE_TYPE_DEFINITIONS_SCHEMA_FILE = "FileTypeDefinitions.xsd"; // NON-NLS - private static final String USER_DEFINED_TYPE_DEFINITIONS_FILE = "UserFileTypeDefinitions.xml"; // NON-NLS - private static final String FILE_TYPES_TAG_NAME = "filetypes"; // NON-NLS - private static final String FILE_TYPE_TAG_NAME = "filetype"; // NON-NLS - private static final String ALERT_ATTRIBUTE = "alert"; // NON-NLS - private static final String TYPE_NAME_TAG_NAME = "typename"; // NON-NLS - private static final String SIGNATURE_TAG_NAME = "signature"; // NON-NLS - private static final String SIGNATURE_TYPE_ATTRIBUTE = "type"; // NON-NLS - private static final String BYTES_TAG_NAME = "bytes"; // NON-NLS - private static final String OFFSET_TAG_NAME = "offset"; // NON-NLS - private static final String ENCODING = "UTF-8"; //NON-NLS + private static final String FILE_TYPE_DEFINITIONS_SCHEMA_FILE = "FileTypeDefinitions.xsd"; //NON-NLS + private static final String USER_DEFINED_TYPE_DEFINITIONS_FILE = "UserFileTypeDefinitions.xml"; //NON-NLS + private static final String FILE_TYPES_TAG_NAME = "filetypes"; //NON-NLS + private static final String FILE_TYPE_TAG_NAME = "filetype"; //NON-NLS + private static final String ALERT_ATTRIBUTE = "alert"; //NON-NLS + private static final String TYPE_NAME_TAG_NAME = "typename"; //NON-NLS + private static final String SIGNATURE_TAG_NAME = "signature"; //NON-NLS + private static final String SIGNATURE_TYPE_ATTRIBUTE = "type"; //NON-NLS + private static final String BYTES_TAG_NAME = "bytes"; //NON-NLS + private static final String OFFSET_TAG_NAME = "offset"; //NON-NLS + private static final String ENCODING_FOR_XML_FILE = "UTF-8"; //NON-NLS private static final String ASCII_ENCODING = "US-ASCII"; //NON-NLS private static UserDefinedFileTypesManager instance; - private final Map predefinedFileTypes = new HashMap<>(); + + /** + * User-defined file types to be persisted to the user-defined file type + * definitions file are stored in this mapping of file type names to file + * types. Access to this map is guarded by the intrinsic lock of the + * user-defined file types manager for thread-safety. + */ private final Map userDefinedFileTypes = new HashMap<>(); + + /** + * The combined set of user-defined file types and file types predefined by + * Autopsy are stored in this mapping of file type names to file types. This + * is the current working set of file types. Access to this map is guarded + * by the intrinsic lock of the user-defined file types manager for + * thread-safety. + */ private final Map fileTypes = new HashMap<>(); /** @@ -70,10 +85,10 @@ final class UserDefinedFileTypesManager { * @return A singleton user-defined file types manager. */ synchronized static UserDefinedFileTypesManager getInstance() { - if (instance == null) { - instance = new UserDefinedFileTypesManager(); + if (UserDefinedFileTypesManager.instance == null) { + UserDefinedFileTypesManager.instance = new UserDefinedFileTypesManager(); } - return instance; + return UserDefinedFileTypesManager.instance; } /** @@ -90,7 +105,7 @@ final class UserDefinedFileTypesManager { * names to predefined file types. */ private void loadPredefinedFileTypes() { - // RJCTODO: Remove + // RJCTODO: Remove test type /** * Create a file type that should match $MBR in Small2 image. */ @@ -99,11 +114,11 @@ final class UserDefinedFileTypesManager { /** * Create a file type that should match test.txt in the Small2 image. */ - // RJCTODO: Remove + // RJCTODO: Remove test type try { - this.fileTypes.put("predefinedASCII", new FileType("predefinedASCII", new Signature("hello".getBytes(ASCII_ENCODING), 0L, FileType.Signature.Type.ASCII), true)); + this.fileTypes.put("predefinedASCII", new FileType("predefinedASCII", new Signature("hello".getBytes(UserDefinedFileTypesManager.ASCII_ENCODING), 0L, FileType.Signature.Type.ASCII), true)); } catch (UnsupportedEncodingException ex) { - logger.log(Level.SEVERE, "Unable to create 'predefinedASCII' predefined file type definition", ex); //NON-NLS + UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Unable to create 'predefinedASCII' predefined file type definition", ex); //NON-NLS } try { @@ -129,9 +144,13 @@ final class UserDefinedFileTypesManager { // catch (IndexOutOfBoundsException e) { // // do nothing // } - this.predefinedFileTypes.put("text/xml", new FileType("text/xml", new Signature(" newFileTypes = new ArrayList<>(); - newFileTypes.add(fileType); - addFileTypes(newFileTypes); + this.addFileTypes(Collections.singletonList(fileType)); } /** - * Adds a set of new file types, overwriting any file types with the same - * type names that already exist. + * Adds a collection of new user-defined file types, overwriting any + * existing file types with the same type names. * * @param newFileTypes The file types to add. * @throws * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException */ synchronized void addFileTypes(Collection newFileTypes) throws UserDefinedFileTypesException { + /** + * It is safe to hold references to client-constructed file type objects + * because they are immutable. + */ for (FileType fileType : newFileTypes) { - userDefinedFileTypes.put(fileType.getTypeName(), fileType); - fileTypes.put(fileType.getTypeName(), fileType); + this.userDefinedFileTypes.put(fileType.getTypeName(), fileType); + this.fileTypes.put(fileType.getTypeName(), fileType); } - saveUserDefinedTypes(); + this.saveUserDefinedTypes(); } /** - * Deletes a file type. + * Deletes a user-defined file type. * * @param fileType The file type to delete. * @throws * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException */ synchronized void deleteFileType(FileType fileType) throws UserDefinedFileTypesException { - List deletedFileTypes = new ArrayList<>(); - deletedFileTypes.add(fileType); - deleteFileTypes(deletedFileTypes); + this.deleteFileTypes(Collections.singletonList(fileType)); } /** - * Deletes a set of file types. + * Deletes a set of user-defined file types. * * @param deletedFileTypes The file types to delete. * @throws @@ -227,21 +244,21 @@ final class UserDefinedFileTypesManager { */ synchronized void deleteFileTypes(Collection deletedFileTypes) throws UserDefinedFileTypesException { for (FileType fileType : deletedFileTypes) { - userDefinedFileTypes.remove(fileType.getTypeName(), fileType); - fileTypes.remove(fileType.getTypeName(), fileType); + this.userDefinedFileTypes.remove(fileType.getTypeName(), fileType); + this.fileTypes.remove(fileType.getTypeName(), fileType); } - saveUserDefinedTypes(); + this.saveUserDefinedTypes(); } /** - * Persist the user-defined file type definitions. + * Persists the user-defined file type definitions. * * @throws * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException */ private void saveUserDefinedTypes() throws UserDefinedFileTypesException { - String filePath = getFileTypeDefinitionsFilePath(USER_DEFINED_TYPE_DEFINITIONS_FILE); - writeFileTypes(userDefinedFileTypes.values(), filePath); + String filePath = UserDefinedFileTypesManager.getFileTypeDefinitionsFilePath(UserDefinedFileTypesManager.USER_DEFINED_TYPE_DEFINITIONS_FILE); + UserDefinedFileTypesManager.writeFileTypes(this.userDefinedFileTypes.values(), filePath); } /** @@ -253,10 +270,10 @@ final class UserDefinedFileTypesManager { */ private static void writeFileTypes(Collection fileTypes, String filePath) throws UserDefinedFileTypesException { try { - XMLWriter.writeFileTypes(fileTypes, filePath); + UserDefinedFileTypesManager.XMLWriter.writeFileTypes(fileTypes, filePath); } catch (ParserConfigurationException | IOException ex) { UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Failed to write file types file", ex); - throw new UserDefinedFileTypesException(ex.getLocalizedMessage()); // RJCTODO: Create a bundled message + throw new UserDefinedFileTypesManager.UserDefinedFileTypesException(ex.getLocalizedMessage()); // RJCTODO: Create a bundled message } } @@ -291,9 +308,9 @@ final class UserDefinedFileTypesManager { Element fileTypeElem = UserDefinedFileTypesManager.XMLWriter.createFileTypeElement(fileType, doc); fileTypesElem.appendChild(fileTypeElem); } - if (!XMLUtil.saveDoc(HashDbManager.class, filePath, UserDefinedFileTypesManager.ENCODING, doc)) { + if (!XMLUtil.saveDoc(HashDbManager.class, filePath, UserDefinedFileTypesManager.ENCODING_FOR_XML_FILE, doc)) { // RJCTODO: If time permits add XMLUtil that properly throws and deprecate this one - throw new IOException("Error saving user defined file types, see log for details"); // NON-NLS + throw new IOException("Error saving user defined file types, see log for details"); //NON-NLS } } @@ -451,17 +468,18 @@ final class UserDefinedFileTypesManager { if (!textContent.isEmpty()) { return textContent; } else { - throw new InvalidXMLException("File type " + tagName + " child element missing text content"); // NON-NLS + throw new InvalidXMLException("File type " + tagName + " child element missing text content"); //NON-NLS } } else { - throw new InvalidXMLException("File type element missing " + tagName + " child element"); // NON-NLS + throw new InvalidXMLException("File type element missing " + tagName + " child element"); //NON-NLS } } /** - * RJCTODO + * Used for exceptions when parsing user-defined types XML elements and + * attributes. */ - static class InvalidXMLException extends Exception { + private static class InvalidXMLException extends Exception { InvalidXMLException(String message) { super(message); From a9bc43e320bdf80eb2def997da4f0b7fd1e0dd2f Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 5 Dec 2014 00:45:01 -0500 Subject: [PATCH 10/27] Work on user-defined file types UI --- .../modules/filetypeid/Bundle.properties | 2 +- .../FileTypeIdGlobalSettingsPanel.form | 52 ++--- .../FileTypeIdGlobalSettingsPanel.java | 179 +++++++++++++----- .../UserDefinedFileTypeIdentifier.java | 11 +- .../UserDefinedFileTypesManager.java | 152 +++++++-------- 5 files changed, 241 insertions(+), 155 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties index 4481e95ab3..2d18364283 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties @@ -9,7 +9,6 @@ FileTypeIdModuleFactory.createFileIngestModule.exception.msg=Expected settings a FileTypeIdIngestJobSettingsPanel.skipKnownCheckBox.toolTipText=Depending on how many files have known hashes, checking this box will improve the speed of file type identification. FileTypeIdIngestJobSettingsPanel.skipKnownCheckBox.text=Skip known files (NSRL) FileTypeIdGlobalSettingsPanel.hexPrefixLabel.text=0x -FileTypeIdGlobalSettingsPanel.saveTypeButton.text=Save Type FileTypeIdGlobalSettingsPanel.deleteTypeButton.text=DeleteType FileTypeIdGlobalSettingsPanel.newTypeButton.text=New Type FileTypeIdGlobalSettingsPanel.offsetTextField.text= @@ -21,3 +20,4 @@ FileTypeIdGlobalSettingsPanel.signatureTypeLabel.text=Signature Type FileTypeIdGlobalSettingsPanel.mimeTypeTextField.text= FileTypeIdGlobalSettingsPanel.signatureLabel.text=Signature FileTypeIdGlobalSettingsPanel.mimeTypeLabel.text=Mime Type +FileTypeIdGlobalSettingsPanel.saveTypeButton.text=Save Type diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form index fd6d2250d3..49ae296a57 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form @@ -35,7 +35,6 @@ - @@ -43,18 +42,17 @@ - - + + - - + @@ -78,22 +76,17 @@ - - - - - - - - - - - + + + + + + - + @@ -141,14 +134,14 @@ - + - + @@ -167,6 +160,9 @@ + + + @@ -223,6 +219,9 @@ + + + @@ -230,6 +229,9 @@ + + + @@ -237,6 +239,9 @@ + + + @@ -248,13 +253,12 @@ - - - - - + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java index e9b0060653..aaafa786eb 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -18,23 +18,30 @@ */ package org.sleuthkit.autopsy.modules.filetypeid; -import java.util.HashMap; +import java.util.Map; +import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultListModel; +import javax.swing.JOptionPane; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; import org.sleuthkit.autopsy.modules.filetypeid.FileType.Signature; -import org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException; /** * A panel to allow a user to make custom file type definitions. */ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { - private final HashMap fileTypes = new HashMap<>(); - private final HashMap changedFileTypes = new HashMap<>(); - private final HashMap deletedFileTypes = new HashMap<>(); + private static final String RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM = "Bytes (Hex)"; // RJCTODO: Bundle + private static final String ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM = "String (ASCII)"; // RJCTODO: Bundle + + /** + * This mapping of file type names to file types is used to hold the types + * displayed in the file types list component. + */ + private Map fileTypes; /** * Creates a panel to allow a user to make custom file type definitions. @@ -56,19 +63,38 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane */ @Override public void load() { - fileTypes.clear(); + /** + * Get the user-defined file types and set up a list model for the file + * types list component. + */ + this.fileTypes = UserDefinedFileTypesManager.getInstance().getUserDefinedFileTypes(); DefaultListModel fileTypesListModel = new DefaultListModel<>(); - for (FileType fileType : UserDefinedFileTypesManager.getInstance().getFileTypes()) { - fileTypes.put(fileType.getTypeName(), fileType); + for (FileType fileType : this.fileTypes.values()) { fileTypesListModel.addElement(fileType.getTypeName()); } - typesList.setModel(fileTypesListModel); + this.typesList.setModel(fileTypesListModel); - typesList.addListSelectionListener(new TypesListSelectionListener()); + /** + * Add a selection listener to populate the file type details + * display/edit components. + */ + this.typesList.addListSelectionListener(new TypesListSelectionListener()); + /** + * If there is at least one user-defined file type, select it the file + * types list component. + */ if (!fileTypesListModel.isEmpty()) { - typesList.setSelectedIndex(0); + this.typesList.setSelectedIndex(0); } + + /** + * Make a model for the signature type combo box component. + */ + DefaultComboBoxModel sigTypeComboBoxModel = new DefaultComboBoxModel<>(); + sigTypeComboBoxModel.addElement(FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM); + sigTypeComboBoxModel.addElement(FileTypeIdGlobalSettingsPanel.ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM); + this.signatureTypeComboBox.setModel(sigTypeComboBoxModel); } /** @@ -77,10 +103,8 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane @Override public void store() { try { - UserDefinedFileTypesManager fileTypesManager = UserDefinedFileTypesManager.getInstance(); - fileTypesManager.addFileTypes(changedFileTypes.values()); - fileTypesManager.deleteFileTypes(deletedFileTypes.values()); - } catch (UserDefinedFileTypesException ex) { + UserDefinedFileTypesManager.getInstance().setUserDefinedFileTypes(this.fileTypes); + } catch (UserDefinedFileTypesManager.UserDefinedFileTypesException ex) { // RJCTODO } } @@ -90,22 +114,36 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane @Override public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting() == false) { - if (typesList.getSelectedIndex() == -1) { - deleteTypeButton.setEnabled(false); - + if (FileTypeIdGlobalSettingsPanel.this.typesList.getSelectedIndex() == -1) { + FileTypeIdGlobalSettingsPanel.this.deleteTypeButton.setEnabled(false); } else { - String typeName = (String) typesList.getSelectedValue(); - FileType fileType = fileTypes.get(typeName); + String typeName = FileTypeIdGlobalSettingsPanel.this.typesList.getSelectedValue(); + FileType fileType = FileTypeIdGlobalSettingsPanel.this.fileTypes.get(typeName); Signature signature = fileType.getSignature(); - mimeTypeTextField.setText(typeName); - offsetTextField.setText(Long.toString(signature.getOffset())); - deleteTypeButton.setEnabled(true); + FileTypeIdGlobalSettingsPanel.this.mimeTypeTextField.setText(typeName); + FileType.Signature.Type sigType = fileType.getSignature().getType(); + FileTypeIdGlobalSettingsPanel.this.signatureTypeComboBox.setSelectedItem(sigType == FileType.Signature.Type.RAW ? FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM : FileTypeIdGlobalSettingsPanel.ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM); + FileTypeIdGlobalSettingsPanel.this.offsetTextField.setText(Long.toString(signature.getOffset())); + FileTypeIdGlobalSettingsPanel.this.postHitCheckBox.setSelected(fileType.alertOnMatch()); + FileTypeIdGlobalSettingsPanel.this.deleteTypeButton.setEnabled(true); } } } } - // RJCTODO: Consider fixing OptinsPanel interface or writing story + /** + * RJCTODO + */ + private void clearTypeDetailsComponents() { + this.typesList.setSelectedIndex(-1); + this.mimeTypeTextField.setText(""); //NON-NLS // RJCTODO: Default name? + this.signatureTypeComboBox.setSelectedItem(FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM); + this.signatureTextField.setText(""); //NON-NLS + this.offsetTextField.setText(""); //NON-NLS + this.postHitCheckBox.setSelected(false); + } + + // RJCTODO: Consider fixing OptionsPanel interface or writing story /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -117,7 +155,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane buttonGroup1 = new javax.swing.ButtonGroup(); typesScrollPane = new javax.swing.JScrollPane(); - typesList = new javax.swing.JList(); + typesList = new javax.swing.JList(); jSeparator1 = new javax.swing.JSeparator(); mimeTypeLabel = new javax.swing.JLabel(); mimeTypeTextField = new javax.swing.JTextField(); @@ -129,7 +167,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane deleteTypeButton = new javax.swing.JButton(); saveTypeButton = new javax.swing.JButton(); hexPrefixLabel = new javax.swing.JLabel(); - signatureTypeComboBox = new javax.swing.JComboBox(); + signatureTypeComboBox = new javax.swing.JComboBox(); signatureLabel = new javax.swing.JLabel(); jScrollPane2 = new javax.swing.JScrollPane(); jTextArea1 = new javax.swing.JTextArea(); @@ -152,15 +190,28 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane offsetTextField.setText(org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.offsetTextField.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(newTypeButton, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.newTypeButton.text")); // NOI18N + newTypeButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + newTypeButtonActionPerformed(evt); + } + }); org.openide.awt.Mnemonics.setLocalizedText(deleteTypeButton, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.deleteTypeButton.text")); // NOI18N + deleteTypeButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + deleteTypeButtonActionPerformed(evt); + } + }); org.openide.awt.Mnemonics.setLocalizedText(saveTypeButton, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.saveTypeButton.text")); // NOI18N + saveTypeButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + saveTypeButtonActionPerformed(evt); + } + }); org.openide.awt.Mnemonics.setLocalizedText(hexPrefixLabel, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.hexPrefixLabel.text")); // NOI18N - signatureTypeComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Bytes (Hex)", "String", " " })); - org.openide.awt.Mnemonics.setLocalizedText(signatureLabel, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.signatureLabel.text")); // NOI18N jTextArea1.setEditable(false); @@ -190,25 +241,23 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(37, 37, 37) - .addComponent(saveTypeButton) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(saveTypeButton)) .addGroup(layout.createSequentialGroup() .addGap(18, 18, 18) .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 13, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() .addComponent(signatureTypeLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(signatureTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 82, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE)) + .addComponent(signatureTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 82, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(signatureLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(hexPrefixLabel) .addGap(2, 2, 2)) .addGroup(layout.createSequentialGroup() @@ -224,15 +273,12 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(mimeTypeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 181, javax.swing.GroupLayout.PREFERRED_SIZE)))) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(6, 6, 6) - .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 260, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(postHitCheckBox))) - .addGap(0, 0, Short.MAX_VALUE))) - .addContainerGap()))) + .addGap(6, 6, 6) + .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 260, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(postHitCheckBox))))) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -270,13 +316,50 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane .addComponent(newTypeButton) .addComponent(deleteTypeButton))) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(saveTypeButton)))) .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 260, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) ); }// //GEN-END:initComponents + private void newTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTypeButtonActionPerformed + this.clearTypeDetailsComponents(); + // RJCTODO: Default name? + }//GEN-LAST:event_newTypeButtonActionPerformed + + private void deleteTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTypeButtonActionPerformed + String typeName = this.typesList.getSelectedValue(); + this.fileTypes.remove(typeName); + this.clearTypeDetailsComponents(); + this.typesList.setSelectedIndex(-1); + }//GEN-LAST:event_deleteTypeButtonActionPerformed + + private void saveTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveTypeButtonActionPerformed + try { + String typeName = this.mimeTypeTextField.getText(); + if (typeName.isEmpty()) { + JOptionPane.showMessageDialog(null, "MIME type name cannot be empty.", "Missing MIME Type", JOptionPane.ERROR_MESSAGE); // RJCTODO: Bundle + return; + } + + String sigString = this.signatureTextField.getText(); + if (sigString.isEmpty()) { + JOptionPane.showMessageDialog(null, "Signature cannot be empty.", "Missing Signature", JOptionPane.ERROR_MESSAGE); // RJCTODO: Bundle + return; + } + + long offset = Long.parseUnsignedLong(this.offsetTextField.getText()); + + FileType.Signature.Type sigType = this.signatureTypeComboBox.getSelectedItem() == FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM ? FileType.Signature.Type.RAW : FileType.Signature.Type.ASCII; + FileType.Signature signature = new FileType.Signature(new byte[1], offset, sigType); // RJCTODO: + FileType fileType = new FileType(typeName, signature, this.postHitCheckBox.isSelected()); + this.fileTypes.put(typeName, fileType); + } catch (NumberFormatException ex) { + JOptionPane.showMessageDialog(null, "Offset is not a positive integer.", "Invalid Offset", JOptionPane.ERROR_MESSAGE); // RJCTODO: Bundle + } + }//GEN-LAST:event_saveTypeButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup buttonGroup1; @@ -294,9 +377,9 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane private javax.swing.JButton saveTypeButton; private javax.swing.JLabel signatureLabel; private javax.swing.JTextField signatureTextField; - private javax.swing.JComboBox signatureTypeComboBox; + private javax.swing.JComboBox signatureTypeComboBox; private javax.swing.JLabel signatureTypeLabel; - private javax.swing.JList typesList; + private javax.swing.JList typesList; private javax.swing.JScrollPane typesScrollPane; // End of variables declaration//GEN-END:variables diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java index f7dac840ca..c93cc9a547 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java @@ -18,8 +18,7 @@ */ package org.sleuthkit.autopsy.modules.filetypeid; -import java.util.ArrayList; -import java.util.List; +import java.util.Map; import org.sleuthkit.datamodel.AbstractFile; /** @@ -27,16 +26,14 @@ import org.sleuthkit.datamodel.AbstractFile; */ final class UserDefinedFileTypeIdentifier { - private final List fileTypes; + private final Map fileTypes; /** * Creates an object that can do file type identification for user-defined * file types. */ UserDefinedFileTypeIdentifier() { - this.fileTypes = new ArrayList<>(); - List fileTypeDefs = UserDefinedFileTypesManager.getInstance().getFileTypes(); - this.fileTypes.addAll(fileTypeDefs); + this.fileTypes = UserDefinedFileTypesManager.getInstance().getFileTypes(); } /** @@ -48,7 +45,7 @@ final class UserDefinedFileTypeIdentifier { */ FileType identify(final AbstractFile file) { FileType type = null; - for (FileType fileType : this.fileTypes) { + for (FileType fileType : this.fileTypes.values()) { if (fileType.matches(file)) { type = fileType; break; diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java index c3f177a4c9..1266d3560f 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java @@ -62,6 +62,13 @@ final class UserDefinedFileTypesManager { private static final String ASCII_ENCODING = "US-ASCII"; //NON-NLS private static UserDefinedFileTypesManager instance; + /** + * Predefined file types are stored in this mapping of file type names to + * file types. Access to this map is guarded by the intrinsic lock of the + * user-defined file types manager for thread-safety. + */ + private final Map predefinedFileTypes = new HashMap<>(); + /** * User-defined file types to be persisted to the user-defined file type * definitions file are stored in this mapping of file type names to file @@ -96,6 +103,10 @@ final class UserDefinedFileTypesManager { * (e.g., MIME type) and signatures. */ private UserDefinedFileTypesManager() { + /** + * Load the predefined types first so that they can be overwritten by + * any user-defined types with the same names. + */ loadPredefinedFileTypes(); loadUserDefinedFileTypes(); } @@ -109,14 +120,16 @@ final class UserDefinedFileTypesManager { /** * Create a file type that should match $MBR in Small2 image. */ - this.fileTypes.put("predefinedRAW", new FileType("predefinedRAW", new Signature(new byte[]{(byte) 0x66, (byte) 0x73, (byte) 0x00}, 8L, FileType.Signature.Type.RAW), true)); + FileType fileType = new FileType("predefinedRAW", new Signature(new byte[]{(byte) 0x66, (byte) 0x73, (byte) 0x00}, 8L, FileType.Signature.Type.RAW), true); + this.addPredefinedFileType(fileType); /** * Create a file type that should match test.txt in the Small2 image. */ // RJCTODO: Remove test type try { - this.fileTypes.put("predefinedASCII", new FileType("predefinedASCII", new Signature("hello".getBytes(UserDefinedFileTypesManager.ASCII_ENCODING), 0L, FileType.Signature.Type.ASCII), true)); + fileType = new FileType("predefinedASCII", new Signature("hello".getBytes(UserDefinedFileTypesManager.ASCII_ENCODING), 0L, FileType.Signature.Type.ASCII), true); + this.addPredefinedFileType(fileType); } catch (UnsupportedEncodingException ex) { UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Unable to create 'predefinedASCII' predefined file type definition", ex); //NON-NLS } @@ -144,16 +157,28 @@ final class UserDefinedFileTypesManager { // catch (IndexOutOfBoundsException e) { // // do nothing // } - this.fileTypes.put("text/xml", new FileType("text/xml", new Signature(" getFileTypes() { + synchronized Map getFileTypes() { /** * It is safe to return references to the internal file type objects * because they are immutable. */ - return new ArrayList<>(this.fileTypes.values()); + return new HashMap<>(this.fileTypes); } /** - * Adds a new user-defined file type, overwriting any existing file type - * with the same type name. + * Gets the user-defined file types. * - * @param fileType The file type to add. - * @throws - * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException + * @return A mapping of file type names to file types, possibly empty. */ - synchronized void addFileType(FileType fileType) throws UserDefinedFileTypesException { - this.addFileTypes(Collections.singletonList(fileType)); - } - - /** - * Adds a collection of new user-defined file types, overwriting any - * existing file types with the same type names. - * - * @param newFileTypes The file types to add. - * @throws - * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException - */ - synchronized void addFileTypes(Collection newFileTypes) throws UserDefinedFileTypesException { + synchronized Map getUserDefinedFileTypes() { /** - * It is safe to hold references to client-constructed file type objects + * It is safe to return references to the internal file type objects * because they are immutable. */ - for (FileType fileType : newFileTypes) { - this.userDefinedFileTypes.put(fileType.getTypeName(), fileType); - this.fileTypes.put(fileType.getTypeName(), fileType); - } - this.saveUserDefinedTypes(); + return new HashMap<>(this.userDefinedFileTypes); } /** - * Deletes a user-defined file type. + * Sets the user-defined file types. * - * @param fileType The file type to delete. + * @param newFileTypes A mapping of file type names to user-defined + * file types. * @throws * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException */ - synchronized void deleteFileType(FileType fileType) throws UserDefinedFileTypesException { - this.deleteFileTypes(Collections.singletonList(fileType)); - } - - /** - * Deletes a set of user-defined file types. - * - * @param deletedFileTypes The file types to delete. - * @throws - * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException - */ - synchronized void deleteFileTypes(Collection deletedFileTypes) throws UserDefinedFileTypesException { - for (FileType fileType : deletedFileTypes) { - this.userDefinedFileTypes.remove(fileType.getTypeName(), fileType); - this.fileTypes.remove(fileType.getTypeName(), fileType); - } - this.saveUserDefinedTypes(); - } - - /** - * Persists the user-defined file type definitions. - * - * @throws - * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException - */ - private void saveUserDefinedTypes() throws UserDefinedFileTypesException { - String filePath = UserDefinedFileTypesManager.getFileTypeDefinitionsFilePath(UserDefinedFileTypesManager.USER_DEFINED_TYPE_DEFINITIONS_FILE); - UserDefinedFileTypesManager.writeFileTypes(this.userDefinedFileTypes.values(), filePath); - } - - /** - * Writes a set of file type definitions to a given file. - * - * @param fileTypes The file types. - * @param filePath The destination file. - * @throws UserDefinedFileTypesException - */ - private static void writeFileTypes(Collection fileTypes, String filePath) throws UserDefinedFileTypesException { + synchronized void setUserDefinedFileTypes(Map newFileTypes) throws UserDefinedFileTypesManager.UserDefinedFileTypesException { try { - UserDefinedFileTypesManager.XMLWriter.writeFileTypes(fileTypes, filePath); + /** + * Persist the user-defined file type definitions. + */ + String filePath = UserDefinedFileTypesManager.getFileTypeDefinitionsFilePath(UserDefinedFileTypesManager.USER_DEFINED_TYPE_DEFINITIONS_FILE); + UserDefinedFileTypesManager.XMLWriter.writeFileTypes(newFileTypes.values(), filePath); + } catch (ParserConfigurationException | IOException ex) { UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Failed to write file types file", ex); throw new UserDefinedFileTypesManager.UserDefinedFileTypesException(ex.getLocalizedMessage()); // RJCTODO: Create a bundled message } + + /** + * Clear and reinitialize the user-defined file type map. It is safe to + * hold references to file type objects obtained for the caller because + * they are immutable. + */ + this.userDefinedFileTypes.clear(); + this.userDefinedFileTypes.putAll(newFileTypes); + + /** + * Clear and reinitialize the combined file type map, loading the + * predefined types first so that they can be overwritten by any + * user-defined types with the same names. + */ + this.fileTypes.clear(); + this.fileTypes.putAll(this.predefinedFileTypes); + this.fileTypes.putAll(this.userDefinedFileTypes); } /** From 401c725f67bc838c985fc642803c5ed387a7467a Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 5 Dec 2014 14:54:18 -0500 Subject: [PATCH 11/27] Additional work on user defined types --- .../modules/filetypeid/Bundle.properties | 10 ++ .../FileTypeIdGlobalSettingsPanel.form | 6 +- .../FileTypeIdGlobalSettingsPanel.java | 141 ++++++++++++++---- .../FileTypeIdOptionsPanelController.java | 9 +- .../UserDefinedFileTypesManager.java | 1 - 5 files changed, 123 insertions(+), 44 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties index 2d18364283..6a15e196d1 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties @@ -21,3 +21,13 @@ FileTypeIdGlobalSettingsPanel.mimeTypeTextField.text= FileTypeIdGlobalSettingsPanel.signatureLabel.text=Signature FileTypeIdGlobalSettingsPanel.mimeTypeLabel.text=Mime Type FileTypeIdGlobalSettingsPanel.saveTypeButton.text=Save Type +FileTypeIdGlobalSettingsPanel.signatureComboBox.rawItem=Bytes (Hex) +FileTypeIdGlobalSettingsPanel.signatureComboBox.asciiItem=String (ASCII) +FileTypeIdGlobalSettingsPanel.JOptionPane.invalidMIMEType.message=MIME type is required. +FileTypeIdGlobalSettingsPanel.JOptionPane.invalidMIMEType.title=Missing MIME Type +FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignature.message=Signature is required. +FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignature.title=Missing Signature +FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message=Offset must be a positive integer. +FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.title=Invalid Offset +FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignatureBytes.message=The signature must be able to be converted to UTF-8 bytes. +FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignatureBytes.title=Invalid Signature \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form index 49ae296a57..3d5852a878 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form @@ -1,10 +1,6 @@
- - - - @@ -46,7 +42,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java index aaafa786eb..169c69ddc7 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -18,12 +18,17 @@ */ package org.sleuthkit.autopsy.modules.filetypeid; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collections; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultListModel; import javax.swing.JOptionPane; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; +import javax.xml.bind.DatatypeConverter; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; @@ -34,20 +39,54 @@ import org.sleuthkit.autopsy.modules.filetypeid.FileType.Signature; */ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { - private static final String RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM = "Bytes (Hex)"; // RJCTODO: Bundle - private static final String ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM = "String (ASCII)"; // RJCTODO: Bundle + private static final String RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM = NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.signatureComboBox.rawItem"); + private static final String ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM = NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.signatureComboBox.asciiItem"); + + /** + * These two fields are used to synthesize default names for user-defined + * types. This is a thread-safe implementation because there can be two + * instances of this panel at the same time due to the non-modal nature of + * the NetBeans options window and the fact that these panels can also be + * invoked via ingest job configuration panels. All interactions with + * instances of this panel should occur on the EDT, so this is defensive + * programming. + */ + private static final String DEFAULT_TYPE_NAME_BASE = "userdefined/userdefined"; //NON-NLS + private static final AtomicInteger defaultTypeNameCounter = new AtomicInteger(1); /** * This mapping of file type names to file types is used to hold the types - * displayed in the file types list component. + * displayed in the file types list component via its list model. */ private Map fileTypes; + private DefaultListModel typesListModel; /** * Creates a panel to allow a user to make custom file type definitions. */ FileTypeIdGlobalSettingsPanel() { - initComponents(); + this.initComponents(); + this.customizeComponents(); + } + + /** + * Does component initialization in addition to the the Matisse generated + * initialization. + */ + private void customizeComponents() { + /** + * Make a model for the file types list component. + */ + this.typesListModel = new DefaultListModel<>(); + this.typesList.setModel(this.typesListModel); + + /** + * Make a model for the signature type combo box component. + */ + DefaultComboBoxModel sigTypeComboBoxModel = new DefaultComboBoxModel<>(); + sigTypeComboBoxModel.addElement(FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM); + sigTypeComboBoxModel.addElement(FileTypeIdGlobalSettingsPanel.ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM); + this.signatureTypeComboBox.setModel(sigTypeComboBoxModel); } /** @@ -68,11 +107,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane * types list component. */ this.fileTypes = UserDefinedFileTypesManager.getInstance().getUserDefinedFileTypes(); - DefaultListModel fileTypesListModel = new DefaultListModel<>(); - for (FileType fileType : this.fileTypes.values()) { - fileTypesListModel.addElement(fileType.getTypeName()); - } - this.typesList.setModel(fileTypesListModel); + this.setFileTypesListModel(); /** * Add a selection listener to populate the file type details @@ -84,17 +119,9 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane * If there is at least one user-defined file type, select it the file * types list component. */ - if (!fileTypesListModel.isEmpty()) { + if (!this.typesListModel.isEmpty()) { this.typesList.setSelectedIndex(0); } - - /** - * Make a model for the signature type combo box component. - */ - DefaultComboBoxModel sigTypeComboBoxModel = new DefaultComboBoxModel<>(); - sigTypeComboBoxModel.addElement(FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM); - sigTypeComboBoxModel.addElement(FileTypeIdGlobalSettingsPanel.ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM); - this.signatureTypeComboBox.setModel(sigTypeComboBoxModel); } /** @@ -109,6 +136,9 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane } } + /** + * Selection listener for the file types list component. + */ private class TypesListSelectionListener implements ListSelectionListener { @Override @@ -132,18 +162,30 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane } /** - * RJCTODO + * Sets the list model for the file types list component. + */ + private void setFileTypesListModel() { + ArrayList typeNames = new ArrayList(this.fileTypes.keySet()); + Collections.sort(typeNames); + this.typesListModel.clear(); + for (String typeName : typeNames) { + this.typesListModel.addElement(typeName); + } + } + + /** + * Clears all of the components in the individual type details portion of + * the panel. */ private void clearTypeDetailsComponents() { this.typesList.setSelectedIndex(-1); - this.mimeTypeTextField.setText(""); //NON-NLS // RJCTODO: Default name? + this.mimeTypeTextField.setText(""); this.signatureTypeComboBox.setSelectedItem(FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM); this.signatureTextField.setText(""); //NON-NLS this.offsetTextField.setText(""); //NON-NLS this.postHitCheckBox.setSelected(false); } - // RJCTODO: Consider fixing OptionsPanel interface or writing story /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -153,7 +195,6 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane // //GEN-BEGIN:initComponents private void initComponents() { - buttonGroup1 = new javax.swing.ButtonGroup(); typesScrollPane = new javax.swing.JScrollPane(); typesList = new javax.swing.JList(); jSeparator1 = new javax.swing.JSeparator(); @@ -252,7 +293,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() .addComponent(signatureTypeLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(signatureTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 82, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(signatureTypeComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() @@ -325,7 +366,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane private void newTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTypeButtonActionPerformed this.clearTypeDetailsComponents(); - // RJCTODO: Default name? + this.mimeTypeTextField.setText(FileTypeIdGlobalSettingsPanel.DEFAULT_TYPE_NAME_BASE + FileTypeIdGlobalSettingsPanel.defaultTypeNameCounter.getAndIncrement()); }//GEN-LAST:event_newTypeButtonActionPerformed private void deleteTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTypeButtonActionPerformed @@ -337,32 +378,70 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane private void saveTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveTypeButtonActionPerformed try { + /** + * Get the file type name. + */ String typeName = this.mimeTypeTextField.getText(); if (typeName.isEmpty()) { - JOptionPane.showMessageDialog(null, "MIME type name cannot be empty.", "Missing MIME Type", JOptionPane.ERROR_MESSAGE); // RJCTODO: Bundle + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidMIMEType.message"), + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidMIMEType.title"), + JOptionPane.ERROR_MESSAGE); return; } + /** + * Get the signature type. + */ + FileType.Signature.Type sigType = this.signatureTypeComboBox.getSelectedItem() == FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM ? FileType.Signature.Type.RAW : FileType.Signature.Type.ASCII; + + /** + * Get the signature bytes. + */ String sigString = this.signatureTextField.getText(); if (sigString.isEmpty()) { - JOptionPane.showMessageDialog(null, "Signature cannot be empty.", "Missing Signature", JOptionPane.ERROR_MESSAGE); // RJCTODO: Bundle + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignature.message"), + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignature.title"), + JOptionPane.ERROR_MESSAGE); return; } + byte[] signatureBytes; + if (FileType.Signature.Type.RAW == sigType) { + signatureBytes = DatatypeConverter.parseHexBinary(sigString); + } else { + signatureBytes = sigString.getBytes(Charset.forName("UTF-8")); + } + /** + * Get the offset. + */ long offset = Long.parseUnsignedLong(this.offsetTextField.getText()); - - FileType.Signature.Type sigType = this.signatureTypeComboBox.getSelectedItem() == FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM ? FileType.Signature.Type.RAW : FileType.Signature.Type.ASCII; - FileType.Signature signature = new FileType.Signature(new byte[1], offset, sigType); // RJCTODO: + + /** + * Put it all together and reset the file types list component. + */ + FileType.Signature signature = new FileType.Signature(signatureBytes, offset, sigType); // RJCTODO: FileType fileType = new FileType(typeName, signature, this.postHitCheckBox.isSelected()); this.fileTypes.put(typeName, fileType); + this.setFileTypesListModel(); + this.typesList.setSelectedValue(fileType.getTypeName(), true); + } catch (NumberFormatException ex) { - JOptionPane.showMessageDialog(null, "Offset is not a positive integer.", "Invalid Offset", JOptionPane.ERROR_MESSAGE); // RJCTODO: Bundle + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message"), + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.title"), + JOptionPane.ERROR_MESSAGE); + } catch (IllegalArgumentException ex) { + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignatureBytes.message"), + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignatureBytes.title"), + JOptionPane.ERROR_MESSAGE); } }//GEN-LAST:event_saveTypeButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.ButtonGroup buttonGroup1; private javax.swing.JButton deleteTypeButton; private javax.swing.JLabel hexPrefixLabel; private javax.swing.JScrollPane jScrollPane2; diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java index 45d24b9db4..bbf16073de 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java @@ -34,13 +34,8 @@ public final class FileTypeIdOptionsPanelController extends OptionsPanelControll @Override public void applyChanges() { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - getPanel().store(); - changed = false; - } - }); + getPanel().store(); + changed = false; } @Override diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java index 1266d3560f..031a6d46f8 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java @@ -25,7 +25,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; From 6e9c22032bb377041e794803f1618fbf05a6e829 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Sun, 7 Dec 2014 08:46:39 -0500 Subject: [PATCH 12/27] Additions to user-defined types feature --- .../autopsy/modules/filetypeid/FileType.java | 2 +- .../FileTypeIdGlobalSettingsPanel.form | 23 +++------ .../FileTypeIdGlobalSettingsPanel.java | 49 ++++++++++--------- 3 files changed, 33 insertions(+), 41 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java index 98b174b46f..8aa261a84f 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java @@ -110,7 +110,7 @@ final class FileType { * Creates a file signature consisting of a sequence of bytes at a * specific offset within a file. * - * @param signatureBytes The signature bytes + * @param signatureBytes The signature bytes. * @param offset The offset of the signature bytes. * @param type The interpretation of the signature bytes (e.g., raw * bytes, an ASCII string). diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form index 3d5852a878..a2dbc9c05d 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form @@ -50,14 +50,10 @@ - - - - - + - + @@ -121,18 +117,13 @@ + - - - - - - - - - - + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java index 169c69ddc7..3fdb28898e 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -35,7 +35,9 @@ import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; import org.sleuthkit.autopsy.modules.filetypeid.FileType.Signature; /** - * A panel to allow a user to make custom file type definitions. + * A panel to allow a user to make custom file type definitions. In addition to + * being an ingest module global settings panel, an instance of this class also + * appears in the NetBeans options dialog as an options panel. */ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { @@ -44,10 +46,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane /** * These two fields are used to synthesize default names for user-defined - * types. This is a thread-safe implementation because there can be two - * instances of this panel at the same time due to the non-modal nature of - * the NetBeans options window and the fact that these panels can also be - * invoked via ingest job configuration panels. All interactions with + * types. This is a thread-safe implementation. All interactions with * instances of this panel should occur on the EDT, so this is defensive * programming. */ @@ -55,11 +54,12 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane private static final AtomicInteger defaultTypeNameCounter = new AtomicInteger(1); /** - * This mapping of file type names to file types is used to hold the types - * displayed in the file types list component via its list model. + * The list model for the file types list component of this panel is the set + * of type names of the user-defined file types. A mapping of the file type + * names to file type objects completes the model. */ - private Map fileTypes; private DefaultListModel typesListModel; + private Map fileTypes; /** * Creates a panel to allow a user to make custom file type definitions. @@ -70,8 +70,8 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane } /** - * Does component initialization in addition to the the Matisse generated - * initialization. + * Does child component initialization in addition to the the Matisse + * generated initialization. */ private void customizeComponents() { /** @@ -79,14 +79,14 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane */ this.typesListModel = new DefaultListModel<>(); this.typesList.setModel(this.typesListModel); - + /** * Make a model for the signature type combo box component. */ DefaultComboBoxModel sigTypeComboBoxModel = new DefaultComboBoxModel<>(); sigTypeComboBoxModel.addElement(FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM); sigTypeComboBoxModel.addElement(FileTypeIdGlobalSettingsPanel.ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM); - this.signatureTypeComboBox.setModel(sigTypeComboBoxModel); + this.signatureTypeComboBox.setModel(sigTypeComboBoxModel); } /** @@ -98,7 +98,8 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane } /** - * Populates the child components. + * Populates the child components with file types obtained from the + * user-defined file types manager. */ @Override public void load() { @@ -413,11 +414,11 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane signatureBytes = sigString.getBytes(Charset.forName("UTF-8")); } - /** + /** * Get the offset. */ long offset = Long.parseUnsignedLong(this.offsetTextField.getText()); - + /** * Put it all together and reset the file types list component. */ @@ -426,17 +427,17 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane this.fileTypes.put(typeName, fileType); this.setFileTypesListModel(); this.typesList.setSelectedValue(fileType.getTypeName(), true); - + } catch (NumberFormatException ex) { - JOptionPane.showMessageDialog(null, - NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message"), - NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.title"), - JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message"), + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.title"), + JOptionPane.ERROR_MESSAGE); } catch (IllegalArgumentException ex) { - JOptionPane.showMessageDialog(null, - NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignatureBytes.message"), - NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignatureBytes.title"), - JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignatureBytes.message"), + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignatureBytes.title"), + JOptionPane.ERROR_MESSAGE); } }//GEN-LAST:event_saveTypeButtonActionPerformed From c413aae3771eaa27bde7e92e034ac6a3325c4ef6 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 8 Dec 2014 09:05:42 -0500 Subject: [PATCH 13/27] Continue to work on user-defined types --- .../modules/filetypeid/FileTypeIdGlobalSettingsPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java index 3fdb28898e..32b4aff441 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -51,7 +51,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane * programming. */ private static final String DEFAULT_TYPE_NAME_BASE = "userdefined/userdefined"; //NON-NLS - private static final AtomicInteger defaultTypeNameCounter = new AtomicInteger(1); + private static final AtomicInteger defaultTypeNameCounter = new AtomicInteger(1); // RJCTODO: Need to save and init counter /** * The list model for the file types list component of this panel is the set From 552d1039fb2e55713b3c99d8be9d67e7f2c1759b Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 8 Dec 2014 19:30:26 -0500 Subject: [PATCH 14/27] Improve user-defined file types (incomplete) --- .../sleuthkit/autopsy/coreutils/XMLUtil.java | 48 +++++ .../modules/filetypeid/Bundle.properties | 6 +- .../autopsy/modules/filetypeid/FileType.java | 25 ++- .../FileTypeIdGlobalSettingsPanel.form | 181 ++++++++--------- .../FileTypeIdGlobalSettingsPanel.java | 182 ++++++++++-------- .../filetypeid/UserDefinedFileTypes.xsd | 11 +- .../UserDefinedFileTypesManager.java | 126 +++++++----- 7 files changed, 350 insertions(+), 229 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/XMLUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/XMLUtil.java index dc12e3bd2c..603fc52e60 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/XMLUtil.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/XMLUtil.java @@ -25,6 +25,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; +import java.nio.file.Paths; import java.util.logging.Level; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; @@ -155,6 +156,7 @@ public class XMLUtil { * @param xmlPath the full path to the file to load * @param xsdPath the full path to the file to validate against */ + // RJCTODO: Deprecate public static Document loadDoc(Class clazz, String xmlPath, String xsdPath) { Document ret = loadDoc(clazz, xmlPath); if (!XMLUtil.xmlIsValid(ret, clazz, xsdPath)) { @@ -163,6 +165,51 @@ public class XMLUtil { return ret; } + /** + * Used to consolidate more specific exception types. + */ + public static class XmlUtilException extends Exception { + + XmlUtilException(String message) { + super(message); + } + } + + /** + * Loads and validates an XML document. + * + * @param docPath The full path to the file to load. + * @param schemaPath The full path to the file to validate against. + */ + /** + * Loads and XML document and validates against a schema packaged as a + * class resource. + * + * @param The name of the class associated with the resource. + * @param clazz The class associated with the resource. + * @param docPath The full path to the XML document. + * @param schemaResourceName The name of the schema resource + * @return A WC3 DOM representation of the document + * @throws IOException + * @throws org.sleuthkit.autopsy.coreutils.XMLUtil.XmlUtilException + */ + public static Document loadAndValidateDoc(Class clazz, String docPath, String schemaResourceName) throws IOException, XmlUtilException { + try { + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + Document doc = builder.parse(new FileInputStream(docPath)); + PlatformUtil.extractResourceToUserConfigDir(clazz, schemaResourceName, false); + File schemaFile = new File(Paths.get(PlatformUtil.getUserConfigDirectory(), schemaResourceName).toAbsolutePath().toString()); + SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + Schema schema = schemaFactory.newSchema(schemaFile); + Validator validator = schema.newValidator(); + validator.validate(new DOMSource(doc), new DOMResult()); + return doc; + } catch (ParserConfigurationException | SAXException ex) { + throw new XmlUtilException(ex.getLocalizedMessage()); + } + } + /** * Saves XML files to disk * @@ -203,4 +250,5 @@ public class XMLUtil { } return success; } + } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties index 6a15e196d1..2f55fc8fb8 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties @@ -19,7 +19,7 @@ FileTypeIdGlobalSettingsPanel.jTextArea1.text=Enter a MIME type and signature to FileTypeIdGlobalSettingsPanel.signatureTypeLabel.text=Signature Type FileTypeIdGlobalSettingsPanel.mimeTypeTextField.text= FileTypeIdGlobalSettingsPanel.signatureLabel.text=Signature -FileTypeIdGlobalSettingsPanel.mimeTypeLabel.text=Mime Type +FileTypeIdGlobalSettingsPanel.mimeTypeLabel.text=MIME Type FileTypeIdGlobalSettingsPanel.saveTypeButton.text=Save Type FileTypeIdGlobalSettingsPanel.signatureComboBox.rawItem=Bytes (Hex) FileTypeIdGlobalSettingsPanel.signatureComboBox.asciiItem=String (ASCII) @@ -30,4 +30,6 @@ FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignature.title=Missing Signatu FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message=Offset must be a positive integer. FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.title=Invalid Offset FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignatureBytes.message=The signature must be able to be converted to UTF-8 bytes. -FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignatureBytes.title=Invalid Signature \ No newline at end of file +FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignatureBytes.title=Invalid Signature +FileTypeIdGlobalSettingsPanel.filesSetNameLabel.text=Files Set Name +FileTypeIdGlobalSettingsPanel.filesSetNameTextField.text= diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java index 8aa261a84f..e3b9908131 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java @@ -29,32 +29,35 @@ import org.sleuthkit.datamodel.TskCoreException; */ final class FileType { - private final String typeName; + private final String mimeType; private final Signature signature; + private final String filesSetName; private final boolean alert; /** * Creates a representation of a named file type characterized by a file * signature. * - * @param typeName The name of the file type. + * @param mimeType The mime type to associate with this file type. * @param signature The signature that characterizes the file type. + * @param filesSetName The interesting files set name * @param alert A flag indicating whether the user wishes to be alerted when * a file matching this type is encountered. */ - FileType(String typeName, final Signature signature, boolean alert) { - this.typeName = typeName; + FileType(String mimeType, final Signature signature, String filesSetName, boolean alert) { + this.mimeType = mimeType; this.signature = new Signature(signature.getSignatureBytes(), signature.getOffset(), signature.getType()); + this.filesSetName = filesSetName; this.alert = alert; } /** - * Gets the name associated with this file type. + * Gets the MIME type associated with this file type. * * @return The type name. */ - String getTypeName() { - return this.typeName; + String getMimeType() { + return this.mimeType; } /** @@ -85,6 +88,14 @@ final class FileType { boolean alertOnMatch() { return this.alert; } + + /** + * Gets the interesting files set name assigned to this file type + * @return + */ + String getFilesSetName() { + return this.filesSetName; + } /** * A file signature consisting of a sequence of bytes at a specific offset diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form index a2dbc9c05d..a4615bbc52 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form @@ -20,115 +20,107 @@ - + + + + + + - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + - + - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + @@ -284,6 +276,23 @@ + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java index 32b4aff441..70aebae4d5 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -87,6 +87,8 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane sigTypeComboBoxModel.addElement(FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM); sigTypeComboBoxModel.addElement(FileTypeIdGlobalSettingsPanel.ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM); this.signatureTypeComboBox.setModel(sigTypeComboBoxModel); + + this.filesSetNameTextField.setEnabled(false); } /** @@ -214,6 +216,8 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane jScrollPane2 = new javax.swing.JScrollPane(); jTextArea1 = new javax.swing.JTextArea(); postHitCheckBox = new javax.swing.JCheckBox(); + filesSetNameLabel = new javax.swing.JLabel(); + filesSetNameTextField = new javax.swing.JTextField(); typesScrollPane.setViewportView(typesList); @@ -266,6 +270,15 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane jScrollPane2.setViewportView(jTextArea1); org.openide.awt.Mnemonics.setLocalizedText(postHitCheckBox, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.postHitCheckBox.text")); // NOI18N + postHitCheckBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + postHitCheckBoxActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(filesSetNameLabel, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.filesSetNameLabel.text")); // NOI18N + + filesSetNameTextField.setText(org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.filesSetNameTextField.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -275,93 +288,85 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane .addGap(26, 26, 26) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(10, 10, 10) + .addComponent(typesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) .addComponent(newTypeButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(deleteTypeButton)) - .addComponent(typesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)) + .addComponent(deleteTypeButton) + .addGap(9, 9, 9))) + .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 13, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(37, 37, 37) - .addComponent(saveTypeButton)) - .addGroup(layout.createSequentialGroup() - .addGap(18, 18, 18) - .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 13, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(signatureTypeLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(signatureTypeComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(signatureLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(hexPrefixLabel) - .addGap(2, 2, 2)) - .addGroup(layout.createSequentialGroup() - .addComponent(offsetLabel) - .addGap(44, 44, 44))) - .addGap(5, 5, 5) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(offsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 84, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(signatureTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 178, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addGap(2, 2, 2) - .addComponent(mimeTypeLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(mimeTypeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 181, javax.swing.GroupLayout.PREFERRED_SIZE)))) - .addGroup(layout.createSequentialGroup() - .addGap(6, 6, 6) - .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 260, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(postHitCheckBox))))) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(signatureTypeLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(signatureTypeComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(offsetLabel) + .addComponent(filesSetNameLabel) + .addGroup(layout.createSequentialGroup() + .addComponent(signatureLabel) + .addGap(18, 18, 18) + .addComponent(hexPrefixLabel))) + .addGap(5, 5, 5) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(offsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 84, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(signatureTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 178, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addGap(2, 2, 2) + .addComponent(mimeTypeLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(mimeTypeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 181, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(filesSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 179, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 260, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(postHitCheckBox) + .addComponent(saveTypeButton)) + .addContainerGap(29, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(16, 16, 16) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 281, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(typesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 219, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(mimeTypeLabel) - .addComponent(mimeTypeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(signatureTypeLabel) - .addComponent(signatureTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(signatureTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(hexPrefixLabel) - .addComponent(signatureLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(offsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(offsetLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(postHitCheckBox))) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addGroup(layout.createSequentialGroup() - .addGap(18, 18, 18) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(newTypeButton) - .addComponent(deleteTypeButton))) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(saveTypeButton)))) - .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 260, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap()) + .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(mimeTypeLabel) + .addComponent(mimeTypeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(signatureTypeLabel) + .addComponent(signatureTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(signatureTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(hexPrefixLabel) + .addComponent(signatureLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(offsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(offsetLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(postHitCheckBox) + .addGap(8, 8, 8) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(filesSetNameLabel) + .addComponent(filesSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(saveTypeButton)) + .addGroup(layout.createSequentialGroup() + .addComponent(typesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 249, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(deleteTypeButton) + .addComponent(newTypeButton)))) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -419,14 +424,25 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane */ long offset = Long.parseUnsignedLong(this.offsetTextField.getText()); + /** + * Get the interesting files set details. + */ + String filesSetName = this.filesSetNameTextField.getText(); + if (this.postHitCheckBox.isSelected() && filesSetName.isEmpty()) { + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message"), + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.title"), + JOptionPane.ERROR_MESSAGE); + } + /** * Put it all together and reset the file types list component. */ FileType.Signature signature = new FileType.Signature(signatureBytes, offset, sigType); // RJCTODO: - FileType fileType = new FileType(typeName, signature, this.postHitCheckBox.isSelected()); + FileType fileType = new FileType(typeName, signature, filesSetName, this.postHitCheckBox.isSelected()); this.fileTypes.put(typeName, fileType); this.setFileTypesListModel(); - this.typesList.setSelectedValue(fileType.getTypeName(), true); + this.typesList.setSelectedValue(fileType.getMimeType(), true); } catch (NumberFormatException ex) { JOptionPane.showMessageDialog(null, @@ -441,9 +457,15 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane } }//GEN-LAST:event_saveTypeButtonActionPerformed + private void postHitCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_postHitCheckBoxActionPerformed + this.filesSetNameTextField.setEnabled(this.postHitCheckBox.isSelected()); + }//GEN-LAST:event_postHitCheckBoxActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton deleteTypeButton; + private javax.swing.JLabel filesSetNameLabel; + private javax.swing.JTextField filesSetNameTextField; private javax.swing.JLabel hexPrefixLabel; private javax.swing.JScrollPane jScrollPane2; private javax.swing.JSeparator jSeparator1; diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.xsd b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.xsd index aa8e053534..16557dc422 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.xsd +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.xsd @@ -30,11 +30,18 @@ + + + + + + + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java index 031a6d46f8..53ec537fa6 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java @@ -41,8 +41,8 @@ import org.sleuthkit.autopsy.modules.filetypeid.FileType.Signature; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; /** - * Manages user-defined file types characterized by type names (e.g., MIME type) - * and signatures. + * Manages user-defined file types characterized by MIME type, signature, and + * optional membership in an interesting files set. */ final class UserDefinedFileTypesManager { @@ -51,19 +51,20 @@ final class UserDefinedFileTypesManager { private static final String USER_DEFINED_TYPE_DEFINITIONS_FILE = "UserFileTypeDefinitions.xml"; //NON-NLS private static final String FILE_TYPES_TAG_NAME = "filetypes"; //NON-NLS private static final String FILE_TYPE_TAG_NAME = "filetype"; //NON-NLS - private static final String ALERT_ATTRIBUTE = "alert"; //NON-NLS - private static final String TYPE_NAME_TAG_NAME = "typename"; //NON-NLS + private static final String MIME_TYPE_TAG_NAME = "mimetype"; //NON-NLS private static final String SIGNATURE_TAG_NAME = "signature"; //NON-NLS private static final String SIGNATURE_TYPE_ATTRIBUTE = "type"; //NON-NLS private static final String BYTES_TAG_NAME = "bytes"; //NON-NLS private static final String OFFSET_TAG_NAME = "offset"; //NON-NLS + private static final String INTERESTING_FILES_SET_TAG_NAME = "filesset"; //NON-NLS + private static final String ALERT_ATTRIBUTE = "alert"; //NON-NLS private static final String ENCODING_FOR_XML_FILE = "UTF-8"; //NON-NLS private static final String ASCII_ENCODING = "US-ASCII"; //NON-NLS private static UserDefinedFileTypesManager instance; /** - * Predefined file types are stored in this mapping of file type names to - * file types. Access to this map is guarded by the intrinsic lock of the + * Predefined file types are stored in this mapping of MIME types to file + * types. Access to this map is guarded by the intrinsic lock of the * user-defined file types manager for thread-safety. */ private final Map predefinedFileTypes = new HashMap<>(); @@ -78,17 +79,18 @@ final class UserDefinedFileTypesManager { /** * The combined set of user-defined file types and file types predefined by - * Autopsy are stored in this mapping of file type names to file types. This - * is the current working set of file types. Access to this map is guarded - * by the intrinsic lock of the user-defined file types manager for + * Autopsy are stored in this mapping of MIME types to file types. This is + * the current working set of file types. Access to this map is guarded by + * the intrinsic lock of the user-defined file types manager for * thread-safety. */ private final Map fileTypes = new HashMap<>(); /** - * Gets the user-defined file types manager. + * Gets the manager of user-defined file types characterized by MIME type, + * signature, and optional membership in an interesting files set. * - * @return A singleton user-defined file types manager. + * @return The user-defined file types manager singleton. */ synchronized static UserDefinedFileTypesManager getInstance() { if (UserDefinedFileTypesManager.instance == null) { @@ -98,8 +100,8 @@ final class UserDefinedFileTypesManager { } /** - * Creates a manager of user-defined file types characterized by type names - * (e.g., MIME type) and signatures. + * Creates a manager of user-defined file types characterized by MIME type, + * signature, and optional membership in an interesting files set. */ private UserDefinedFileTypesManager() { /** @@ -111,30 +113,30 @@ final class UserDefinedFileTypesManager { } /** - * Adds standard predefined file types to the in-memory mapping of file type - * names to predefined file types. + * Adds the predefined file types to the in-memory mappings of MIME types to + * file types. */ private void loadPredefinedFileTypes() { - // RJCTODO: Remove test type + // RJCTODO: Remove test file type. /** * Create a file type that should match $MBR in Small2 image. */ - FileType fileType = new FileType("predefinedRAW", new Signature(new byte[]{(byte) 0x66, (byte) 0x73, (byte) 0x00}, 8L, FileType.Signature.Type.RAW), true); + FileType fileType = new FileType("predefinedRAW", new Signature(new byte[]{(byte) 0x66, (byte) 0x73, (byte) 0x00}, 8L, FileType.Signature.Type.RAW), "predefinedRAW", true); this.addPredefinedFileType(fileType); /** * Create a file type that should match test.txt in the Small2 image. */ - // RJCTODO: Remove test type + // RJCTODO: Remove test file type. try { - fileType = new FileType("predefinedASCII", new Signature("hello".getBytes(UserDefinedFileTypesManager.ASCII_ENCODING), 0L, FileType.Signature.Type.ASCII), true); + fileType = new FileType("predefinedASCII", new Signature("hello".getBytes(UserDefinedFileTypesManager.ASCII_ENCODING), 0L, FileType.Signature.Type.ASCII), "predefinedASCII", true); this.addPredefinedFileType(fileType); } catch (UnsupportedEncodingException ex) { UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Unable to create 'predefinedASCII' predefined file type definition", ex); //NON-NLS } try { - // RJCTODO: Remove this code from TikaFileTypeDetector.java + // RJCTODO: Remove this code from TikaFileTypeDetector.java. // try { // byte buf[]; // int len = abstractFile.read(buffer, 0, BUFFER_SIZE); @@ -156,7 +158,7 @@ final class UserDefinedFileTypesManager { // catch (IndexOutOfBoundsException e) { // // do nothing // } - fileType = new FileType("text/xml", new Signature(" Date: Thu, 18 Dec 2014 09:54:34 -0500 Subject: [PATCH 15/27] Add caveat to IngestManager.isIngestRunning --- Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java index b0cb987710..42f518b5e4 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -470,7 +470,8 @@ public class IngestManager { } /** - * Queries whether or not any ingest jobs are in progress. + * Queries whether or not any ingest jobs are in progress, at least at the + * moment of the query. * * @return True or false. */ From 0a523552e1c06195cb5104ab7f05d6f228177292 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 18 Dec 2014 10:25:05 -0500 Subject: [PATCH 16/27] Continue work on user-defined file types --- .../sleuthkit/autopsy/coreutils/XMLUtil.java | 56 ++--- .../UserDefinedFileTypesManager.java | 192 ++++++++---------- 2 files changed, 110 insertions(+), 138 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/XMLUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/XMLUtil.java index 603fc52e60..bdcd28e32d 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/XMLUtil.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/XMLUtil.java @@ -166,24 +166,8 @@ public class XMLUtil { } /** - * Used to consolidate more specific exception types. - */ - public static class XmlUtilException extends Exception { - - XmlUtilException(String message) { - super(message); - } - } - - /** - * Loads and validates an XML document. - * - * @param docPath The full path to the file to load. - * @param schemaPath The full path to the file to validate against. - */ - /** - * Loads and XML document and validates against a schema packaged as a - * class resource. + * Loads an XML document into a WC3 DOM and validates it against a schema + * packaged as a class resource. * * @param The name of the class associated with the resource. * @param clazz The class associated with the resource. @@ -193,21 +177,25 @@ public class XMLUtil { * @throws IOException * @throws org.sleuthkit.autopsy.coreutils.XMLUtil.XmlUtilException */ - public static Document loadAndValidateDoc(Class clazz, String docPath, String schemaResourceName) throws IOException, XmlUtilException { - try { - DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = builderFactory.newDocumentBuilder(); - Document doc = builder.parse(new FileInputStream(docPath)); - PlatformUtil.extractResourceToUserConfigDir(clazz, schemaResourceName, false); - File schemaFile = new File(Paths.get(PlatformUtil.getUserConfigDirectory(), schemaResourceName).toAbsolutePath().toString()); - SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); - Schema schema = schemaFactory.newSchema(schemaFile); - Validator validator = schema.newValidator(); - validator.validate(new DOMSource(doc), new DOMResult()); - return doc; - } catch (ParserConfigurationException | SAXException ex) { - throw new XmlUtilException(ex.getLocalizedMessage()); - } + public static Document loadAndValidateDoc(Class clazz, String docPath, String schemaResourceName) throws IOException, ParserConfigurationException, SAXException { + /** + * Parse the XML file into a DOM. + */ + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + Document doc = builder.parse(new FileInputStream(docPath)); + + /** + * Extract the schema and validate the DOM. + */ + PlatformUtil.extractResourceToUserConfigDir(clazz, schemaResourceName, false); + File schemaFile = new File(Paths.get(PlatformUtil.getUserConfigDirectory(), schemaResourceName).toAbsolutePath().toString()); + SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + Schema schema = schemaFactory.newSchema(schemaFile); + Validator validator = schema.newValidator(); + validator.validate(new DOMSource(doc), new DOMResult()); + + return doc; } /** @@ -220,7 +208,7 @@ public class XMLUtil { */ public static boolean saveDoc(Class clazz, String xmlPath, String encoding, final Document doc) { TransformerFactory xf = TransformerFactory.newInstance(); - xf.setAttribute("indent-number", new Integer(1)); //NON-NLS + xf.setAttribute("indent-number", 1); //NON-NLS boolean success = false; try { Transformer xformer = xf.newTransformer(); diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java index 53ec537fa6..2b46c4880d 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java @@ -5,7 +5,7 @@ * Contact: carrier sleuthkit 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 not use this schemaFile except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 @@ -34,15 +34,17 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import javax.xml.bind.DatatypeConverter; +import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.XMLUtil; import org.sleuthkit.autopsy.modules.filetypeid.FileType.Signature; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; +import org.xml.sax.SAXException; /** - * Manages user-defined file types characterized by MIME type, signature, and - * optional membership in an interesting files set. + * Manages user-defined schemaFile types characterized by MIME type, signature, + * and optional membership in an interesting files set. */ final class UserDefinedFileTypesManager { @@ -63,34 +65,35 @@ final class UserDefinedFileTypesManager { private static UserDefinedFileTypesManager instance; /** - * Predefined file types are stored in this mapping of MIME types to file - * types. Access to this map is guarded by the intrinsic lock of the - * user-defined file types manager for thread-safety. + * Predefined schemaFile types are stored in this mapping of MIME types to + * schemaFile types. Access to this map is guarded by the intrinsic lock of + * the user-defined schemaFile types manager for thread-safety. */ private final Map predefinedFileTypes = new HashMap<>(); /** - * User-defined file types to be persisted to the user-defined file type - * definitions file are stored in this mapping of file type names to file - * types. Access to this map is guarded by the intrinsic lock of the - * user-defined file types manager for thread-safety. + * User-defined schemaFile types to be persisted to the user-defined + * schemaFile type definitions schemaFile are stored in this mapping of + * schemaFile type names to schemaFile types. Access to this map is guarded + * by the intrinsic lock of the user-defined schemaFile types manager for + * thread-safety. */ private final Map userDefinedFileTypes = new HashMap<>(); /** - * The combined set of user-defined file types and file types predefined by - * Autopsy are stored in this mapping of MIME types to file types. This is - * the current working set of file types. Access to this map is guarded by - * the intrinsic lock of the user-defined file types manager for - * thread-safety. + * The combined set of user-defined schemaFile types and schemaFile types + * predefined by Autopsy are stored in this mapping of MIME types to + * schemaFile types. This is the current working set of schemaFile types. + * Access to this map is guarded by the intrinsic lock of the user-defined + * schemaFile types manager for thread-safety. */ private final Map fileTypes = new HashMap<>(); /** - * Gets the manager of user-defined file types characterized by MIME type, - * signature, and optional membership in an interesting files set. + * Gets the manager of user-defined schemaFile types characterized by MIME + * type, signature, and optional membership in an interesting files set. * - * @return The user-defined file types manager singleton. + * @return The user-defined schemaFile types manager singleton. */ synchronized static UserDefinedFileTypesManager getInstance() { if (UserDefinedFileTypesManager.instance == null) { @@ -100,8 +103,8 @@ final class UserDefinedFileTypesManager { } /** - * Creates a manager of user-defined file types characterized by MIME type, - * signature, and optional membership in an interesting files set. + * Creates a manager of user-defined schemaFile types characterized by MIME + * type, signature, and optional membership in an interesting files set. */ private UserDefinedFileTypesManager() { /** @@ -113,11 +116,11 @@ final class UserDefinedFileTypesManager { } /** - * Adds the predefined file types to the in-memory mappings of MIME types to - * file types. + * Adds the predefined schemaFile types to the in-memory mappings of MIME + * types to schemaFile types. */ private void loadPredefinedFileTypes() { - // RJCTODO: Remove test file type. + // RJCTODO: Remove test schemaFile type. /** * Create a file type that should match $MBR in Small2 image. */ @@ -127,7 +130,7 @@ final class UserDefinedFileTypesManager { /** * Create a file type that should match test.txt in the Small2 image. */ - // RJCTODO: Remove test file type. + // RJCTODO: Remove test schemaFile type. try { fileType = new FileType("predefinedASCII", new Signature("hello".getBytes(UserDefinedFileTypesManager.ASCII_ENCODING), 0L, FileType.Signature.Type.ASCII), "predefinedASCII", true); this.addPredefinedFileType(fileType); @@ -147,7 +150,7 @@ final class UserDefinedFileTypesManager { // buf = buffer; // } // -// // the xml detection in Tika tries to parse the entire file and throws exceptions +// // the xml detection in Tika tries to parse the entire schemaFile and throws exceptions // // for files that are not valid XML // try { // String tagHeader = new String(buf, 0, 5); @@ -170,10 +173,10 @@ final class UserDefinedFileTypesManager { } /** - * Adds a file type to the the predefined file types and combined file types - * maps. + * Adds a schemaFile type to the the predefined schemaFile types and + * combined schemaFile types maps. * - * @param fileType The file type to add. + * @param fileType The schemaFile type to add. */ private void addPredefinedFileType(FileType fileType) { this.predefinedFileTypes.put(fileType.getMimeType(), fileType); @@ -181,8 +184,8 @@ final class UserDefinedFileTypesManager { } /** - * Adds the user-defined file types to the in-memory mappings of MIME types - * to file types. + * Adds the user-defined schemaFile types to the in-memory mappings of MIME + * types to schemaFile types. */ private void loadUserDefinedFileTypes() { try { @@ -194,21 +197,21 @@ final class UserDefinedFileTypesManager { } } - } catch (UserDefinedFileTypesManager.InvalidXMLException ex) { + } catch (IOException | ParserConfigurationException | SAXException ex) { /** * Using an all-or-none policy. */ UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Unable to load user-defined types", ex); //NON-NLS this.fileTypes.clear(); this.userDefinedFileTypes.clear(); - } + } } /** - * Adds a file type to the the user-defined file types and combined file - * types maps. + * Adds a schemaFile type to the the user-defined schemaFile types and + * combined schemaFile types maps. * - * @param fileType The file type to add. + * @param fileType The schemaFile type to add. */ private void addUserDefinedFileType(FileType fileType) { this.userDefinedFileTypes.put(fileType.getMimeType(), fileType); @@ -216,9 +219,10 @@ final class UserDefinedFileTypesManager { } /** - * Gets both the predefined and the user-defined file types. + * Gets both the predefined and the user-defined schemaFile types. * - * @return A mapping of file type names to file types, possibly empty. + * @return A mapping of schemaFile type names to schemaFile types, possibly + * empty. */ synchronized Map getFileTypes() { /** @@ -229,9 +233,10 @@ final class UserDefinedFileTypesManager { } /** - * Gets the user-defined file types. + * Gets the user-defined schemaFile types. * - * @return A mapping of file type names to file types, possibly empty. + * @return A mapping of schemaFile type names to schemaFile types, possibly + * empty. */ synchronized Map getUserDefinedFileTypes() { /** @@ -242,10 +247,10 @@ final class UserDefinedFileTypesManager { } /** - * Sets the user-defined file types. + * Sets the user-defined schemaFile types. * - * @param newFileTypes A mapping of file type names to user-defined file - * types. + * @param newFileTypes A mapping of schemaFile type names to user-defined + * schemaFile types. * @throws * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException */ @@ -281,10 +286,10 @@ final class UserDefinedFileTypesManager { } /** - * Gets the absolute path of a file type definitions file. + * Gets the absolute path of a schemaFile type definitions schemaFile. * - * @param fileName The name of the file. - * @return The absolute path to the file. + * @param fileName The name of the schemaFile. + * @return The absolute path to the schemaFile. */ private static String getFileTypeDefinitionsFilePath(String fileName) { Path filePath = Paths.get(PlatformUtil.getUserConfigDirectory(), fileName); @@ -292,16 +297,16 @@ final class UserDefinedFileTypesManager { } /** - * Provides a mechanism for writing a set of file type definitions to an XML - * file. + * Provides a mechanism for writing a set of schemaFile type definitions to + * an XML schemaFile. */ private static class XMLWriter { /** - * Writes a set of file type definitions to an XML file. + * Writes a set of schemaFile type definitions to an XML schemaFile. * - * @param signatures A collection of file types. - * @param filePath The path to the destination file. + * @param signatures A collection of schemaFile types. + * @param filePath The path to the destination schemaFile. */ private static void writeFileTypes(Collection fileTypes, String filePath) throws ParserConfigurationException, IOException { Document doc = XMLUtil.createDoc(); @@ -318,9 +323,9 @@ final class UserDefinedFileTypesManager { } /** - * Creates an XML representation of a file type. + * Creates an XML representation of a schemaFile type. * - * @param fileType The file type object. + * @param fileType The schemaFile type object. * @param doc The DOM document to use to create the XML. * @return An XML element. */ @@ -372,33 +377,30 @@ final class UserDefinedFileTypesManager { } /** - * Provides a mechanism for reading a set of file type definitions from an - * XML file. + * Provides a mechanism for reading a set of schemaFile type definitions + * from an XML schemaFile. */ private static class XMLReader { /** - * Reads a set of file type definitions from an XML file. + * Reads a set of schemaFile type definitions from an XML schemaFile. * - * @param filePath The path to the file. - * @return A collection of file types. + * @param filePath The path to the XML schemaFile. + * @return A collection of schemaFile types read from the XML + * schemaFile. */ - private static List readFileTypes(String filePath) throws InvalidXMLException { + private static List readFileTypes(String filePath) throws IOException, ParserConfigurationException, SAXException { List fileTypes = new ArrayList<>(); - Path xsdPath = Paths.get(PlatformUtil.getUserConfigDirectory(), UserDefinedFileTypesManager.FILE_TYPE_DEFINITIONS_SCHEMA_FILE); - String xsdPathString = xsdPath.toAbsolutePath().toString(); - File file = new File(xsdPathString); - if (file.exists() && file.canRead()) { - Document doc = XMLUtil.loadAndValidateDoc(UserDefinedFileTypesManager.XMLReader.class, filePath, xsdPathString); - if (doc != null) { - Element fileTypesElem = doc.getDocumentElement(); - if (fileTypesElem != null && fileTypesElem.getNodeName().equals(UserDefinedFileTypesManager.FILE_TYPES_TAG_NAME)) { - NodeList fileTypeElems = fileTypesElem.getElementsByTagName(UserDefinedFileTypesManager.FILE_TYPE_TAG_NAME); - for (int i = 0; i < fileTypeElems.getLength(); ++i) { - Element fileTypeElem = (Element) fileTypeElems.item(i); - FileType fileType = UserDefinedFileTypesManager.XMLReader.parseFileType(fileTypeElem); - fileTypes.add(fileType); - } + Path schemaFilePath = Paths.get(PlatformUtil.getUserConfigDirectory(), UserDefinedFileTypesManager.FILE_TYPE_DEFINITIONS_SCHEMA_FILE); + Document doc = XMLUtil.loadAndValidateDoc(UserDefinedFileTypesManager.XMLReader.class, filePath, schemaFilePath.toAbsolutePath().toString()); + if (doc != null) { + Element fileTypesElem = doc.getDocumentElement(); + if (fileTypesElem != null && fileTypesElem.getNodeName().equals(UserDefinedFileTypesManager.FILE_TYPES_TAG_NAME)) { + NodeList fileTypeElems = fileTypesElem.getElementsByTagName(UserDefinedFileTypesManager.FILE_TYPE_TAG_NAME); + for (int i = 0; i < fileTypeElems.getLength(); ++i) { + Element fileTypeElem = (Element) fileTypeElems.item(i); + FileType fileType = UserDefinedFileTypesManager.XMLReader.parseFileType(fileTypeElem); + fileTypes.add(fileType); } } } @@ -406,29 +408,23 @@ final class UserDefinedFileTypesManager { } /** - * Parse a file type definition from a file type XML element. + * Parse a schemaFile type definition from a schemaFile type XML + * element. * * @param fileTypeElem The XML element. - * @return A file type object. + * @return A schemaFile type object. * @throws - * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.InvalidXMLException */ - private static FileType parseFileType(Element fileTypeElem) throws InvalidXMLException, IllegalArgumentException, NumberFormatException { + private static FileType parseFileType(Element fileTypeElem) throws IllegalArgumentException, NumberFormatException { /** * Get the mime type child element. */ String mimeType = UserDefinedFileTypesManager.getChildElementTextContent(fileTypeElem, UserDefinedFileTypesManager.MIME_TYPE_TAG_NAME); /** - * Get the signature child element. The check here is essentially a - * "sanity check" since the XML was already validated using the XSD - * file. + * Get the signature child element. */ NodeList signatureElems = fileTypeElem.getElementsByTagName(UserDefinedFileTypesManager.SIGNATURE_TAG_NAME); - if (signatureElems.getLength() < 1) { - } else { - throw new InvalidXMLException("Missing " + UserDefinedFileTypesManager.SIGNATURE_TAG_NAME + " child element"); //NON-NLS - } Element signatureElem = (Element) signatureElems.item(0); /** @@ -472,35 +468,22 @@ final class UserDefinedFileTypesManager { } /** - * Gets the text content of a single child element. + * Gets the text content of a single child element. Assumes the elements + * have already been validated. * * @param elem The parent element. * @param tagName The tag name of the child element. * @return The text content. - * @throws UserDefinedFileTypesException */ - private static String getChildElementTextContent(Element elem, String tagName) throws InvalidXMLException { - /** - * The checks here are essentially "sanity checks" since the XML was - * already validated using the XSD file. - */ + private static String getChildElementTextContent(Element elem, String tagName) { NodeList childElems = elem.getElementsByTagName(tagName); - if (childElems.getLength() > 0) { - Element childElem = (Element) childElems.item(0); - String textContent = childElem.getTextContent(); - if (!textContent.isEmpty()) { - return textContent; - } else { - throw new InvalidXMLException(tagName + " child element missing text content"); //NON-NLS - } - } else { - throw new InvalidXMLException("Missing " + tagName + " child element"); //NON-NLS - } + Element childElem = (Element) childElems.item(0); + return childElem.getTextContent(); } /** - * Used for exceptions when parsing user-defined types XML elements and - * attributes. + * Used for throwing exceptions when parsing user-defined types XML elements + * and attributes. */ private static class InvalidXMLException extends Exception { @@ -511,7 +494,8 @@ final class UserDefinedFileTypesManager { /** * Used to translate more implementation-details-specific exceptions (which - * are logged by this class) into more generic exceptions. + * are logged by this class) into more generic exceptions for propagation to + * clients of the user-defined schemaFile types manager. */ static class UserDefinedFileTypesException extends Exception { From dcd632e5e6193d81fc226b15b5caaa9fc4ee3f2c Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 18 Dec 2014 16:59:34 -0500 Subject: [PATCH 17/27] Continue to work on user-defined file types --- .../sleuthkit/autopsy/coreutils/XMLUtil.java | 124 ++++-- .../autopsy/modules/filetypeid/FileType.java | 7 +- .../FileTypeIdGlobalSettingsPanel.java | 58 +-- .../filetypeid/UserDefinedFileTypes.xsd | 12 +- .../UserDefinedFileTypesManager.java | 364 ++++++++++-------- 5 files changed, 304 insertions(+), 261 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/XMLUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/XMLUtil.java index bdcd28e32d..ef360762d9 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/XMLUtil.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/XMLUtil.java @@ -56,17 +56,100 @@ import org.xml.sax.SAXException; public class XMLUtil { /** - * Creates a W3C DOM document. + * Creates a W3C DOM. * * @return The document object. * @throws ParserConfigurationException */ - public static Document createDoc() throws ParserConfigurationException { + public static Document createDocument() throws ParserConfigurationException { DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = builderFactory.newDocumentBuilder(); return builder.newDocument(); } + /** + * Loads an XML document into a WC3 DOM and validates it using a schema + * packaged as a class resource. + * + * @param The name of the class associated with the resource. + * @param docPath The full path to the XML document. + * @param clazz The class associated with the schema resource. + * @param schemaResourceName The name of the schema resource. + * @return The WC3 DOM document object. + * @throws IOException + * @throws ParserConfigurationException + * @throws SAXException + */ + public static Document loadDocument(String docPath, Class clazz, String schemaResourceName) throws IOException, ParserConfigurationException, SAXException { + Document doc = loadDocument(docPath); + validateDocument(doc, clazz, schemaResourceName); + return doc; + } + + /** + * Loads an XML document into a WC3 DOM. + * + * @param docPath The full path to the XML document. + * @return The WC3 DOM document object. + * @throws ParserConfigurationException + * @throws SAXException + * @throws IOException + */ + public static Document loadDocument(String docPath) throws ParserConfigurationException, SAXException, IOException { + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + Document doc = builder.parse(new FileInputStream(docPath)); + return doc; + } + + /** + * Validates a WC3 DOM using a schema packaged as a class resource. + * + * @param doc + * @param clazz + * @param schemaResourceName + * @throws SAXException + * @throws IOException + */ + public static void validateDocument(final Document doc, Class clazz, String schemaResourceName) throws SAXException, IOException { + PlatformUtil.extractResourceToUserConfigDir(clazz, schemaResourceName, false); + File schemaFile = new File(Paths.get(PlatformUtil.getUserConfigDirectory(), schemaResourceName).toAbsolutePath().toString()); + SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + Schema schema = schemaFactory.newSchema(schemaFile); + Validator validator = schema.newValidator(); + validator.validate(new DOMSource(doc), new DOMResult()); + } + + /** + * Saves a WC3 DOM by writing it to an XML document. + * + * @param doc The WC3 DOM document object. + * @param docPath The full path to the XML document. + * @param encoding Encoding scheme to use for the XML document, e.g., + * "UTF-8." + * @throws TransformerConfigurationException + * @throws FileNotFoundException + * @throws UnsupportedEncodingException + * @throws TransformerException + * @throws IOException + */ + public static void saveDocument(final Document doc, String encoding, String docPath) throws TransformerConfigurationException, FileNotFoundException, UnsupportedEncodingException, TransformerException, IOException { + TransformerFactory xf = TransformerFactory.newInstance(); + xf.setAttribute("indent-number", 1); //NON-NLS + Transformer xformer = xf.newTransformer(); + xformer.setOutputProperty(OutputKeys.METHOD, "xml"); //NON-NLS + xformer.setOutputProperty(OutputKeys.INDENT, "yes"); //NON-NLS + xformer.setOutputProperty(OutputKeys.ENCODING, encoding); + xformer.setOutputProperty(OutputKeys.STANDALONE, "yes"); //NON-NLS + xformer.setOutputProperty(OutputKeys.VERSION, "1.0"); + File file = new File(docPath); + try (FileOutputStream stream = new FileOutputStream(file)) { + Result out = new StreamResult(new OutputStreamWriter(stream, encoding)); + xformer.transform(new DOMSource(doc), out); + stream.flush(); + } + } + /** * Utility to validate XML files against pre-defined schema files. * @@ -84,6 +167,7 @@ public class XMLUtil { * IngestModuleLoader. * */ + // RJCTODO: Deprecate. public static boolean xmlIsValid(DOMSource xmlfile, Class clazz, String schemaFile) { try { PlatformUtil.extractResourceToUserConfigDir(clazz, schemaFile, false); @@ -121,6 +205,7 @@ public class XMLUtil { * IngestModuleLoader. * */ + // RJCTODO: Deprecate. public static boolean xmlIsValid(Document doc, Class clazz, String type) { DOMSource dms = new DOMSource(doc); return xmlIsValid(dms, clazz, type); @@ -132,6 +217,7 @@ public class XMLUtil { * @param clazz the class this method is invoked from * @param xmlPath the full path to the file to load */ + // RJCTODO: Deprecate. public static Document loadDoc(Class clazz, String xmlPath) { DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); Document ret = null; @@ -165,39 +251,6 @@ public class XMLUtil { return ret; } - /** - * Loads an XML document into a WC3 DOM and validates it against a schema - * packaged as a class resource. - * - * @param The name of the class associated with the resource. - * @param clazz The class associated with the resource. - * @param docPath The full path to the XML document. - * @param schemaResourceName The name of the schema resource - * @return A WC3 DOM representation of the document - * @throws IOException - * @throws org.sleuthkit.autopsy.coreutils.XMLUtil.XmlUtilException - */ - public static Document loadAndValidateDoc(Class clazz, String docPath, String schemaResourceName) throws IOException, ParserConfigurationException, SAXException { - /** - * Parse the XML file into a DOM. - */ - DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = builderFactory.newDocumentBuilder(); - Document doc = builder.parse(new FileInputStream(docPath)); - - /** - * Extract the schema and validate the DOM. - */ - PlatformUtil.extractResourceToUserConfigDir(clazz, schemaResourceName, false); - File schemaFile = new File(Paths.get(PlatformUtil.getUserConfigDirectory(), schemaResourceName).toAbsolutePath().toString()); - SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); - Schema schema = schemaFactory.newSchema(schemaFile); - Validator validator = schema.newValidator(); - validator.validate(new DOMSource(doc), new DOMResult()); - - return doc; - } - /** * Saves XML files to disk * @@ -206,6 +259,7 @@ public class XMLUtil { * @param encoding to encoding, such as "UTF-8", to encode the file with * @param doc the document to save */ + // RJCTODO: Deprecate. public static boolean saveDoc(Class clazz, String xmlPath, String encoding, final Document doc) { TransformerFactory xf = TransformerFactory.newInstance(); xf.setAttribute("indent-number", 1); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java index e3b9908131..55639114ec 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java @@ -88,10 +88,11 @@ final class FileType { boolean alertOnMatch() { return this.alert; } - + /** - * Gets the interesting files set name assigned to this file type - * @return + * Gets the interesting files set name assigned to this file type. + * + * @return The files set name, possibly empty. */ String getFilesSetName() { return this.filesSetName; diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java index 70aebae4d5..178937ca56 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -44,19 +44,10 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane private static final String RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM = NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.signatureComboBox.rawItem"); private static final String ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM = NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.signatureComboBox.asciiItem"); - /** - * These two fields are used to synthesize default names for user-defined - * types. This is a thread-safe implementation. All interactions with - * instances of this panel should occur on the EDT, so this is defensive - * programming. - */ - private static final String DEFAULT_TYPE_NAME_BASE = "userdefined/userdefined"; //NON-NLS - private static final AtomicInteger defaultTypeNameCounter = new AtomicInteger(1); // RJCTODO: Need to save and init counter - /** * The list model for the file types list component of this panel is the set * of type names of the user-defined file types. A mapping of the file type - * names to file type objects completes the model. + * names to file type objects lies behind the list model. */ private DefaultListModel typesListModel; private Map fileTypes; @@ -70,24 +61,18 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane } /** - * Does child component initialization in addition to the the Matisse - * generated initialization. + * Does child component initialization in addition to that done by the + * Matisse generated code. */ private void customizeComponents() { - /** - * Make a model for the file types list component. - */ this.typesListModel = new DefaultListModel<>(); this.typesList.setModel(this.typesListModel); - /** - * Make a model for the signature type combo box component. - */ DefaultComboBoxModel sigTypeComboBoxModel = new DefaultComboBoxModel<>(); sigTypeComboBoxModel.addElement(FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM); sigTypeComboBoxModel.addElement(FileTypeIdGlobalSettingsPanel.ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM); this.signatureTypeComboBox.setModel(sigTypeComboBoxModel); - + this.filesSetNameTextField.setEnabled(false); } @@ -100,35 +85,20 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane } /** - * Populates the child components with file types obtained from the - * user-defined file types manager. + * @inheritDoc */ @Override public void load() { - /** - * Get the user-defined file types and set up a list model for the file - * types list component. - */ this.fileTypes = UserDefinedFileTypesManager.getInstance().getUserDefinedFileTypes(); this.setFileTypesListModel(); - - /** - * Add a selection listener to populate the file type details - * display/edit components. - */ this.typesList.addListSelectionListener(new TypesListSelectionListener()); - - /** - * If there is at least one user-defined file type, select it the file - * types list component. - */ if (!this.typesListModel.isEmpty()) { this.typesList.setSelectedIndex(0); } } /** - * Stores any changes to the user-defined types. + * @inheritDoc */ @Override public void store() { @@ -158,6 +128,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane FileTypeIdGlobalSettingsPanel.this.signatureTypeComboBox.setSelectedItem(sigType == FileType.Signature.Type.RAW ? FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM : FileTypeIdGlobalSettingsPanel.ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM); FileTypeIdGlobalSettingsPanel.this.offsetTextField.setText(Long.toString(signature.getOffset())); FileTypeIdGlobalSettingsPanel.this.postHitCheckBox.setSelected(fileType.alertOnMatch()); + FileTypeIdGlobalSettingsPanel.this.filesSetNameTextField.setText(fileType.getFilesSetName()); FileTypeIdGlobalSettingsPanel.this.deleteTypeButton.setEnabled(true); } } @@ -187,6 +158,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane this.signatureTextField.setText(""); //NON-NLS this.offsetTextField.setText(""); //NON-NLS this.postHitCheckBox.setSelected(false); + this.filesSetNameTextField.setText(""); } /** @@ -372,7 +344,6 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane private void newTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTypeButtonActionPerformed this.clearTypeDetailsComponents(); - this.mimeTypeTextField.setText(FileTypeIdGlobalSettingsPanel.DEFAULT_TYPE_NAME_BASE + FileTypeIdGlobalSettingsPanel.defaultTypeNameCounter.getAndIncrement()); }//GEN-LAST:event_newTypeButtonActionPerformed private void deleteTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTypeButtonActionPerformed @@ -429,16 +400,16 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane */ String filesSetName = this.filesSetNameTextField.getText(); if (this.postHitCheckBox.isSelected() && filesSetName.isEmpty()) { - JOptionPane.showMessageDialog(null, - NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message"), - NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.title"), - JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message"), + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.title"), + JOptionPane.ERROR_MESSAGE); } - + /** * Put it all together and reset the file types list component. */ - FileType.Signature signature = new FileType.Signature(signatureBytes, offset, sigType); // RJCTODO: + FileType.Signature signature = new FileType.Signature(signatureBytes, offset, sigType); FileType fileType = new FileType(typeName, signature, filesSetName, this.postHitCheckBox.isSelected()); this.fileTypes.put(typeName, fileType); this.setFileTypesListModel(); @@ -461,7 +432,6 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane this.filesSetNameTextField.setEnabled(this.postHitCheckBox.isSelected()); }//GEN-LAST:event_postHitCheckBoxActionPerformed - // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton deleteTypeButton; private javax.swing.JLabel filesSetNameLabel; diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.xsd b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.xsd index 16557dc422..47f658599a 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.xsd +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.xsd @@ -26,14 +26,7 @@ - - - - - - - - + @@ -41,7 +34,8 @@ - + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java index 2b46c4880d..65a7a447a2 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java @@ -5,7 +5,7 @@ * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this schemaFile except in compliance with 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 @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.modules.filetypeid; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.file.Path; @@ -34,17 +35,16 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import javax.xml.bind.DatatypeConverter; -import org.openide.util.Exceptions; +import javax.xml.transform.TransformerException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.XMLUtil; import org.sleuthkit.autopsy.modules.filetypeid.FileType.Signature; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; import org.xml.sax.SAXException; /** - * Manages user-defined schemaFile types characterized by MIME type, signature, - * and optional membership in an interesting files set. + * Manages user-defined file types characterized by MIME type, signature, and + * optional membership in an interesting files set. */ final class UserDefinedFileTypesManager { @@ -65,35 +65,34 @@ final class UserDefinedFileTypesManager { private static UserDefinedFileTypesManager instance; /** - * Predefined schemaFile types are stored in this mapping of MIME types to - * schemaFile types. Access to this map is guarded by the intrinsic lock of - * the user-defined schemaFile types manager for thread-safety. + * Predefined file types are stored in this mapping of MIME types to file + * types. Access to this map is guarded by the intrinsic lock of the + * user-defined file types manager for thread-safety. */ private final Map predefinedFileTypes = new HashMap<>(); /** - * User-defined schemaFile types to be persisted to the user-defined - * schemaFile type definitions schemaFile are stored in this mapping of - * schemaFile type names to schemaFile types. Access to this map is guarded - * by the intrinsic lock of the user-defined schemaFile types manager for - * thread-safety. + * File types to be persisted to the user-defined file type definitions file + * are stored in this mapping of MIME types to file types. Access to this + * map is guarded by the intrinsic lock of the user-defined file types + * manager for thread-safety. */ private final Map userDefinedFileTypes = new HashMap<>(); /** - * The combined set of user-defined schemaFile types and schemaFile types - * predefined by Autopsy are stored in this mapping of MIME types to - * schemaFile types. This is the current working set of schemaFile types. - * Access to this map is guarded by the intrinsic lock of the user-defined - * schemaFile types manager for thread-safety. + * The combined set of user-defined file types and file types predefined by + * Autopsy are stored in this mapping of MIME types to file types. This is + * the current working set of file types. Access to this map is guarded by + * the intrinsic lock of the user-defined file types manager for + * thread-safety. */ private final Map fileTypes = new HashMap<>(); - + /** - * Gets the manager of user-defined schemaFile types characterized by MIME - * type, signature, and optional membership in an interesting files set. + * Gets the manager of user-defined file types characterized by MIME type, + * signature, and optional membership in an interesting files set. * - * @return The user-defined schemaFile types manager singleton. + * @return The user-defined file types manager singleton. */ synchronized static UserDefinedFileTypesManager getInstance() { if (UserDefinedFileTypesManager.instance == null) { @@ -103,8 +102,8 @@ final class UserDefinedFileTypesManager { } /** - * Creates a manager of user-defined schemaFile types characterized by MIME - * type, signature, and optional membership in an interesting files set. + * Creates a manager of user-defined file types characterized by MIME type, + * signature, and optional membership in an interesting files set. */ private UserDefinedFileTypesManager() { /** @@ -116,11 +115,11 @@ final class UserDefinedFileTypesManager { } /** - * Adds the predefined schemaFile types to the in-memory mappings of MIME - * types to schemaFile types. + * Adds the predefined file types to the in-memory mappings of MIME types to + * file types. */ private void loadPredefinedFileTypes() { - // RJCTODO: Remove test schemaFile type. + // RJCTODO: Remove test file type. /** * Create a file type that should match $MBR in Small2 image. */ @@ -130,7 +129,7 @@ final class UserDefinedFileTypesManager { /** * Create a file type that should match test.txt in the Small2 image. */ - // RJCTODO: Remove test schemaFile type. + // RJCTODO: Remove test file type. try { fileType = new FileType("predefinedASCII", new Signature("hello".getBytes(UserDefinedFileTypesManager.ASCII_ENCODING), 0L, FileType.Signature.Type.ASCII), "predefinedASCII", true); this.addPredefinedFileType(fileType); @@ -150,7 +149,7 @@ final class UserDefinedFileTypesManager { // buf = buffer; // } // -// // the xml detection in Tika tries to parse the entire schemaFile and throws exceptions +// // the xml detection in Tika tries to parse the entire file and throws exceptions // // for files that are not valid XML // try { // String tagHeader = new String(buf, 0, 5); @@ -173,10 +172,10 @@ final class UserDefinedFileTypesManager { } /** - * Adds a schemaFile type to the the predefined schemaFile types and - * combined schemaFile types maps. + * Adds a predefined file type to the in-memory mappings of MIME types to + * file types. * - * @param fileType The schemaFile type to add. + * @param fileType The file type to add. */ private void addPredefinedFileType(FileType fileType) { this.predefinedFileTypes.put(fileType.getMimeType(), fileType); @@ -184,15 +183,15 @@ final class UserDefinedFileTypesManager { } /** - * Adds the user-defined schemaFile types to the in-memory mappings of MIME - * types to schemaFile types. + * Adds the user-defined file types to the in-memory mappings of MIME types + * to file types. */ private void loadUserDefinedFileTypes() { try { String filePath = getFileTypeDefinitionsFilePath(UserDefinedFileTypesManager.USER_DEFINED_TYPE_DEFINITIONS_FILE); File file = new File(filePath); if (file.exists() && file.canRead()) { - for (FileType fileType : XMLReader.readFileTypes(filePath)) { + for (FileType fileType : XmlReader.readFileTypes(filePath)) { this.addUserDefinedFileType(fileType); } } @@ -204,14 +203,14 @@ final class UserDefinedFileTypesManager { UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Unable to load user-defined types", ex); //NON-NLS this.fileTypes.clear(); this.userDefinedFileTypes.clear(); - } + } } /** - * Adds a schemaFile type to the the user-defined schemaFile types and - * combined schemaFile types maps. + * Adds a user-defined file type to the in-memory mappings of MIME types to + * file types. * - * @param fileType The schemaFile type to add. + * @param fileType The file type to add. */ private void addUserDefinedFileType(FileType fileType) { this.userDefinedFileTypes.put(fileType.getMimeType(), fileType); @@ -219,10 +218,9 @@ final class UserDefinedFileTypesManager { } /** - * Gets both the predefined and the user-defined schemaFile types. + * Gets both the predefined and the user-defined file types. * - * @return A mapping of schemaFile type names to schemaFile types, possibly - * empty. + * @return A mapping of file type names to file types, possibly empty. */ synchronized Map getFileTypes() { /** @@ -233,10 +231,9 @@ final class UserDefinedFileTypesManager { } /** - * Gets the user-defined schemaFile types. + * Gets the user-defined file types. * - * @return A mapping of schemaFile type names to schemaFile types, possibly - * empty. + * @return A mapping of file type names to file types, possibly empty. */ synchronized Map getUserDefinedFileTypes() { /** @@ -247,22 +244,20 @@ final class UserDefinedFileTypesManager { } /** - * Sets the user-defined schemaFile types. + * Sets the user-defined file types. * - * @param newFileTypes A mapping of schemaFile type names to user-defined - * schemaFile types. - * @throws - * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException + * @param newFileTypes A mapping of file type names to user-defined file + * types. */ synchronized void setUserDefinedFileTypes(Map newFileTypes) throws UserDefinedFileTypesManager.UserDefinedFileTypesException { try { - /** - * Persist the user-defined file type definitions. - */ String filePath = UserDefinedFileTypesManager.getFileTypeDefinitionsFilePath(UserDefinedFileTypesManager.USER_DEFINED_TYPE_DEFINITIONS_FILE); - UserDefinedFileTypesManager.XMLWriter.writeFileTypes(newFileTypes.values(), filePath); + UserDefinedFileTypesManager.XmlWriter.writeFileTypes(newFileTypes.values(), filePath); - } catch (ParserConfigurationException | IOException ex) { + } catch (ParserConfigurationException | FileNotFoundException | UnsupportedEncodingException | TransformerException ex) { + UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Failed to write file types file", ex); + throw new UserDefinedFileTypesManager.UserDefinedFileTypesException(ex.getLocalizedMessage()); // RJCTODO: Create a bundled message + } catch (IOException ex) { UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Failed to write file types file", ex); throw new UserDefinedFileTypesManager.UserDefinedFileTypesException(ex.getLocalizedMessage()); // RJCTODO: Create a bundled message } @@ -286,10 +281,10 @@ final class UserDefinedFileTypesManager { } /** - * Gets the absolute path of a schemaFile type definitions schemaFile. + * Gets the absolute path of a file type definitions file. * - * @param fileName The name of the schemaFile. - * @return The absolute path to the schemaFile. + * @param fileName The name of the file. + * @return The absolute path to the file. */ private static String getFileTypeDefinitionsFilePath(String fileName) { Path filePath = Paths.get(PlatformUtil.getUserConfigDirectory(), fileName); @@ -297,109 +292,133 @@ final class UserDefinedFileTypesManager { } /** - * Provides a mechanism for writing a set of schemaFile type definitions to - * an XML schemaFile. + * Provides a mechanism for writing a set of file type definitions to an XML + * file. */ - private static class XMLWriter { + private static class XmlWriter { /** - * Writes a set of schemaFile type definitions to an XML schemaFile. + * Writes a set of file type definitions to an XML file. * - * @param signatures A collection of schemaFile types. - * @param filePath The path to the destination schemaFile. + * @param fileTypes A collection of file types. + * @param filePath The path to the destination file. + * @throws ParserConfigurationException + * @throws IOException + * @throws FileNotFoundException + * @throws UnsupportedEncodingException + * @throws TransformerException */ - private static void writeFileTypes(Collection fileTypes, String filePath) throws ParserConfigurationException, IOException { - Document doc = XMLUtil.createDoc(); + private static void writeFileTypes(Collection fileTypes, String filePath) throws ParserConfigurationException, IOException, FileNotFoundException, UnsupportedEncodingException, TransformerException { + Document doc = XMLUtil.createDocument(); Element fileTypesElem = doc.createElement(UserDefinedFileTypesManager.FILE_TYPES_TAG_NAME); doc.appendChild(fileTypesElem); for (FileType fileType : fileTypes) { - Element fileTypeElem = UserDefinedFileTypesManager.XMLWriter.createFileTypeElement(fileType, doc); + Element fileTypeElem = UserDefinedFileTypesManager.XmlWriter.createFileTypeElement(fileType, doc); fileTypesElem.appendChild(fileTypeElem); } - if (!XMLUtil.saveDoc(HashDbManager.class, filePath, UserDefinedFileTypesManager.ENCODING_FOR_XML_FILE, doc)) { - // RJCTODO: If time permits add XMLUtil that properly throws and deprecate this one - throw new IOException("Error saving user defined file types, see log for details"); //NON-NLS - } + XMLUtil.saveDocument(doc, UserDefinedFileTypesManager.ENCODING_FOR_XML_FILE, filePath); } /** - * Creates an XML representation of a schemaFile type. + * Creates an XML representation of a file type. * - * @param fileType The schemaFile type object. - * @param doc The DOM document to use to create the XML. + * @param fileType The file type object. + * @param doc The WC3 DOM object to use to create the XML. * @return An XML element. */ private static Element createFileTypeElement(FileType fileType, Document doc) { - /** - * Create a file type element. - */ Element fileTypeElem = doc.createElement(UserDefinedFileTypesManager.FILE_TYPE_TAG_NAME); + XmlWriter.addMimeTypeElement(fileType, fileTypeElem, doc); + XmlWriter.addSignatureElement(fileType, fileTypeElem, doc); + XmlWriter.addInterestingFilesSetElement(fileType, fileTypeElem, doc); + XmlWriter.addAlertAttribute(fileType, fileTypeElem); + return fileTypeElem; + } - /** - * Add a MIME type name child element. - */ + /** + * Add a MIME type child element to a file type XML element. + * + * @param fileType The file type to use as a content source. + * @param fileTypeElem The parent file type element. + * @param doc The WC3 DOM object to use to create the XML. + */ + private static void addMimeTypeElement(FileType fileType, Element fileTypeElem, Document doc) { Element typeNameElem = doc.createElement(UserDefinedFileTypesManager.MIME_TYPE_TAG_NAME); typeNameElem.setTextContent(fileType.getMimeType()); fileTypeElem.appendChild(typeNameElem); + } - /** - * Add a signature child element with a type attribute. - */ + /** + * Add a signature child element to a file type XML element. + * + * @param fileType The file type to use as a content source. + * @param fileTypeElem The parent file type element. + * @param doc The WC3 DOM object to use to create the XML. + */ + private static void addSignatureElement(FileType fileType, Element fileTypeElem, Document doc) { Signature signature = fileType.getSignature(); Element signatureElem = doc.createElement(UserDefinedFileTypesManager.SIGNATURE_TAG_NAME); - signatureElem.setAttribute(UserDefinedFileTypesManager.SIGNATURE_TYPE_ATTRIBUTE, signature.getType().toString()); - fileTypeElem.appendChild(signatureElem); - /** - * Add a bytes child element to the signature element. - */ Element bytesElem = doc.createElement(UserDefinedFileTypesManager.BYTES_TAG_NAME); bytesElem.setTextContent(DatatypeConverter.printHexBinary(signature.getSignatureBytes())); signatureElem.appendChild(bytesElem); - /** - * Add an offset child element to the signature element. - */ Element offsetElem = doc.createElement(UserDefinedFileTypesManager.OFFSET_TAG_NAME); offsetElem.setTextContent(DatatypeConverter.printLong(signature.getOffset())); signatureElem.appendChild(offsetElem); - /** - * Add a files set child element with an alert attribute. - */ + signatureElem.setAttribute(UserDefinedFileTypesManager.SIGNATURE_TYPE_ATTRIBUTE, signature.getType().toString()); + fileTypeElem.appendChild(signatureElem); + } + + /** + * Add an interesting files set element to a file type XML element. + * + * @param fileType The file type to use as a content source. + * @param fileTypeElem The parent file type element. + * @param doc The WC3 DOM object to use to create the XML. + */ + private static void addInterestingFilesSetElement(FileType fileType, Element fileTypeElem, Document doc) { Element filesSetElem = doc.createElement(UserDefinedFileTypesManager.INTERESTING_FILES_SET_TAG_NAME); filesSetElem.setTextContent(fileType.getFilesSetName()); - filesSetElem.setAttribute(UserDefinedFileTypesManager.ALERT_ATTRIBUTE, Boolean.toString(fileType.alertOnMatch())); fileTypeElem.appendChild(filesSetElem); - - return fileTypeElem; } + + /** + * Add an alert attribute to a file type XML element. + * + * @param fileType The file type to use as a content source. + * @param fileTypeElem The parent file type element. + */ + private static void addAlertAttribute(FileType fileType, Element fileTypeElem) { + fileTypeElem.setAttribute(UserDefinedFileTypesManager.ALERT_ATTRIBUTE, Boolean.toString(fileType.alertOnMatch())); + } + } /** - * Provides a mechanism for reading a set of schemaFile type definitions - * from an XML schemaFile. + * Provides a mechanism for reading a set of file type definitions from an + * XML file. */ - private static class XMLReader { + private static class XmlReader { /** - * Reads a set of schemaFile type definitions from an XML schemaFile. + * Reads a set of file type definitions from an XML file. * - * @param filePath The path to the XML schemaFile. - * @return A collection of schemaFile types read from the XML - * schemaFile. + * @param filePath The path to the XML file. + * @return A collection of file types read from the XML file. */ private static List readFileTypes(String filePath) throws IOException, ParserConfigurationException, SAXException { List fileTypes = new ArrayList<>(); Path schemaFilePath = Paths.get(PlatformUtil.getUserConfigDirectory(), UserDefinedFileTypesManager.FILE_TYPE_DEFINITIONS_SCHEMA_FILE); - Document doc = XMLUtil.loadAndValidateDoc(UserDefinedFileTypesManager.XMLReader.class, filePath, schemaFilePath.toAbsolutePath().toString()); + Document doc = XMLUtil.loadDocument(filePath, UserDefinedFileTypesManager.XmlReader.class, schemaFilePath.toAbsolutePath().toString()); if (doc != null) { Element fileTypesElem = doc.getDocumentElement(); if (fileTypesElem != null && fileTypesElem.getNodeName().equals(UserDefinedFileTypesManager.FILE_TYPES_TAG_NAME)) { NodeList fileTypeElems = fileTypesElem.getElementsByTagName(UserDefinedFileTypesManager.FILE_TYPE_TAG_NAME); for (int i = 0; i < fileTypeElems.getLength(); ++i) { Element fileTypeElem = (Element) fileTypeElems.item(i); - FileType fileType = UserDefinedFileTypesManager.XMLReader.parseFileType(fileTypeElem); + FileType fileType = XmlReader.parseFileType(fileTypeElem); fileTypes.add(fileType); } } @@ -408,94 +427,99 @@ final class UserDefinedFileTypesManager { } /** - * Parse a schemaFile type definition from a schemaFile type XML - * element. + * Gets a file type definition from a file type XML element. * * @param fileTypeElem The XML element. - * @return A schemaFile type object. - * @throws + * @return A file type object. + * @throws IllegalArgumentException + * @throws NumberFormatException */ private static FileType parseFileType(Element fileTypeElem) throws IllegalArgumentException, NumberFormatException { - /** - * Get the mime type child element. - */ - String mimeType = UserDefinedFileTypesManager.getChildElementTextContent(fileTypeElem, UserDefinedFileTypesManager.MIME_TYPE_TAG_NAME); + String mimeType = XmlReader.parseMimeType(fileTypeElem); + Signature signature = XmlReader.parseSignature(fileTypeElem); + String filesSetName = XmlReader.parseInterestingFilesSet(fileTypeElem); + boolean alert = XmlReader.parseAlert(fileTypeElem); + return new FileType(mimeType, signature, filesSetName, alert); + } - /** - * Get the signature child element. - */ + /** + * Gets the MIME type from a file type XML element. + * + * @param fileTypeElem The element + * @return A MIME type string. + */ + private static String parseMimeType(Element fileTypeElem) { + return getChildElementTextContent(fileTypeElem, UserDefinedFileTypesManager.MIME_TYPE_TAG_NAME); + } + + /** + * Gets the signature from a file type XML element. + * + * @param fileTypeElem The XML element. + * @return The signature. + */ + private static Signature parseSignature(Element fileTypeElem) throws IllegalArgumentException, NumberFormatException { NodeList signatureElems = fileTypeElem.getElementsByTagName(UserDefinedFileTypesManager.SIGNATURE_TAG_NAME); Element signatureElem = (Element) signatureElems.item(0); - /** - * Get the signature (interpretation) type attribute from the - * signature child element. - */ String sigTypeAttribute = signatureElem.getAttribute(UserDefinedFileTypesManager.SIGNATURE_TYPE_ATTRIBUTE); Signature.Type signatureType = Signature.Type.valueOf(sigTypeAttribute); - /** - * Get the signature bytes. - */ - String sigBytesString = UserDefinedFileTypesManager.getChildElementTextContent(signatureElem, UserDefinedFileTypesManager.BYTES_TAG_NAME); + String sigBytesString = getChildElementTextContent(signatureElem, UserDefinedFileTypesManager.BYTES_TAG_NAME); byte[] signatureBytes = DatatypeConverter.parseHexBinary(sigBytesString); - /** - * Get the offset. - */ - String offsetString = UserDefinedFileTypesManager.getChildElementTextContent(signatureElem, UserDefinedFileTypesManager.OFFSET_TAG_NAME); + String offsetString = getChildElementTextContent(signatureElem, UserDefinedFileTypesManager.OFFSET_TAG_NAME); long offset = DatatypeConverter.parseLong(offsetString); - /** - * Get the interesting files set element. - */ + return new Signature(signatureBytes, offset, signatureType); + } + + /** + * Gets the interesting files set name from a file type XML element. + * + * @param fileTypeElem The XML element. + * @return The files set name, possibly empty. + */ + private static String parseInterestingFilesSet(Element fileTypeElem) { + String filesSetName = ""; NodeList filesSetElems = fileTypeElem.getElementsByTagName(UserDefinedFileTypesManager.INTERESTING_FILES_SET_TAG_NAME); - Element filesSetElem = (Element) filesSetElems.item(0); - String filesSetName = filesSetElem.getTextContent(); - - /** - * Get the alert attribute from the interesting files set element. - */ - String alertAttribute = filesSetElem.getAttribute(UserDefinedFileTypesManager.ALERT_ATTRIBUTE); - boolean alert = Boolean.parseBoolean(alertAttribute); - - /** - * Put it all together. - */ - Signature signature = new Signature(signatureBytes, offset, signatureType); - return new FileType(mimeType, signature, filesSetName, alert); + if (filesSetElems.getLength() > 0) { + Element filesSetElem = (Element) filesSetElems.item(0); + filesSetName = filesSetElem.getTextContent(); + } + return filesSetName; } - } - /** - * Gets the text content of a single child element. Assumes the elements - * have already been validated. - * - * @param elem The parent element. - * @param tagName The tag name of the child element. - * @return The text content. - */ - private static String getChildElementTextContent(Element elem, String tagName) { - NodeList childElems = elem.getElementsByTagName(tagName); - Element childElem = (Element) childElems.item(0); - return childElem.getTextContent(); - } - - /** - * Used for throwing exceptions when parsing user-defined types XML elements - * and attributes. - */ - private static class InvalidXMLException extends Exception { - - InvalidXMLException(String message) { - super(message); + /** + * Gets the alert attribute from a file type XML element. + * + * @param fileTypeElem The XML element. + * @return True or false; + */ + private static boolean parseAlert(Element fileTypeElem) { + String alertAttribute = fileTypeElem.getAttribute(UserDefinedFileTypesManager.ALERT_ATTRIBUTE); + return Boolean.parseBoolean(alertAttribute); } + + /** + * Gets the text content of a single child element. + * + * @param elem The parent element. + * @param tagName The tag name of the child element. + * @return The text content. + */ + private static String getChildElementTextContent(Element elem, String tagName) { + NodeList childElems = elem.getElementsByTagName(tagName); + Element childElem = (Element) childElems.item(0); + return childElem.getTextContent(); + } + } /** * Used to translate more implementation-details-specific exceptions (which * are logged by this class) into more generic exceptions for propagation to - * clients of the user-defined schemaFile types manager. + * clients of the user-defined file types manager. */ static class UserDefinedFileTypesException extends Exception { From 86e9ba0692476cff5657a92d5722ffbf12f53c56 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 18 Dec 2014 22:45:34 -0500 Subject: [PATCH 18/27] Continue to work on user-defined file types --- .../modules/filetypeid/Bundle.properties | 1 + .../FileTypeIdGlobalSettingsPanel.java | 37 +++++++++++++------ .../filetypeid/FileTypeIdIngestModule.java | 34 ++++++++++++----- 3 files changed, 51 insertions(+), 21 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties index 2f55fc8fb8..e81c0f9e02 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties @@ -33,3 +33,4 @@ FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignatureBytes.message=The sign FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignatureBytes.title=Invalid Signature FileTypeIdGlobalSettingsPanel.filesSetNameLabel.text=Files Set Name FileTypeIdGlobalSettingsPanel.filesSetNameTextField.text= +FileTypeIdGlobalSettingsPanel.JOptionPane.storeFailed.title=Save Failed diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java index 178937ca56..754d52b888 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -22,7 +22,6 @@ import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultListModel; import javax.swing.JOptionPane; @@ -46,8 +45,9 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane /** * The list model for the file types list component of this panel is the set - * of type names of the user-defined file types. A mapping of the file type - * names to file type objects lies behind the list model. + * of MIME types associated with the user-defined file types. A mapping of + * the MIME types to file type objects lies behind the list model. This map + * is obtained from the user-defined types manager. */ private DefaultListModel typesListModel; private Map fileTypes; @@ -73,6 +73,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane sigTypeComboBoxModel.addElement(FileTypeIdGlobalSettingsPanel.ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM); this.signatureTypeComboBox.setModel(sigTypeComboBoxModel); + this.postHitCheckBox.setSelected(false); this.filesSetNameTextField.setEnabled(false); } @@ -105,7 +106,10 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane try { UserDefinedFileTypesManager.getInstance().setUserDefinedFileTypes(this.fileTypes); } catch (UserDefinedFileTypesManager.UserDefinedFileTypesException ex) { - // RJCTODO + JOptionPane.showMessageDialog(null, + ex.getLocalizedMessage(), + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.storeFailed.title"), + JOptionPane.ERROR_MESSAGE); } } @@ -120,10 +124,10 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane if (FileTypeIdGlobalSettingsPanel.this.typesList.getSelectedIndex() == -1) { FileTypeIdGlobalSettingsPanel.this.deleteTypeButton.setEnabled(false); } else { - String typeName = FileTypeIdGlobalSettingsPanel.this.typesList.getSelectedValue(); - FileType fileType = FileTypeIdGlobalSettingsPanel.this.fileTypes.get(typeName); + String mimeType = FileTypeIdGlobalSettingsPanel.this.typesList.getSelectedValue(); + FileType fileType = FileTypeIdGlobalSettingsPanel.this.fileTypes.get(mimeType); Signature signature = fileType.getSignature(); - FileTypeIdGlobalSettingsPanel.this.mimeTypeTextField.setText(typeName); + FileTypeIdGlobalSettingsPanel.this.mimeTypeTextField.setText(mimeType); FileType.Signature.Type sigType = fileType.getSignature().getType(); FileTypeIdGlobalSettingsPanel.this.signatureTypeComboBox.setSelectedItem(sigType == FileType.Signature.Type.RAW ? FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM : FileTypeIdGlobalSettingsPanel.ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM); FileTypeIdGlobalSettingsPanel.this.offsetTextField.setText(Long.toString(signature.getOffset())); @@ -139,11 +143,11 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane * Sets the list model for the file types list component. */ private void setFileTypesListModel() { - ArrayList typeNames = new ArrayList(this.fileTypes.keySet()); - Collections.sort(typeNames); + ArrayList mimeTypes = new ArrayList(this.fileTypes.keySet()); + Collections.sort(mimeTypes); this.typesListModel.clear(); - for (String typeName : typeNames) { - this.typesListModel.addElement(typeName); + for (String mimeType : mimeTypes) { + this.typesListModel.addElement(mimeType); } } @@ -393,7 +397,16 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane /** * Get the offset. */ - long offset = Long.parseUnsignedLong(this.offsetTextField.getText()); + long offset; + try { + offset = Long.parseUnsignedLong(this.offsetTextField.getText()); + } catch (NumberFormatException ex) { + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message"), + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.title"), + JOptionPane.ERROR_MESSAGE); + return; + } /** * Get the interesting files set details. diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java index df575fe18d..577e01aca6 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java @@ -32,6 +32,8 @@ import org.sleuthkit.datamodel.TskData.FileKnown; import org.sleuthkit.datamodel.TskException; import org.sleuthkit.autopsy.ingest.IngestModule.ProcessResult; import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardAttribute; /** * Detects the type of a file based on signature (magic) values. Posts results @@ -45,6 +47,7 @@ public class FileTypeIdIngestModule implements FileIngestModule { private long jobId; private static final HashMap totalsForIngestJobs = new HashMap<>(); private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter(); + private final UserDefinedFileTypeIdentifier userDefinedFileTypeIdentifier; private final TikaFileTypeDetector tikaDetector = new TikaFileTypeDetector(); /** @@ -72,6 +75,7 @@ public class FileTypeIdIngestModule implements FileIngestModule { */ FileTypeIdIngestModule(FileTypeIdModuleSettings settings) { this.settings = settings; + this.userDefinedFileTypeIdentifier = new UserDefinedFileTypeIdentifier(); } /** @@ -87,12 +91,12 @@ public class FileTypeIdIngestModule implements FileIngestModule { * @inheritDoc */ @Override - public ProcessResult process(AbstractFile abstractFile) { + public ProcessResult process(AbstractFile file) { /** * Skip unallocated space and unused blocks files. */ - if ((abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) - || (abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)) { + if ((file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) + || (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)) { return ProcessResult.OK; } @@ -100,7 +104,7 @@ public class FileTypeIdIngestModule implements FileIngestModule { /** * Skip known files if configured to do so. */ - if (settings.skipKnownFiles() && (abstractFile.getKnown() == FileKnown.KNOWN)) { + if (settings.skipKnownFiles() && (file.getKnown() == FileKnown.KNOWN)) { return ProcessResult.OK; } @@ -108,18 +112,30 @@ public class FileTypeIdIngestModule implements FileIngestModule { * Filter out very small files to minimize false positives. */ // RJCTODO: Make this size a setting - if (abstractFile.getSize() < MIN_FILE_SIZE) { + if (file.getSize() < MIN_FILE_SIZE) { return ProcessResult.OK; } try { long startTime = System.currentTimeMillis(); + FileType fileType = this.userDefinedFileTypeIdentifier.identify(file); + if (null != fileType) { + BlackboardArtifact getInfoArtifact = file.getGenInfoArtifact(); + BlackboardAttribute typeAttr = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG.getTypeID(), FileTypeIdModuleFactory.getModuleName(), fileType.getMimeType()); + getInfoArtifact.addAttribute(typeAttr); - // RJCTODO: Add code here to use nay user-defined signstures first; - // if there is a match, post a intersting file hit, if the user has - // elected alerts - tikaDetector.detectAndSave(abstractFile); + if (fileType.alertOnMatch()) { + String moduleName = FileTypeIdModuleFactory.getModuleName(); + BlackboardArtifact artifact = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); + BlackboardAttribute setNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(), moduleName, fileType.getFilesSetName()); + artifact.addAttribute(setNameAttribute); + BlackboardAttribute ruleNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY.getTypeID(), moduleName, fileType.getMimeType()); + artifact.addAttribute(ruleNameAttribute); + } + } else { + tikaDetector.detectAndSave(file); + } addToTotals(jobId, (System.currentTimeMillis() - startTime)); return ProcessResult.OK; } catch (TskException ex) { From fe64bac2397169ae62043729dbb7e1217f8b3b55 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 19 Dec 2014 17:04:21 -0500 Subject: [PATCH 19/27] Improve user-defined file types UI --- .../sleuthkit/autopsy/casemodule/Case.java | 2 +- .../modules/filetypeid/Bundle.properties | 3 +- .../autopsy/modules/filetypeid/FileType.java | 34 +- .../FileTypeIdGlobalSettingsPanel.form | 120 +++--- .../FileTypeIdGlobalSettingsPanel.java | 403 ++++++++++++------ .../filetypeid/FileTypeIdModuleFactory.java | 13 +- .../FileTypeIdOptionsPanelController.java | 3 +- .../UserDefinedFileTypesManager.java | 14 +- .../autopsy/modules/filetypeid/warning16.png | Bin 0 -> 552 bytes 9 files changed, 382 insertions(+), 210 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/modules/filetypeid/warning16.png diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index cb409ad7c7..69c9034c15 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -167,7 +167,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * * @throws IllegalStateException if there is no case open. */ - public static Case getCurrentCase() { + public static Case getCurrentCase() throws IllegalStateException { if (currentCase != null) { return currentCase; } else { diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties index e81c0f9e02..fbf61da330 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties @@ -15,7 +15,6 @@ FileTypeIdGlobalSettingsPanel.offsetTextField.text= FileTypeIdGlobalSettingsPanel.offsetLabel.text=Offset FileTypeIdGlobalSettingsPanel.postHitCheckBox.text=Post interesting file hit when found FileTypeIdGlobalSettingsPanel.signatureTextField.text= -FileTypeIdGlobalSettingsPanel.jTextArea1.text=Enter a MIME type and signature to be used to identify files of that type. If the signature is a byte sequence, enter the sequence using two hex values for each byte, e.g., EEF0 is a two byte signature. FileTypeIdGlobalSettingsPanel.signatureTypeLabel.text=Signature Type FileTypeIdGlobalSettingsPanel.mimeTypeTextField.text= FileTypeIdGlobalSettingsPanel.signatureLabel.text=Signature @@ -34,3 +33,5 @@ FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignatureBytes.title=Invalid Si FileTypeIdGlobalSettingsPanel.filesSetNameLabel.text=Files Set Name FileTypeIdGlobalSettingsPanel.filesSetNameTextField.text= FileTypeIdGlobalSettingsPanel.JOptionPane.storeFailed.title=Save Failed +FileTypeIdGlobalSettingsPanel.hintTextArea.text=Enter a MIME type and signature to be used to identify files of that type. If the signature is a byte sequence, enter the sequence using two hex values for each byte, e.g., EEF0 is a two byte signature. +FileTypeIdGlobalSettingsPanel.ingestRunningWarningLabel.text=Cannot make changes to file type definitions when ingest is running diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java index 55639114ec..513eff58b3 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java @@ -25,36 +25,39 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; /** - * Represents a named file type characterized by a file signature. + * Represents a file type characterized by a file signature. + *

+ * Thread-safe. */ final class FileType { private final String mimeType; private final Signature signature; - private final String filesSetName; + private final String interestingFilesSetName; private final boolean alert; /** - * Creates a representation of a named file type characterized by a file + * Creates a representation of a file type characterized by a file * signature. * * @param mimeType The mime type to associate with this file type. * @param signature The signature that characterizes the file type. - * @param filesSetName The interesting files set name - * @param alert A flag indicating whether the user wishes to be alerted when - * a file matching this type is encountered. + * @param filesSetName The name of an interesting files set that includes + * files of this type. + * @param alert Whether the user wishes to be alerted when a file matching + * this type is encountered. */ FileType(String mimeType, final Signature signature, String filesSetName, boolean alert) { this.mimeType = mimeType; this.signature = new Signature(signature.getSignatureBytes(), signature.getOffset(), signature.getType()); - this.filesSetName = filesSetName; + this.interestingFilesSetName = filesSetName; this.alert = alert; } /** * Gets the MIME type associated with this file type. * - * @return The type name. + * @return The MIME type. */ String getMimeType() { return this.mimeType; @@ -63,14 +66,14 @@ final class FileType { /** * Gets the signature associated with this file type. * - * @return The file signature. + * @return The signature. */ Signature getSignature() { return new Signature(this.signature.getSignatureBytes(), this.signature.getOffset(), this.signature.getType()); } /** - * Determines whether or not a given file is an instance of this file type. + * Determines whether or not a file is an instance of this file type. * * @param file The file to test. * @return True or false. @@ -90,17 +93,20 @@ final class FileType { } /** - * Gets the interesting files set name assigned to this file type. + * Gets the name of an interesting files set that includes files of this + * type. * - * @return The files set name, possibly empty. + * @return The interesting files set name, possibly empty. */ String getFilesSetName() { - return this.filesSetName; + return this.interestingFilesSetName; } /** * A file signature consisting of a sequence of bytes at a specific offset * within a file. + *

+ * Thread-safe. */ static final class Signature { @@ -170,7 +176,7 @@ final class FileType { boolean containedIn(final AbstractFile file) { try { byte[] buffer = new byte[this.signatureBytes.length]; - int bytesRead = file.read(buffer, offset, this.signatureBytes.length); + int bytesRead = file.read(buffer, this.offset, this.signatureBytes.length); return ((bytesRead == this.signatureBytes.length) && (Arrays.equals(buffer, this.signatureBytes))); } catch (TskCoreException ex) { Signature.logger.log(Level.WARNING, "Error reading from file with objId = " + file.getId(), ex); diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form index a4615bbc52..8c04fa7747 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form @@ -20,55 +20,64 @@ - - + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + - - - - - + + + - - - - - - - + - - - - @@ -77,9 +86,9 @@ - + - + @@ -120,7 +129,9 @@ - + + + @@ -145,7 +156,7 @@ - + @@ -235,6 +246,9 @@ + + + @@ -246,14 +260,14 @@ - + - + @@ -263,7 +277,7 @@ - + @@ -294,5 +308,15 @@ + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java index 754d52b888..b5ca9abc62 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -18,6 +18,9 @@ */ package org.sleuthkit.autopsy.modules.filetypeid; +import java.awt.EventQueue; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; @@ -25,11 +28,14 @@ import java.util.Map; import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultListModel; import javax.swing.JOptionPane; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.xml.bind.DatatypeConverter; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; +import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; import org.sleuthkit.autopsy.modules.filetypeid.FileType.Signature; @@ -56,8 +62,9 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane * Creates a panel to allow a user to make custom file type definitions. */ FileTypeIdGlobalSettingsPanel() { - this.initComponents(); - this.customizeComponents(); + initComponents(); + customizeComponents(); + addIngestJobEventsListener(); } /** @@ -65,24 +72,113 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane * Matisse generated code. */ private void customizeComponents() { - this.typesListModel = new DefaultListModel<>(); - this.typesList.setModel(this.typesListModel); - - DefaultComboBoxModel sigTypeComboBoxModel = new DefaultComboBoxModel<>(); - sigTypeComboBoxModel.addElement(FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM); - sigTypeComboBoxModel.addElement(FileTypeIdGlobalSettingsPanel.ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM); - this.signatureTypeComboBox.setModel(sigTypeComboBoxModel); - - this.postHitCheckBox.setSelected(false); - this.filesSetNameTextField.setEnabled(false); + setFileTypesListModel(); + setSignatureTypeComboBoxModel(); + clearTypeDetailsComponents(); + addTypeListSelectionListener(); + addTextFieldListeners(); } /** - * @inheritDoc + * Sets the list model for the list of file types. */ - @Override - public void saveSettings() { - this.store(); + private void setFileTypesListModel() { + typesListModel = new DefaultListModel<>(); + typesList.setModel(typesListModel); + } + + /** + * Sets the model for the signature type combo box. + */ + private void setSignatureTypeComboBoxModel() { + DefaultComboBoxModel sigTypeComboBoxModel = new DefaultComboBoxModel<>(); + sigTypeComboBoxModel.addElement(FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM); + sigTypeComboBoxModel.addElement(FileTypeIdGlobalSettingsPanel.ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM); + signatureTypeComboBox.setModel(sigTypeComboBoxModel); + signatureTypeComboBox.setSelectedItem(FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM); + } + + private void addTypeListSelectionListener() { + typesList.addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + if (e.getValueIsAdjusting() == false) { + if (typesList.getSelectedIndex() == -1) { + clearTypeDetailsComponents(); + } else { + populateTypeDetailsComponents(); + } + } + } + }); + } + + /** + * Adds listeners to the text fields that enable and disable the buttons on + * the panel. + */ + private void addTextFieldListeners() { + DocumentListener listener = new DocumentListener() { + @Override + public void changedUpdate(DocumentEvent e) { + enableButtons(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + enableButtons(); + } + + @Override + public void insertUpdate(DocumentEvent e) { + enableButtons(); + } + }; + + mimeTypeTextField.getDocument().addDocumentListener(listener); + offsetTextField.getDocument().addDocumentListener(listener); + signatureTextField.getDocument().addDocumentListener(listener); + } + + /** + * Add a property change listener that listens to ingest job events to + * disable the buttons on the panel if ingest is running. This is done to + * prevent changes to user-defined types while the type definitions are in + * use. the components in sync with file ingest. + */ + private void addIngestJobEventsListener() { + IngestManager.getInstance().addIngestJobEventListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + enableButtons(); + } + }); + } + }); + } + + /** + * Enables or disables the panel buttons based on the state of the panel and + * the application. + */ + private void enableButtons() { + boolean ingestIsRunning = IngestManager.getInstance().isIngestRunning(); + newTypeButton.setEnabled(!ingestIsRunning); + + boolean fileTypeIsSelected = typesList.getSelectedIndex() != -1; + deleteTypeButton.setEnabled(!ingestIsRunning && fileTypeIsSelected); + + boolean requiredFieldsPopulated + = !mimeTypeTextField.getText().isEmpty() + && !offsetTextField.getText().isEmpty() + && !signatureTextField.getText().isEmpty() + && postHitCheckBox.isSelected() ? !filesSetNameTextField.getText().isEmpty() : true; + saveTypeButton.setEnabled(!ingestIsRunning && fileTypeIsSelected && requiredFieldsPopulated); + + ingestRunningWarningLabel.setVisible(ingestIsRunning); } /** @@ -90,12 +186,59 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane */ @Override public void load() { - this.fileTypes = UserDefinedFileTypesManager.getInstance().getUserDefinedFileTypes(); - this.setFileTypesListModel(); - this.typesList.addListSelectionListener(new TypesListSelectionListener()); - if (!this.typesListModel.isEmpty()) { - this.typesList.setSelectedIndex(0); + fileTypes = UserDefinedFileTypesManager.getInstance().getUserDefinedFileTypes(); + updateFileTypesListModel(); + if (!typesListModel.isEmpty()) { + typesList.setSelectedIndex(0); } + enableButtons(); + } + + /** + * Sets the list model for the file types list component. + */ + private void updateFileTypesListModel() { + ArrayList mimeTypes = new ArrayList<>(fileTypes.keySet()); + Collections.sort(mimeTypes); + typesListModel.clear(); + for (String mimeType : mimeTypes) { + typesListModel.addElement(mimeType); + } + } + + /** + * Sets all of the components in the individual type details portion of the + * panel based on the current selection in the file types list. + */ + private void populateTypeDetailsComponents() { + String mimeType = typesList.getSelectedValue(); + FileType fileType = fileTypes.get(mimeType); + if (null != fileType) { + Signature signature = fileType.getSignature(); + mimeTypeTextField.setText(mimeType); + FileType.Signature.Type sigType = fileType.getSignature().getType(); + signatureTypeComboBox.setSelectedItem(sigType == FileType.Signature.Type.RAW ? FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM : FileTypeIdGlobalSettingsPanel.ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM); + offsetTextField.setText(Long.toString(signature.getOffset())); + postHitCheckBox.setSelected(fileType.alertOnMatch()); + filesSetNameTextField.setText(fileType.getFilesSetName()); + } + enableButtons(); + } + + /** + * Clears all of the components in the individual type details portion of + * the panel. + */ + private void clearTypeDetailsComponents() { + typesList.setSelectedIndex(-1); + mimeTypeTextField.setText(""); //NON-NLS + signatureTypeComboBox.setSelectedItem(FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM); + signatureTextField.setText(""); //NON-NLS + offsetTextField.setText(""); //NON-NLS + postHitCheckBox.setSelected(false); + filesSetNameTextField.setText(""); //NON-NLS + filesSetNameTextField.setEnabled(false); + enableButtons(); } /** @@ -104,7 +247,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane @Override public void store() { try { - UserDefinedFileTypesManager.getInstance().setUserDefinedFileTypes(this.fileTypes); + UserDefinedFileTypesManager.getInstance().setUserDefinedFileTypes(fileTypes); } catch (UserDefinedFileTypesManager.UserDefinedFileTypesException ex) { JOptionPane.showMessageDialog(null, ex.getLocalizedMessage(), @@ -114,57 +257,13 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane } /** - * Selection listener for the file types list component. + * @inheritDoc */ - private class TypesListSelectionListener implements ListSelectionListener { - - @Override - public void valueChanged(ListSelectionEvent e) { - if (e.getValueIsAdjusting() == false) { - if (FileTypeIdGlobalSettingsPanel.this.typesList.getSelectedIndex() == -1) { - FileTypeIdGlobalSettingsPanel.this.deleteTypeButton.setEnabled(false); - } else { - String mimeType = FileTypeIdGlobalSettingsPanel.this.typesList.getSelectedValue(); - FileType fileType = FileTypeIdGlobalSettingsPanel.this.fileTypes.get(mimeType); - Signature signature = fileType.getSignature(); - FileTypeIdGlobalSettingsPanel.this.mimeTypeTextField.setText(mimeType); - FileType.Signature.Type sigType = fileType.getSignature().getType(); - FileTypeIdGlobalSettingsPanel.this.signatureTypeComboBox.setSelectedItem(sigType == FileType.Signature.Type.RAW ? FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM : FileTypeIdGlobalSettingsPanel.ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM); - FileTypeIdGlobalSettingsPanel.this.offsetTextField.setText(Long.toString(signature.getOffset())); - FileTypeIdGlobalSettingsPanel.this.postHitCheckBox.setSelected(fileType.alertOnMatch()); - FileTypeIdGlobalSettingsPanel.this.filesSetNameTextField.setText(fileType.getFilesSetName()); - FileTypeIdGlobalSettingsPanel.this.deleteTypeButton.setEnabled(true); - } - } - } + @Override + public void saveSettings() { + store(); } - - /** - * Sets the list model for the file types list component. - */ - private void setFileTypesListModel() { - ArrayList mimeTypes = new ArrayList(this.fileTypes.keySet()); - Collections.sort(mimeTypes); - this.typesListModel.clear(); - for (String mimeType : mimeTypes) { - this.typesListModel.addElement(mimeType); - } - } - - /** - * Clears all of the components in the individual type details portion of - * the panel. - */ - private void clearTypeDetailsComponents() { - this.typesList.setSelectedIndex(-1); - this.mimeTypeTextField.setText(""); - this.signatureTypeComboBox.setSelectedItem(FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM); - this.signatureTextField.setText(""); //NON-NLS - this.offsetTextField.setText(""); //NON-NLS - this.postHitCheckBox.setSelected(false); - this.filesSetNameTextField.setText(""); - } - + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -176,7 +275,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane typesScrollPane = new javax.swing.JScrollPane(); typesList = new javax.swing.JList(); - jSeparator1 = new javax.swing.JSeparator(); + separator = new javax.swing.JSeparator(); mimeTypeLabel = new javax.swing.JLabel(); mimeTypeTextField = new javax.swing.JTextField(); signatureTypeLabel = new javax.swing.JLabel(); @@ -189,15 +288,16 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane hexPrefixLabel = new javax.swing.JLabel(); signatureTypeComboBox = new javax.swing.JComboBox(); signatureLabel = new javax.swing.JLabel(); - jScrollPane2 = new javax.swing.JScrollPane(); - jTextArea1 = new javax.swing.JTextArea(); + hintScrollPane = new javax.swing.JScrollPane(); + hintTextArea = new javax.swing.JTextArea(); postHitCheckBox = new javax.swing.JCheckBox(); filesSetNameLabel = new javax.swing.JLabel(); filesSetNameTextField = new javax.swing.JTextField(); + ingestRunningWarningLabel = new javax.swing.JLabel(); typesScrollPane.setViewportView(typesList); - jSeparator1.setOrientation(javax.swing.SwingConstants.VERTICAL); + separator.setOrientation(javax.swing.SwingConstants.VERTICAL); org.openide.awt.Mnemonics.setLocalizedText(mimeTypeLabel, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.mimeTypeLabel.text")); // NOI18N @@ -234,16 +334,22 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane org.openide.awt.Mnemonics.setLocalizedText(hexPrefixLabel, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.hexPrefixLabel.text")); // NOI18N + signatureTypeComboBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + signatureTypeComboBoxActionPerformed(evt); + } + }); + org.openide.awt.Mnemonics.setLocalizedText(signatureLabel, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.signatureLabel.text")); // NOI18N - jTextArea1.setEditable(false); - jTextArea1.setColumns(20); - jTextArea1.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N - jTextArea1.setLineWrap(true); - jTextArea1.setRows(5); - jTextArea1.setText(org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.jTextArea1.text")); // NOI18N - jTextArea1.setWrapStyleWord(true); - jScrollPane2.setViewportView(jTextArea1); + hintTextArea.setEditable(false); + hintTextArea.setColumns(20); + hintTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N + hintTextArea.setLineWrap(true); + hintTextArea.setRows(5); + hintTextArea.setText(org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.hintTextArea.text")); // NOI18N + hintTextArea.setWrapStyleWord(true); + hintScrollPane.setViewportView(hintTextArea); org.openide.awt.Mnemonics.setLocalizedText(postHitCheckBox, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.postHitCheckBox.text")); // NOI18N postHitCheckBox.addActionListener(new java.awt.event.ActionListener() { @@ -256,6 +362,9 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane filesSetNameTextField.setText(org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.filesSetNameTextField.text")); // NOI18N + ingestRunningWarningLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/modules/filetypeid/warning16.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(ingestRunningWarningLabel, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.ingestRunningWarningLabel.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -264,53 +373,58 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane .addGap(26, 26, 26) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(typesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addComponent(newTypeButton) + .addComponent(ingestRunningWarningLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(30, 30, 30)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(typesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(newTypeButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(deleteTypeButton) + .addGap(9, 9, 9))) + .addComponent(separator, javax.swing.GroupLayout.PREFERRED_SIZE, 13, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(deleteTypeButton) - .addGap(9, 9, 9))) - .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 13, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(signatureTypeLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(signatureTypeComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(offsetLabel) - .addComponent(filesSetNameLabel) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addGroup(layout.createSequentialGroup() - .addComponent(signatureLabel) - .addGap(18, 18, 18) - .addComponent(hexPrefixLabel))) - .addGap(5, 5, 5) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(offsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 84, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(signatureTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 178, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addGap(2, 2, 2) - .addComponent(mimeTypeLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(mimeTypeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 181, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(filesSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 179, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 260, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(postHitCheckBox) - .addComponent(saveTypeButton)) - .addContainerGap(29, Short.MAX_VALUE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(offsetLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(filesSetNameLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(offsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 178, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(filesSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 179, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(signatureLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(signatureTypeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addGap(2, 2, 2) + .addComponent(mimeTypeLabel))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(mimeTypeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 176, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(signatureTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 176, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(hexPrefixLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(signatureTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 160, javax.swing.GroupLayout.PREFERRED_SIZE))))) + .addComponent(hintScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 260, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(postHitCheckBox) + .addComponent(saveTypeButton)) + .addGap(29, 29, 29)))) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(16, 16, 16) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 281, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(separator, javax.swing.GroupLayout.PREFERRED_SIZE, 281, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(layout.createSequentialGroup() - .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(hintScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(18, 18, 18) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(mimeTypeLabel) @@ -342,19 +456,21 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(deleteTypeButton) .addComponent(newTypeButton)))) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(ingestRunningWarningLabel) + .addContainerGap(22, Short.MAX_VALUE)) ); }// //GEN-END:initComponents private void newTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTypeButtonActionPerformed - this.clearTypeDetailsComponents(); + clearTypeDetailsComponents(); }//GEN-LAST:event_newTypeButtonActionPerformed private void deleteTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTypeButtonActionPerformed - String typeName = this.typesList.getSelectedValue(); - this.fileTypes.remove(typeName); - this.clearTypeDetailsComponents(); - this.typesList.setSelectedIndex(-1); + String typeName = typesList.getSelectedValue(); + fileTypes.remove(typeName); + clearTypeDetailsComponents(); + typesList.setSelectedIndex(-1); }//GEN-LAST:event_deleteTypeButtonActionPerformed private void saveTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveTypeButtonActionPerformed @@ -362,7 +478,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane /** * Get the file type name. */ - String typeName = this.mimeTypeTextField.getText(); + String typeName = mimeTypeTextField.getText(); if (typeName.isEmpty()) { JOptionPane.showMessageDialog(null, NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidMIMEType.message"), @@ -374,12 +490,12 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane /** * Get the signature type. */ - FileType.Signature.Type sigType = this.signatureTypeComboBox.getSelectedItem() == FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM ? FileType.Signature.Type.RAW : FileType.Signature.Type.ASCII; + FileType.Signature.Type sigType = signatureTypeComboBox.getSelectedItem() == FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM ? FileType.Signature.Type.RAW : FileType.Signature.Type.ASCII; /** * Get the signature bytes. */ - String sigString = this.signatureTextField.getText(); + String sigString = signatureTextField.getText(); if (sigString.isEmpty()) { JOptionPane.showMessageDialog(null, NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignature.message"), @@ -399,7 +515,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane */ long offset; try { - offset = Long.parseUnsignedLong(this.offsetTextField.getText()); + offset = Long.parseUnsignedLong(offsetTextField.getText()); } catch (NumberFormatException ex) { JOptionPane.showMessageDialog(null, NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message"), @@ -411,8 +527,8 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane /** * Get the interesting files set details. */ - String filesSetName = this.filesSetNameTextField.getText(); - if (this.postHitCheckBox.isSelected() && filesSetName.isEmpty()) { + String filesSetName = filesSetNameTextField.getText(); + if (postHitCheckBox.isSelected() && filesSetName.isEmpty()) { JOptionPane.showMessageDialog(null, NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message"), NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.title"), @@ -423,10 +539,10 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane * Put it all together and reset the file types list component. */ FileType.Signature signature = new FileType.Signature(signatureBytes, offset, sigType); - FileType fileType = new FileType(typeName, signature, filesSetName, this.postHitCheckBox.isSelected()); - this.fileTypes.put(typeName, fileType); - this.setFileTypesListModel(); - this.typesList.setSelectedValue(fileType.getMimeType(), true); + FileType fileType = new FileType(typeName, signature, filesSetName, postHitCheckBox.isSelected()); + fileTypes.put(typeName, fileType); + updateFileTypesListModel(); + typesList.setSelectedValue(fileType.getMimeType(), true); } catch (NumberFormatException ex) { JOptionPane.showMessageDialog(null, @@ -442,17 +558,21 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane }//GEN-LAST:event_saveTypeButtonActionPerformed private void postHitCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_postHitCheckBoxActionPerformed - this.filesSetNameTextField.setEnabled(this.postHitCheckBox.isSelected()); + filesSetNameTextField.setEnabled(postHitCheckBox.isSelected()); }//GEN-LAST:event_postHitCheckBoxActionPerformed + private void signatureTypeComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_signatureTypeComboBoxActionPerformed + hexPrefixLabel.setVisible(signatureTypeComboBox.getSelectedItem() == FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM); + }//GEN-LAST:event_signatureTypeComboBoxActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton deleteTypeButton; private javax.swing.JLabel filesSetNameLabel; private javax.swing.JTextField filesSetNameTextField; private javax.swing.JLabel hexPrefixLabel; - private javax.swing.JScrollPane jScrollPane2; - private javax.swing.JSeparator jSeparator1; - private javax.swing.JTextArea jTextArea1; + private javax.swing.JScrollPane hintScrollPane; + private javax.swing.JTextArea hintTextArea; + private javax.swing.JLabel ingestRunningWarningLabel; private javax.swing.JLabel mimeTypeLabel; private javax.swing.JTextField mimeTypeTextField; private javax.swing.JButton newTypeButton; @@ -460,6 +580,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane private javax.swing.JTextField offsetTextField; private javax.swing.JCheckBox postHitCheckBox; private javax.swing.JButton saveTypeButton; + private javax.swing.JSeparator separator; private javax.swing.JLabel signatureLabel; private javax.swing.JTextField signatureTextField; private javax.swing.JComboBox signatureTypeComboBox; diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java index dbd54351cc..ee6f427dde 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java @@ -34,6 +34,12 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; @ServiceProvider(service = IngestModuleFactory.class) public class FileTypeIdModuleFactory extends IngestModuleFactoryAdapter { + /** + * Make this a singleton since it is a ingest job event listener that never + * de-registers. + */ + FileTypeIdGlobalSettingsPanel globalSettingsPanel; + /** * @inheritDoc */ @@ -82,9 +88,12 @@ public class FileTypeIdModuleFactory extends IngestModuleFactoryAdapter { */ @Override public IngestModuleGlobalSettingsPanel getGlobalSettingsPanel() { - return new FileTypeIdGlobalSettingsPanel(); + if (null == globalSettingsPanel) { + globalSettingsPanel = new FileTypeIdGlobalSettingsPanel(); + } + return globalSettingsPanel; } - + /** * @inheritDoc */ diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java index bbf16073de..8f9aa7b500 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdOptionsPanelController.java @@ -8,14 +8,13 @@ package org.sleuthkit.autopsy.modules.filetypeid; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import javax.swing.JComponent; -import javax.swing.SwingUtilities; import org.netbeans.spi.options.OptionsPanelController; import org.openide.util.HelpCtx; import org.openide.util.Lookup; @OptionsPanelController.TopLevelRegistration( categoryName = "#OptionsCategory_Name_FileTypeId", - iconBase = "org/sleuthkit/autopsy/corecomponents/display-options.png", + iconBase = "org/sleuthkit/autopsy/modules/filetypeid/user-defined-file-types-settings.png", keywords = "#OptionsCategory_Keywords_FileTypeId", keywordsCategory = "FileTypeId" ) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java index 65a7a447a2..4c1325192c 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java @@ -45,6 +45,18 @@ import org.xml.sax.SAXException; /** * Manages user-defined file types characterized by MIME type, signature, and * optional membership in an interesting files set. + *

+ * Note that this class exposes a very simple get/set API that operates on the + * user-defined file types as a complete set - there is no concept of adding, + * editing or deleting file types singly. This works because this class is not + * exposed outside of this ingest module package and is ONLY used in a very + * specific paradigm where there is a single modal writer of file types in the + * form of a global settings panel that disables itself when ingest is running + * so that multiple readers in the form of file ingest modules get a consistent + * set of file type definitions. Moreover, there is no enforcement of compliance + * with this paradigm by this class - it merely participates in the scheme. + *

+ * Thread-safe. */ final class UserDefinedFileTypesManager { @@ -87,7 +99,7 @@ final class UserDefinedFileTypesManager { * thread-safety. */ private final Map fileTypes = new HashMap<>(); - + /** * Gets the manager of user-defined file types characterized by MIME type, * signature, and optional membership in an interesting files set. diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/warning16.png b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/warning16.png new file mode 100644 index 0000000000000000000000000000000000000000..f5ba881738ae3072e476f3ddbd7dd34d642f06d6 GIT binary patch literal 552 zcmV+@0@wYCP)A&a_P7S}o zG!s6}jEu~GKp4p&41mvo3NbA|1~KhGFq>2ZZB(et$g5@cY9-1{tFW22MeRe4v~wF$QERIaM<- z{{O*nd`23>@mYBc|Np&XP;x8-%MmglnP1j4N=(g;;pf|paKWFi*D(ky8Zq$8n1Dhw z4W9v-%1)IGf4<*f`2Xh#iNdNA(_lT4EX==BZIP28N-#eIhh~>reEIz qPU=w%q=Bs Date: Fri, 19 Dec 2014 17:04:37 -0500 Subject: [PATCH 20/27] Improve user-defined file types UI --- .../user-defined-file-types-settings.png | Bin 0 -> 1652 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/modules/filetypeid/user-defined-file-types-settings.png diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/user-defined-file-types-settings.png b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/user-defined-file-types-settings.png new file mode 100644 index 0000000000000000000000000000000000000000..4dc0c47b17696e6eca344dfbb1fcb2fa7a588661 GIT binary patch literal 1652 zcmV-)28;QLP)!3MP&iN;Q8y_;930mYIZ#D45)wJ#K(R=2 zpb>&Zju4cH5)@G(6-1?o+}cB{G^8Bp0X5--gdL=S>_#ajcGB3JZTxR{-+TLJhQq#f zW4F6r(gXaY(c4+=%zo$l{r=|nd+_Bhr5?#< zv)xjz`x0@G+B(hFo}MR- zF;5l>h1x=~_(m?5`@zwpNB`Aojk6JeHKsnSMQe?<7RPZALLd^?wi>SMlF4M$_U+q8 z2KVjz-Opcm;j{O}fa^F&*ToovF@`vfSy@@Z7=vh?9)v-F5 z$&>$V3qXSbzavf7SXNh-vBqGuCJaN2F)d|qU6)iUMHoc@^!4?9Wq5e_*Ncmb-#T;V z%)d96z*>Tu=GAMO-~Iz`u3AV~u?ZWkhSr+Za+zwiiqRS&1pWQ}gZuaI|Ha72NPcq( zj3KsAj69a`(JW)E!4ZO7Hq$gEEnsb3f?BOcu~=kgW`-aL5W?Y;`TR2n4jhcfxXjyvqGVd?1Qv2La;9+jAXkLCt5epXwkPdYD zknez%2*R3WsJqM#wL+{77LZcX)6+vPmqRH{m(;v&+|5aScY0_A7veBdFJ-$f?<3AR2E^Vhfj%xkZ` z&dkgV*-VD7J^eI?Mn_4dQuR#PVB(MTfa?nSx?H*yL^XpphH52Z_Qo<=-^C)ZI0z|m z)ODOx4#(?cu_NHe$HvzE!QUn(DBZckv17-OQhq3lKGFk12&zFqxl%<4fzcXAo{@!7FdwV&5{ye{W@kM@r?i^!dW8`uLCxhtsD|=bvYGc9!3~ z^b*^)ZCl%8qXf=+4}4HiYH^LI7S%hXM2?2`n~k?GUE=cP%N#s-klxS8p6BI^G0Iwlr&L=KOiWC0;lc$51_s!v({z)#A)|zJ2It#^^_lu?W##umAOtXL#a?0Y3BT{dMQ5&r>cti$kf)k{|Z0000 Date: Sun, 21 Dec 2014 21:31:10 -0500 Subject: [PATCH 21/27] Complete user-defined file types feature --- .../sleuthkit/autopsy/coreutils/XMLUtil.java | 10 +-- .../autopsy/modules/filetypeid/FileType.java | 39 +++++---- .../FileTypeIdGlobalSettingsPanel.java | 81 +++++++++++-------- .../FileTypeIdIngestJobSettingsPanel.java | 10 ++- .../filetypeid/FileTypeIdIngestModule.java | 10 ++- .../filetypeid/FileTypeIdModuleFactory.java | 5 +- .../filetypeid/FileTypeIdModuleSettings.java | 2 +- .../UserDefinedFileTypesManager.java | 4 +- 8 files changed, 94 insertions(+), 67 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/XMLUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/XMLUtil.java index ef360762d9..cc055638d7 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/XMLUtil.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/XMLUtil.java @@ -167,7 +167,7 @@ public class XMLUtil { * IngestModuleLoader. * */ - // RJCTODO: Deprecate. + // TODO: Deprecate. public static boolean xmlIsValid(DOMSource xmlfile, Class clazz, String schemaFile) { try { PlatformUtil.extractResourceToUserConfigDir(clazz, schemaFile, false); @@ -205,7 +205,7 @@ public class XMLUtil { * IngestModuleLoader. * */ - // RJCTODO: Deprecate. + // TODO: Deprecate. public static boolean xmlIsValid(Document doc, Class clazz, String type) { DOMSource dms = new DOMSource(doc); return xmlIsValid(dms, clazz, type); @@ -217,7 +217,7 @@ public class XMLUtil { * @param clazz the class this method is invoked from * @param xmlPath the full path to the file to load */ - // RJCTODO: Deprecate. + // TODO: Deprecate. public static Document loadDoc(Class clazz, String xmlPath) { DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); Document ret = null; @@ -242,7 +242,7 @@ public class XMLUtil { * @param xmlPath the full path to the file to load * @param xsdPath the full path to the file to validate against */ - // RJCTODO: Deprecate + // TODO: Deprecate public static Document loadDoc(Class clazz, String xmlPath, String xsdPath) { Document ret = loadDoc(clazz, xmlPath); if (!XMLUtil.xmlIsValid(ret, clazz, xsdPath)) { @@ -259,7 +259,7 @@ public class XMLUtil { * @param encoding to encoding, such as "UTF-8", to encode the file with * @param doc the document to save */ - // RJCTODO: Deprecate. + // TODO: Deprecate. public static boolean saveDoc(Class clazz, String xmlPath, String encoding, final Document doc) { TransformerFactory xf = TransformerFactory.newInstance(); xf.setAttribute("indent-number", 1); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java index 513eff58b3..e3903ffc30 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java @@ -27,9 +27,9 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Represents a file type characterized by a file signature. *

- * Thread-safe. + * Thread-safe (immutable). */ -final class FileType { +class FileType { private final String mimeType; private final Signature signature; @@ -41,9 +41,9 @@ final class FileType { * signature. * * @param mimeType The mime type to associate with this file type. - * @param signature The signature that characterizes the file type. + * @param signature The signature that characterizes this file type. * @param filesSetName The name of an interesting files set that includes - * files of this type. + * files of this type, may be the empty string. * @param alert Whether the user wishes to be alerted when a file matching * this type is encountered. */ @@ -60,7 +60,7 @@ final class FileType { * @return The MIME type. */ String getMimeType() { - return this.mimeType; + return mimeType; } /** @@ -69,7 +69,7 @@ final class FileType { * @return The signature. */ Signature getSignature() { - return new Signature(this.signature.getSignatureBytes(), this.signature.getOffset(), this.signature.getType()); + return new Signature(signature.getSignatureBytes(), signature.getOffset(), signature.getType()); } /** @@ -79,7 +79,7 @@ final class FileType { * @return True or false. */ boolean matches(final AbstractFile file) { - return this.signature.containedIn(file); + return signature.containedIn(file); } /** @@ -89,7 +89,7 @@ final class FileType { * @return True or false. */ boolean alertOnMatch() { - return this.alert; + return alert; } /** @@ -99,16 +99,16 @@ final class FileType { * @return The interesting files set name, possibly empty. */ String getFilesSetName() { - return this.interestingFilesSetName; + return interestingFilesSetName; } /** * A file signature consisting of a sequence of bytes at a specific offset * within a file. *

- * Thread-safe. + * Thread-safe (immutable). */ - static final class Signature { + static class Signature { private static final Logger logger = Logger.getLogger(Signature.class.getName()); @@ -145,7 +145,7 @@ final class FileType { * @return The byte sequence as an array of bytes. */ byte[] getSignatureBytes() { - return Arrays.copyOf(this.signatureBytes, this.signatureBytes.length); + return Arrays.copyOf(signatureBytes, signatureBytes.length); } /** @@ -154,7 +154,7 @@ final class FileType { * @return The offset. */ long getOffset() { - return this.offset; + return offset; } /** @@ -163,7 +163,7 @@ final class FileType { * @return The signature type. */ Type getType() { - return this.type; + return type; } /** @@ -175,10 +175,15 @@ final class FileType { */ boolean containedIn(final AbstractFile file) { try { - byte[] buffer = new byte[this.signatureBytes.length]; - int bytesRead = file.read(buffer, this.offset, this.signatureBytes.length); - return ((bytesRead == this.signatureBytes.length) && (Arrays.equals(buffer, this.signatureBytes))); + byte[] buffer = new byte[signatureBytes.length]; + int bytesRead = file.read(buffer, offset, signatureBytes.length); + return ((bytesRead == signatureBytes.length) && (Arrays.equals(buffer, signatureBytes))); } catch (TskCoreException ex) { + /** + * This exception is caught rather than propagated because files + * in images are not always consistent with their file system + * meta data making for read errors. + */ Signature.logger.log(Level.WARNING, "Error reading from file with objId = " + file.getId(), ex); return false; } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java index b5ca9abc62..4984384296 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -33,6 +33,7 @@ import javax.swing.event.DocumentListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.xml.bind.DatatypeConverter; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -58,6 +59,14 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane private DefaultListModel typesListModel; private Map fileTypes; + /** + * This panel implements a property change listener that listens to ingest + * job events to disable the buttons on the panel if ingest is running. This + * is done to prevent changes to user-defined types while the type + * definitions are in use. + */ + IngestJobEventPropertyChangeListener ingestJobEventsListener; + /** * Creates a panel to allow a user to make custom file type definitions. */ @@ -110,9 +119,9 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane } } } - }); + }); } - + /** * Adds listeners to the text fields that enable and disable the buttons on * the panel. @@ -144,20 +153,27 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane * Add a property change listener that listens to ingest job events to * disable the buttons on the panel if ingest is running. This is done to * prevent changes to user-defined types while the type definitions are in - * use. the components in sync with file ingest. + * use. */ private void addIngestJobEventsListener() { - IngestManager.getInstance().addIngestJobEventListener(new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - enableButtons(); - } - }); - } - }); + ingestJobEventsListener = new IngestJobEventPropertyChangeListener(); + IngestManager.getInstance().addIngestJobEventListener(ingestJobEventsListener); + } + + /** + * A property change listener that listens to ingest job events. + */ + private class IngestJobEventPropertyChangeListener implements PropertyChangeListener { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + enableButtons(); + } + }); + } } /** @@ -177,7 +193,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane && !signatureTextField.getText().isEmpty() && postHitCheckBox.isSelected() ? !filesSetNameTextField.getText().isEmpty() : true; saveTypeButton.setEnabled(!ingestIsRunning && fileTypeIsSelected && requiredFieldsPopulated); - + ingestRunningWarningLabel.setVisible(ingestIsRunning); } @@ -207,21 +223,21 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane } /** - * Sets all of the components in the individual type details portion of the + * Populates all of the components in the file type details portion of the * panel based on the current selection in the file types list. */ private void populateTypeDetailsComponents() { String mimeType = typesList.getSelectedValue(); FileType fileType = fileTypes.get(mimeType); if (null != fileType) { - Signature signature = fileType.getSignature(); mimeTypeTextField.setText(mimeType); - FileType.Signature.Type sigType = fileType.getSignature().getType(); + Signature signature = fileType.getSignature(); + FileType.Signature.Type sigType = signature.getType(); signatureTypeComboBox.setSelectedItem(sigType == FileType.Signature.Type.RAW ? FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM : FileTypeIdGlobalSettingsPanel.ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM); offsetTextField.setText(Long.toString(signature.getOffset())); postHitCheckBox.setSelected(fileType.alertOnMatch()); filesSetNameTextField.setText(fileType.getFilesSetName()); - } + } enableButtons(); } @@ -233,6 +249,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane typesList.setSelectedIndex(-1); mimeTypeTextField.setText(""); //NON-NLS signatureTypeComboBox.setSelectedItem(FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM); + hexPrefixLabel.setVisible(true); signatureTextField.setText(""); //NON-NLS offsetTextField.setText(""); //NON-NLS postHitCheckBox.setSelected(false); @@ -263,7 +280,17 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane public void saveSettings() { store(); } - + + /** + * @inheritDoc + */ + @Override + @SuppressWarnings("FinalizeDeclaration") + protected void finalize() throws Throwable { + IngestManager.getInstance().removeIngestJobEventListener(ingestJobEventsListener); + super.finalize(); + } + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -470,13 +497,12 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane String typeName = typesList.getSelectedValue(); fileTypes.remove(typeName); clearTypeDetailsComponents(); - typesList.setSelectedIndex(-1); }//GEN-LAST:event_deleteTypeButtonActionPerformed private void saveTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveTypeButtonActionPerformed try { /** - * Get the file type name. + * Get the MIME type. */ String typeName = mimeTypeTextField.getText(); if (typeName.isEmpty()) { @@ -513,16 +539,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane /** * Get the offset. */ - long offset; - try { - offset = Long.parseUnsignedLong(offsetTextField.getText()); - } catch (NumberFormatException ex) { - JOptionPane.showMessageDialog(null, - NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message"), - NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.title"), - JOptionPane.ERROR_MESSAGE); - return; - } + long offset = Long.parseUnsignedLong(offsetTextField.getText()); /** * Get the interesting files set details. diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.java index f31380379d..ff65c1ac63 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.java @@ -25,12 +25,10 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; * UI component used to set ingest job options for file type identifier ingest * modules. */ -final class FileTypeIdIngestJobSettingsPanel extends IngestModuleIngestJobSettingsPanel { +class FileTypeIdIngestJobSettingsPanel extends IngestModuleIngestJobSettingsPanel { private final FileTypeIdModuleSettings settings; - // NOTE: This was declared public, but was inaccessible because the class is - // not public FileTypeIdIngestJobSettingsPanel(FileTypeIdModuleSettings settings) { this.settings = settings; initComponents(); @@ -44,7 +42,11 @@ final class FileTypeIdIngestJobSettingsPanel extends IngestModuleIngestJobSettin public IngestModuleIngestJobSettings getSettings() { return settings; } - + + /** + * Does child component initialization in addition to that done by the + * Matisse generated code. + */ private void customizeComponents() { skipKnownCheckBox.setSelected(settings.skipKnownFiles()); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java index 577e01aca6..348bb13e9c 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java @@ -39,6 +39,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute; * Detects the type of a file based on signature (magic) values. Posts results * to the blackboard. */ +// TODO: This class does not need to be public. public class FileTypeIdIngestModule implements FileIngestModule { private static final Logger logger = Logger.getLogger(FileTypeIdIngestModule.class.getName()); @@ -120,15 +121,20 @@ public class FileTypeIdIngestModule implements FileIngestModule { long startTime = System.currentTimeMillis(); FileType fileType = this.userDefinedFileTypeIdentifier.identify(file); if (null != fileType) { + String moduleName = FileTypeIdModuleFactory.getModuleName(); BlackboardArtifact getInfoArtifact = file.getGenInfoArtifact(); - BlackboardAttribute typeAttr = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG.getTypeID(), FileTypeIdModuleFactory.getModuleName(), fileType.getMimeType()); + BlackboardAttribute typeAttr = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG.getTypeID(), moduleName, fileType.getMimeType()); getInfoArtifact.addAttribute(typeAttr); if (fileType.alertOnMatch()) { - String moduleName = FileTypeIdModuleFactory.getModuleName(); BlackboardArtifact artifact = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); BlackboardAttribute setNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(), moduleName, fileType.getFilesSetName()); artifact.addAttribute(setNameAttribute); + + /** + * Use the MIME type as the category, i.e., the rule that + * determined this file belongs to the interesting files set. + */ BlackboardAttribute ruleNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY.getTypeID(), moduleName, fileType.getMimeType()); artifact.addAttribute(ruleNameAttribute); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java index ee6f427dde..f831ed15e2 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java @@ -31,13 +31,10 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; /** * A factory that creates file ingest modules that determine the types of files. */ +// TODO: This class does not need to be public. @ServiceProvider(service = IngestModuleFactory.class) public class FileTypeIdModuleFactory extends IngestModuleFactoryAdapter { - /** - * Make this a singleton since it is a ingest job event listener that never - * de-registers. - */ FileTypeIdGlobalSettingsPanel globalSettingsPanel; /** diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java index 31e077a875..ddf5371045 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java @@ -23,7 +23,7 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; /** * Ingest job options for the file type identifier ingest module instances. */ -// @Deprecated This class is not for public use +// TODO: This class does not need to be public. public class FileTypeIdModuleSettings implements IngestModuleIngestJobSettings { private static final long serialVersionUID = 1L; diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java index 4c1325192c..9f093b5570 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java @@ -268,10 +268,10 @@ final class UserDefinedFileTypesManager { } catch (ParserConfigurationException | FileNotFoundException | UnsupportedEncodingException | TransformerException ex) { UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Failed to write file types file", ex); - throw new UserDefinedFileTypesManager.UserDefinedFileTypesException(ex.getLocalizedMessage()); // RJCTODO: Create a bundled message + throw new UserDefinedFileTypesManager.UserDefinedFileTypesException(ex.getLocalizedMessage()); } catch (IOException ex) { UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Failed to write file types file", ex); - throw new UserDefinedFileTypesManager.UserDefinedFileTypesException(ex.getLocalizedMessage()); // RJCTODO: Create a bundled message + throw new UserDefinedFileTypesManager.UserDefinedFileTypesException(ex.getLocalizedMessage()); } /** From a9ea3d280e43ed9baee5ec5bf5ecfdffe93f2a59 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Sun, 21 Dec 2014 23:48:43 -0500 Subject: [PATCH 22/27] Bug fixes for user-defined file types --- .../FileTypeIdGlobalSettingsPanel.java | 9 +++++--- .../filetypeid/FileTypeIdIngestModule.java | 6 ++--- .../filetypeid/FileTypeIdModuleFactory.java | 1 + .../filetypeid/UserDefinedFileTypes.xsd | 16 +++++++------- .../UserDefinedFileTypesManager.java | 22 +++++++++---------- 5 files changed, 29 insertions(+), 25 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java index 4984384296..83bc32d167 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -147,6 +147,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane mimeTypeTextField.getDocument().addDocumentListener(listener); offsetTextField.getDocument().addDocumentListener(listener); signatureTextField.getDocument().addDocumentListener(listener); + filesSetNameTextField.getDocument().addDocumentListener(listener); } /** @@ -186,13 +187,13 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane boolean fileTypeIsSelected = typesList.getSelectedIndex() != -1; deleteTypeButton.setEnabled(!ingestIsRunning && fileTypeIsSelected); - + boolean requiredFieldsPopulated = !mimeTypeTextField.getText().isEmpty() && !offsetTextField.getText().isEmpty() && !signatureTextField.getText().isEmpty() - && postHitCheckBox.isSelected() ? !filesSetNameTextField.getText().isEmpty() : true; - saveTypeButton.setEnabled(!ingestIsRunning && fileTypeIsSelected && requiredFieldsPopulated); + && (postHitCheckBox.isSelected() ? !filesSetNameTextField.getText().isEmpty() : true); + saveTypeButton.setEnabled(!ingestIsRunning && requiredFieldsPopulated); ingestRunningWarningLabel.setVisible(ingestIsRunning); } @@ -234,6 +235,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane Signature signature = fileType.getSignature(); FileType.Signature.Type sigType = signature.getType(); signatureTypeComboBox.setSelectedItem(sigType == FileType.Signature.Type.RAW ? FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM : FileTypeIdGlobalSettingsPanel.ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM); + this.signatureTextField.setText(DatatypeConverter.printHexBinary(signature.getSignatureBytes())); offsetTextField.setText(Long.toString(signature.getOffset())); postHitCheckBox.setSelected(fileType.alertOnMatch()); filesSetNameTextField.setText(fileType.getFilesSetName()); @@ -576,6 +578,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane private void postHitCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_postHitCheckBoxActionPerformed filesSetNameTextField.setEnabled(postHitCheckBox.isSelected()); + enableButtons(); }//GEN-LAST:event_postHitCheckBoxActionPerformed private void signatureTypeComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_signatureTypeComboBoxActionPerformed diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java index 348bb13e9c..6d6a1796e5 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java @@ -113,9 +113,9 @@ public class FileTypeIdIngestModule implements FileIngestModule { * Filter out very small files to minimize false positives. */ // RJCTODO: Make this size a setting - if (file.getSize() < MIN_FILE_SIZE) { - return ProcessResult.OK; - } +// if (file.getSize() < MIN_FILE_SIZE) { +// return ProcessResult.OK; +// } try { long startTime = System.currentTimeMillis(); diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java index f831ed15e2..38823ca03d 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java @@ -88,6 +88,7 @@ public class FileTypeIdModuleFactory extends IngestModuleFactoryAdapter { if (null == globalSettingsPanel) { globalSettingsPanel = new FileTypeIdGlobalSettingsPanel(); } + globalSettingsPanel.load(); return globalSettingsPanel; } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.xsd b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.xsd index 47f658599a..727d86bb97 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.xsd +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.xsd @@ -24,22 +24,22 @@ - - - + + + - + - - - + + + - + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java index 9f093b5570..74762cbbfb 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java @@ -63,14 +63,14 @@ final class UserDefinedFileTypesManager { private static final Logger logger = Logger.getLogger(UserDefinedFileTypesManager.class.getName()); private static final String FILE_TYPE_DEFINITIONS_SCHEMA_FILE = "FileTypeDefinitions.xsd"; //NON-NLS private static final String USER_DEFINED_TYPE_DEFINITIONS_FILE = "UserFileTypeDefinitions.xml"; //NON-NLS - private static final String FILE_TYPES_TAG_NAME = "filetypes"; //NON-NLS - private static final String FILE_TYPE_TAG_NAME = "filetype"; //NON-NLS - private static final String MIME_TYPE_TAG_NAME = "mimetype"; //NON-NLS - private static final String SIGNATURE_TAG_NAME = "signature"; //NON-NLS + private static final String FILE_TYPES_TAG_NAME = "FileTypes"; //NON-NLS + private static final String FILE_TYPE_TAG_NAME = "FileType"; //NON-NLS + private static final String MIME_TYPE_TAG_NAME = "MimeType"; //NON-NLS + private static final String SIGNATURE_TAG_NAME = "Signature"; //NON-NLS private static final String SIGNATURE_TYPE_ATTRIBUTE = "type"; //NON-NLS - private static final String BYTES_TAG_NAME = "bytes"; //NON-NLS - private static final String OFFSET_TAG_NAME = "offset"; //NON-NLS - private static final String INTERESTING_FILES_SET_TAG_NAME = "filesset"; //NON-NLS + private static final String BYTES_TAG_NAME = "Bytes"; //NON-NLS + private static final String OFFSET_TAG_NAME = "Offset"; //NON-NLS + private static final String INTERESTING_FILES_SET_TAG_NAME = "InterestingFileSset"; //NON-NLS private static final String ALERT_ATTRIBUTE = "alert"; //NON-NLS private static final String ENCODING_FOR_XML_FILE = "UTF-8"; //NON-NLS private static final String ASCII_ENCODING = "US-ASCII"; //NON-NLS @@ -135,7 +135,7 @@ final class UserDefinedFileTypesManager { /** * Create a file type that should match $MBR in Small2 image. */ - FileType fileType = new FileType("predefinedRAW", new Signature(new byte[]{(byte) 0x66, (byte) 0x73, (byte) 0x00}, 8L, FileType.Signature.Type.RAW), "predefinedRAW", true); + FileType fileType = new FileType("predefinedRAW", new Signature(new byte[]{(byte) 0x66, (byte) 0x73, (byte) 0x00}, 8L, FileType.Signature.Type.RAW), "Suspicious", true); this.addPredefinedFileType(fileType); /** @@ -143,7 +143,7 @@ final class UserDefinedFileTypesManager { */ // RJCTODO: Remove test file type. try { - fileType = new FileType("predefinedASCII", new Signature("hello".getBytes(UserDefinedFileTypesManager.ASCII_ENCODING), 0L, FileType.Signature.Type.ASCII), "predefinedASCII", true); + fileType = new FileType("predefinedASCII", new Signature("hello".getBytes(UserDefinedFileTypesManager.ASCII_ENCODING), 0L, FileType.Signature.Type.ASCII), "Benign", true); this.addPredefinedFileType(fileType); } catch (UnsupportedEncodingException ex) { UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Unable to create 'predefinedASCII' predefined file type definition", ex); //NON-NLS @@ -422,8 +422,8 @@ final class UserDefinedFileTypesManager { */ private static List readFileTypes(String filePath) throws IOException, ParserConfigurationException, SAXException { List fileTypes = new ArrayList<>(); - Path schemaFilePath = Paths.get(PlatformUtil.getUserConfigDirectory(), UserDefinedFileTypesManager.FILE_TYPE_DEFINITIONS_SCHEMA_FILE); - Document doc = XMLUtil.loadDocument(filePath, UserDefinedFileTypesManager.XmlReader.class, schemaFilePath.toAbsolutePath().toString()); +// Document doc = XMLUtil.loadDocument(filePath, UserDefinedFileTypesManager.XmlReader.class, UserDefinedFileTypesManager.FILE_TYPE_DEFINITIONS_SCHEMA_FILE); RJCTODO + Document doc = XMLUtil.loadDocument(filePath); if (doc != null) { Element fileTypesElem = doc.getDocumentElement(); if (fileTypesElem != null && fileTypesElem.getNodeName().equals(UserDefinedFileTypesManager.FILE_TYPES_TAG_NAME)) { From 2de508e11a2fe21348aab5706ca0df367f2212ac Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 22 Dec 2014 08:35:43 -0500 Subject: [PATCH 23/27] Commit version of file types manager with fine grained-control, simpler will be better --- .../{UserDefinedFileTypes.xsd => FileTypeDefinitions.xsd} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Core/src/org/sleuthkit/autopsy/modules/filetypeid/{UserDefinedFileTypes.xsd => FileTypeDefinitions.xsd} (100%) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.xsd b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDefinitions.xsd similarity index 100% rename from Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypes.xsd rename to Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDefinitions.xsd From 3562152a990706d2f9f6c79c5db8913b54b8785a Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 22 Dec 2014 08:36:05 -0500 Subject: [PATCH 24/27] Bug fixes for user-defined file types --- .../filetypeid/FileTypeDefinitions.xsd | 4 ++-- .../UserDefinedFileTypesManager.java | 24 ++++++++++++------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDefinitions.xsd b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDefinitions.xsd index 727d86bb97..f0ec8fa6c4 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDefinitions.xsd +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDefinitions.xsd @@ -26,7 +26,7 @@ - + @@ -42,7 +42,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java index 74762cbbfb..c07607c41d 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java @@ -118,12 +118,6 @@ final class UserDefinedFileTypesManager { * signature, and optional membership in an interesting files set. */ private UserDefinedFileTypesManager() { - /** - * Load the predefined types first so that they can be overwritten by - * any user-defined types with the same names. - */ - loadPredefinedFileTypes(); - loadUserDefinedFileTypes(); } /** @@ -235,6 +229,13 @@ final class UserDefinedFileTypesManager { * @return A mapping of file type names to file types, possibly empty. */ synchronized Map getFileTypes() { + /** + * Load the predefined types first so that they can be overwritten by + * any user-defined types with the same names. + */ + loadPredefinedFileTypes(); + loadUserDefinedFileTypes(); + /** * It is safe to return references to the internal file type objects * because they are immutable. @@ -248,6 +249,13 @@ final class UserDefinedFileTypesManager { * @return A mapping of file type names to file types, possibly empty. */ synchronized Map getUserDefinedFileTypes() { + /** + * Load the predefined types first so that they can be overwritten by + * any user-defined types with the same names. + */ + loadPredefinedFileTypes(); + loadUserDefinedFileTypes(); + /** * It is safe to return references to the internal file type objects * because they are immutable. @@ -422,8 +430,8 @@ final class UserDefinedFileTypesManager { */ private static List readFileTypes(String filePath) throws IOException, ParserConfigurationException, SAXException { List fileTypes = new ArrayList<>(); -// Document doc = XMLUtil.loadDocument(filePath, UserDefinedFileTypesManager.XmlReader.class, UserDefinedFileTypesManager.FILE_TYPE_DEFINITIONS_SCHEMA_FILE); RJCTODO - Document doc = XMLUtil.loadDocument(filePath); + Document doc = XMLUtil.loadDocument(filePath, UserDefinedFileTypesManager.class, UserDefinedFileTypesManager.FILE_TYPE_DEFINITIONS_SCHEMA_FILE); +// Document doc = XMLUtil.loadDocument(filePath); if (doc != null) { Element fileTypesElem = doc.getDocumentElement(); if (fileTypesElem != null && fileTypesElem.getNodeName().equals(UserDefinedFileTypesManager.FILE_TYPES_TAG_NAME)) { From acf83debc5bc7796d070b06882c6a6c943962673 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 22 Dec 2014 17:07:37 -0500 Subject: [PATCH 25/27] Bug fixes for user-defined file types --- .../autopsy/coreutils/PlatformUtil.java | 38 ++- .../modules/filetypeid/Bundle.properties | 13 +- .../FileTypeIdGlobalSettingsPanel.form | 136 +++++---- .../FileTypeIdGlobalSettingsPanel.java | 258 +++++++++------- .../FileTypeIdIngestJobSettingsPanel.form | 19 +- .../FileTypeIdIngestJobSettingsPanel.java | 27 +- .../filetypeid/FileTypeIdIngestModule.java | 23 +- .../filetypeid/FileTypeIdModuleSettings.java | 28 +- ...{FileTypeDefinitions.xsd => FileTypes.xsd} | 12 +- .../UserDefinedFileTypeIdentifier.java | 16 +- .../UserDefinedFileTypesManager.java | 287 +++++++++--------- 11 files changed, 487 insertions(+), 370 deletions(-) rename Core/src/org/sleuthkit/autopsy/modules/filetypeid/{FileTypeDefinitions.xsd => FileTypes.xsd} (81%) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/PlatformUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/PlatformUtil.java index a5c01c9d42..da0423735b 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/PlatformUtil.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/PlatformUtil.java @@ -30,6 +30,8 @@ import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; import java.lang.management.MemoryUsage; import java.nio.charset.Charset; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -211,37 +213,31 @@ public class PlatformUtil { * * @param resourceClass class in the same package as the resourceFile to * extract - * @param resourceFile resource file name to extract + * @param resourceFileName Name of the resource file to extract * @param overWrite true to overwrite an existing resource * @return true if extracted, false otherwise (if file already exists) * @throws IOException exception thrown if extract the file failed for IO * reasons */ - public static boolean extractResourceToUserConfigDir(final Class resourceClass, final String resourceFile, boolean overWrite) throws IOException { - final File userDir = new File(getUserConfigDirectory()); - - final File resourceFileF = new File(userDir + File.separator + resourceFile); - if (resourceFileF.exists() && !overWrite) { + public static boolean extractResourceToUserConfigDir(final Class resourceClass, final String resourceFileName, boolean overWrite) throws IOException { + Path resourceFilePath = Paths.get(getUserConfigDirectory(), resourceFileName); + final File resourceFile = resourceFilePath.toFile(); + if (resourceFile.exists() && !overWrite) { return false; } - resourceFileF.getParentFile().mkdirs(); + InputStream inputStream = resourceClass.getResourceAsStream(resourceFileName); + if (null == inputStream) { + return false; + } - InputStream inputStream = resourceClass.getResourceAsStream(resourceFile); - - OutputStream out = null; + resourceFile.getParentFile().mkdirs(); try (InputStream in = new BufferedInputStream(inputStream)) { - - OutputStream outFile = new FileOutputStream(resourceFileF); - out = new BufferedOutputStream(outFile); - int readBytes; - while ((readBytes = in.read()) != -1) { - out.write(readBytes); - } - } finally { - if (out != null) { - out.flush(); - out.close(); + try (OutputStream out = new BufferedOutputStream(new FileOutputStream(resourceFile))) { + int readBytes; + while ((readBytes = in.read()) != -1) { + out.write(readBytes); + } } } return true; diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties index fbf61da330..b0dc119618 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties @@ -10,7 +10,6 @@ FileTypeIdIngestJobSettingsPanel.skipKnownCheckBox.toolTipText=Depending on how FileTypeIdIngestJobSettingsPanel.skipKnownCheckBox.text=Skip known files (NSRL) FileTypeIdGlobalSettingsPanel.hexPrefixLabel.text=0x FileTypeIdGlobalSettingsPanel.deleteTypeButton.text=DeleteType -FileTypeIdGlobalSettingsPanel.newTypeButton.text=New Type FileTypeIdGlobalSettingsPanel.offsetTextField.text= FileTypeIdGlobalSettingsPanel.offsetLabel.text=Offset FileTypeIdGlobalSettingsPanel.postHitCheckBox.text=Post interesting file hit when found @@ -28,10 +27,18 @@ FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignature.message=Signature is FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignature.title=Missing Signature FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message=Offset must be a positive integer. FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.title=Invalid Offset -FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignatureBytes.message=The signature must be able to be converted to UTF-8 bytes. +FileTypeIdGlobalSettingsPanel.JOptionPane.invalidRawSignatureBytes.message=The signature has one or more invalid hexadecimal digits. +FileTypeIdGlobalSettingsPanel.JOptionPane.invalidAsciiSignatureBytes.message=The signature must be able to be converted to UTF-8 bytes. FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignatureBytes.title=Invalid Signature +FileTypeIdGlobalSettingsPanel.JOptionPane.invalidInterestingFilesSetName.message=Interesting files set name is required if alert is requests. +FileTypeIdGlobalSettingsPanel.JOptionPane.invalidInterestingFilesSetName.title=Missing Interesting Files Set Name FileTypeIdGlobalSettingsPanel.filesSetNameLabel.text=Files Set Name FileTypeIdGlobalSettingsPanel.filesSetNameTextField.text= FileTypeIdGlobalSettingsPanel.JOptionPane.storeFailed.title=Save Failed +FileTypeIdGlobalSettingsPanel.JOptionPane.loadFailed.title=Load Failed FileTypeIdGlobalSettingsPanel.hintTextArea.text=Enter a MIME type and signature to be used to identify files of that type. If the signature is a byte sequence, enter the sequence using two hex values for each byte, e.g., EEF0 is a two byte signature. -FileTypeIdGlobalSettingsPanel.ingestRunningWarningLabel.text=Cannot make changes to file type definitions when ingest is running +FileTypeIdGlobalSettingsPanel.ingestRunningWarningLabel.text=Cannot make changes to file type definitions when ingest is running! +UserDefinedFileTypesManager.loadFileTypes.errorMessage=Failed to load existing file type definitions. +UserDefinedFileTypesManager.saveFileTypes.errorMessage=Failed to save file type definitions. +FileTypeIdIngestJobSettingsPanel.skipSmallFilesCheckBox.text=Skip files smaller than {0} bytes +FileTypeIdGlobalSettingsPanel.newTypeButton.text=New Type diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form index 8c04fa7747..bf19d17803 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form @@ -1,6 +1,14 @@

+ + + + + + + + @@ -17,7 +25,7 @@ - + @@ -25,31 +33,22 @@ + - - - - - - - - - + + + - + - - - - + - @@ -73,7 +72,20 @@ - + + + + + + + + + + + + + + @@ -83,55 +95,59 @@ - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - + @@ -149,6 +165,9 @@ + + + @@ -280,6 +299,9 @@ + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java index 83bc32d167..abc61ac884 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -33,12 +33,12 @@ import javax.swing.event.DocumentListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.xml.bind.DatatypeConverter; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; import org.sleuthkit.autopsy.modules.filetypeid.FileType.Signature; +import org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException; /** * A panel to allow a user to make custom file type definitions. In addition to @@ -187,7 +187,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane boolean fileTypeIsSelected = typesList.getSelectedIndex() != -1; deleteTypeButton.setEnabled(!ingestIsRunning && fileTypeIsSelected); - + boolean requiredFieldsPopulated = !mimeTypeTextField.getText().isEmpty() && !offsetTextField.getText().isEmpty() @@ -203,10 +203,18 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane */ @Override public void load() { - fileTypes = UserDefinedFileTypesManager.getInstance().getUserDefinedFileTypes(); - updateFileTypesListModel(); - if (!typesListModel.isEmpty()) { - typesList.setSelectedIndex(0); + try { + fileTypes = UserDefinedFileTypesManager.getInstance().getUserDefinedFileTypes(); + updateFileTypesListModel(); + if (!typesListModel.isEmpty()) { + typesList.setSelectedIndex(0); + } + } catch (UserDefinedFileTypesException ex) { + JOptionPane.showMessageDialog(null, + ex.getLocalizedMessage(), + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.loadFailed.title"), + JOptionPane.ERROR_MESSAGE); + fileTypes = Collections.emptyMap(); } enableButtons(); } @@ -238,6 +246,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane this.signatureTextField.setText(DatatypeConverter.printHexBinary(signature.getSignatureBytes())); offsetTextField.setText(Long.toString(signature.getOffset())); postHitCheckBox.setSelected(fileType.alertOnMatch()); + filesSetNameTextField.setEnabled(postHitCheckBox.isSelected()); filesSetNameTextField.setText(fileType.getFilesSetName()); } enableButtons(); @@ -248,7 +257,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane * the panel. */ private void clearTypeDetailsComponents() { - typesList.setSelectedIndex(-1); + typesList.clearSelection(); mimeTypeTextField.setText(""); //NON-NLS signatureTypeComboBox.setSelectedItem(FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM); hexPrefixLabel.setVisible(true); @@ -324,6 +333,10 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane filesSetNameTextField = new javax.swing.JTextField(); ingestRunningWarningLabel = new javax.swing.JLabel(); + setMaximumSize(new java.awt.Dimension(500, 300)); + setPreferredSize(new java.awt.Dimension(500, 300)); + + typesList.setMinimumSize(new java.awt.Dimension(200, 0)); typesScrollPane.setViewportView(typesList); separator.setOrientation(javax.swing.SwingConstants.VERTICAL); @@ -378,6 +391,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane hintTextArea.setRows(5); hintTextArea.setText(org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.hintTextArea.text")); // NOI18N hintTextArea.setWrapStyleWord(true); + hintTextArea.setPreferredSize(new java.awt.Dimension(164, 70)); hintScrollPane.setViewportView(hintTextArea); org.openide.awt.Mnemonics.setLocalizedText(postHitCheckBox, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.postHitCheckBox.text")); // NOI18N @@ -399,33 +413,26 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(26, 26, 26) + .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(ingestRunningWarningLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGap(30, 30, 30)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(typesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() - .addComponent(typesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addComponent(newTypeButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(deleteTypeButton) - .addGap(9, 9, 9))) + .addGap(0, 97, Short.MAX_VALUE))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(separator, javax.swing.GroupLayout.PREFERRED_SIZE, 13, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(offsetLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(filesSetNameLabel)) + .addComponent(offsetLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(offsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 178, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(filesSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 179, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) .addComponent(signatureLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) @@ -443,52 +450,69 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane .addComponent(signatureTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 160, javax.swing.GroupLayout.PREFERRED_SIZE))))) .addComponent(hintScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 260, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(postHitCheckBox) - .addComponent(saveTypeButton)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(filesSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 179, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(newTypeButton, javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(saveTypeButton)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(filesSetNameLabel) + .addGap(188, 188, 188))))) .addGap(29, 29, 29)))) ); + + layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {deleteTypeButton, newTypeButton, saveTypeButton}); + layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(16, 16, 16) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(separator, javax.swing.GroupLayout.PREFERRED_SIZE, 281, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(hintScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(mimeTypeLabel) - .addComponent(mimeTypeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(hintScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 76, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(mimeTypeLabel) + .addComponent(mimeTypeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(signatureTypeLabel) + .addComponent(signatureTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(signatureTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(hexPrefixLabel) + .addComponent(signatureLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(offsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(offsetLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(postHitCheckBox) + .addGap(1, 1, 1) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(filesSetNameLabel) + .addComponent(filesSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(typesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 219, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(signatureTypeLabel) - .addComponent(signatureTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(signatureTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(hexPrefixLabel) - .addComponent(signatureLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(offsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(offsetLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(postHitCheckBox) - .addGap(8, 8, 8) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(filesSetNameLabel) - .addComponent(filesSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(saveTypeButton)) - .addGroup(layout.createSequentialGroup() - .addComponent(typesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 249, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(deleteTypeButton) - .addComponent(newTypeButton)))) + .addComponent(newTypeButton) + .addComponent(saveTypeButton))) + .addGroup(layout.createSequentialGroup() + .addGap(11, 11, 11) + .addComponent(separator, javax.swing.GroupLayout.PREFERRED_SIZE, 257, javax.swing.GroupLayout.PREFERRED_SIZE))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(ingestRunningWarningLabel) - .addContainerGap(22, Short.MAX_VALUE)) + .addContainerGap(18, Short.MAX_VALUE)) ); + + layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {deleteTypeButton, newTypeButton, saveTypeButton}); + }// //GEN-END:initComponents private void newTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTypeButtonActionPerformed @@ -498,82 +522,90 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane private void deleteTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTypeButtonActionPerformed String typeName = typesList.getSelectedValue(); fileTypes.remove(typeName); - clearTypeDetailsComponents(); + updateFileTypesListModel(); + if (!typesListModel.isEmpty()) { + typesList.setSelectedIndex(0); + } }//GEN-LAST:event_deleteTypeButtonActionPerformed private void saveTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveTypeButtonActionPerformed - try { - /** - * Get the MIME type. - */ - String typeName = mimeTypeTextField.getText(); - if (typeName.isEmpty()) { - JOptionPane.showMessageDialog(null, - NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidMIMEType.message"), - NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidMIMEType.title"), - JOptionPane.ERROR_MESSAGE); - return; - } + /** + * Get the MIME type. + */ + String typeName = mimeTypeTextField.getText(); + if (typeName.isEmpty()) { + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidMIMEType.message"), + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidMIMEType.title"), + JOptionPane.ERROR_MESSAGE); + return; + } - /** - * Get the signature type. - */ - FileType.Signature.Type sigType = signatureTypeComboBox.getSelectedItem() == FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM ? FileType.Signature.Type.RAW : FileType.Signature.Type.ASCII; + /** + * Get the signature type. + */ + FileType.Signature.Type sigType = signatureTypeComboBox.getSelectedItem() == FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM ? FileType.Signature.Type.RAW : FileType.Signature.Type.ASCII; - /** - * Get the signature bytes. - */ - String sigString = signatureTextField.getText(); - if (sigString.isEmpty()) { - JOptionPane.showMessageDialog(null, - NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignature.message"), - NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignature.title"), - JOptionPane.ERROR_MESSAGE); - return; - } - byte[] signatureBytes; - if (FileType.Signature.Type.RAW == sigType) { + /** + * Get the signature bytes. + */ + String sigString = signatureTextField.getText(); + if (sigString.isEmpty()) { + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignature.message"), + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignature.title"), + JOptionPane.ERROR_MESSAGE); + return; + } + byte[] signatureBytes; + if (FileType.Signature.Type.RAW == sigType) { + try { signatureBytes = DatatypeConverter.parseHexBinary(sigString); - } else { - signatureBytes = sigString.getBytes(Charset.forName("UTF-8")); - } - - /** - * Get the offset. - */ - long offset = Long.parseUnsignedLong(offsetTextField.getText()); - - /** - * Get the interesting files set details. - */ - String filesSetName = filesSetNameTextField.getText(); - if (postHitCheckBox.isSelected() && filesSetName.isEmpty()) { + } catch (IllegalArgumentException ex) { JOptionPane.showMessageDialog(null, - NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message"), - NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.title"), + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidRawSignatureBytes.message"), + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignatureBytes.title"), JOptionPane.ERROR_MESSAGE); + return; } + } else { + signatureBytes = sigString.getBytes(Charset.forName("UTF-8")); + } - /** - * Put it all together and reset the file types list component. - */ - FileType.Signature signature = new FileType.Signature(signatureBytes, offset, sigType); - FileType fileType = new FileType(typeName, signature, filesSetName, postHitCheckBox.isSelected()); - fileTypes.put(typeName, fileType); - updateFileTypesListModel(); - typesList.setSelectedValue(fileType.getMimeType(), true); - + /** + * Get the offset. + */ + long offset; + try { + offset = Long.parseUnsignedLong(offsetTextField.getText()); } catch (NumberFormatException ex) { JOptionPane.showMessageDialog(null, NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message"), NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.title"), JOptionPane.ERROR_MESSAGE); - } catch (IllegalArgumentException ex) { - JOptionPane.showMessageDialog(null, - NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignatureBytes.message"), - NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignatureBytes.title"), - JOptionPane.ERROR_MESSAGE); + return; } + + /** + * Get the interesting files set details. + */ + String filesSetName = filesSetNameTextField.getText(); + if (postHitCheckBox.isSelected() && filesSetName.isEmpty()) { + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidInterestingFilesSetName.message"), + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidInterestingFilesSetName.title"), + JOptionPane.ERROR_MESSAGE); + return; + } + + /** + * Put it all together and reset the file types list component. + */ + FileType.Signature signature = new FileType.Signature(signatureBytes, offset, sigType); + FileType fileType = new FileType(typeName, signature, filesSetName, postHitCheckBox.isSelected()); + fileTypes.put(typeName, fileType); + updateFileTypesListModel(); + typesList.setSelectedValue(fileType.getMimeType(), true); }//GEN-LAST:event_saveTypeButtonActionPerformed private void postHitCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_postHitCheckBoxActionPerformed diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.form index 7a24e05f05..f03a25070c 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.form @@ -18,7 +18,10 @@ - + + + + @@ -28,7 +31,9 @@ - + + + @@ -48,5 +53,15 @@ + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.java index ff65c1ac63..87dd8dd53e 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.modules.filetypeid; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; @@ -49,8 +50,10 @@ class FileTypeIdIngestJobSettingsPanel extends IngestModuleIngestJobSettingsPane */ private void customizeComponents() { skipKnownCheckBox.setSelected(settings.skipKnownFiles()); + skipSmallFilesCheckBox.setSelected(settings.skipSmallFiles()); + skipSmallFilesCheckBox.setText(NbBundle.getMessage(FileTypeIdIngestJobSettingsPanel.class, "FileTypeIdIngestJobSettingsPanel.skipSmallFilesCheckBox.text", settings.minFileSizeInBytes())); } - + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -61,6 +64,7 @@ class FileTypeIdIngestJobSettingsPanel extends IngestModuleIngestJobSettingsPane private void initComponents() { skipKnownCheckBox = new javax.swing.JCheckBox(); + skipSmallFilesCheckBox = new javax.swing.JCheckBox(); skipKnownCheckBox.setSelected(true); skipKnownCheckBox.setText(org.openide.util.NbBundle.getMessage(FileTypeIdIngestJobSettingsPanel.class, "FileTypeIdIngestJobSettingsPanel.skipKnownCheckBox.text")); // NOI18N @@ -71,13 +75,22 @@ class FileTypeIdIngestJobSettingsPanel extends IngestModuleIngestJobSettingsPane } }); + skipSmallFilesCheckBox.setText(org.openide.util.NbBundle.getMessage(FileTypeIdIngestJobSettingsPanel.class, "FileTypeIdIngestJobSettingsPanel.skipSmallFilesCheckBox.text")); // NOI18N + skipSmallFilesCheckBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + skipSmallFilesCheckBoxActionPerformed(evt); + } + }); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(10, 10, 10) - .addComponent(skipKnownCheckBox) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(skipSmallFilesCheckBox) + .addComponent(skipKnownCheckBox)) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); layout.setVerticalGroup( @@ -85,14 +98,22 @@ class FileTypeIdIngestJobSettingsPanel extends IngestModuleIngestJobSettingsPane .addGroup(layout.createSequentialGroup() .addGap(11, 11, 11) .addComponent(skipKnownCheckBox) - .addContainerGap(47, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(skipSmallFilesCheckBox) + .addContainerGap(60, Short.MAX_VALUE)) ); }// //GEN-END:initComponents private void skipKnownCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_skipKnownCheckBoxActionPerformed settings.setSkipKnownFiles(skipKnownCheckBox.isSelected()); }//GEN-LAST:event_skipKnownCheckBoxActionPerformed + + private void skipSmallFilesCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_skipSmallFilesCheckBoxActionPerformed + settings.setSkipSmallFiles(skipSmallFilesCheckBox.isSelected()); + }//GEN-LAST:event_skipSmallFilesCheckBoxActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JCheckBox skipKnownCheckBox; + private javax.swing.JCheckBox skipSmallFilesCheckBox; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java index 6d6a1796e5..2759180c26 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java @@ -20,8 +20,10 @@ package org.sleuthkit.autopsy.modules.filetypeid; import java.util.HashMap; import java.util.logging.Level; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.ingest.FileIngestModule; import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.autopsy.ingest.IngestMessage; @@ -43,7 +45,6 @@ import org.sleuthkit.datamodel.BlackboardAttribute; public class FileTypeIdIngestModule implements FileIngestModule { private static final Logger logger = Logger.getLogger(FileTypeIdIngestModule.class.getName()); - private static final long MIN_FILE_SIZE = 512; private final FileTypeIdModuleSettings settings; private long jobId; private static final HashMap totalsForIngestJobs = new HashMap<>(); @@ -76,7 +77,13 @@ public class FileTypeIdIngestModule implements FileIngestModule { */ FileTypeIdIngestModule(FileTypeIdModuleSettings settings) { this.settings = settings; - this.userDefinedFileTypeIdentifier = new UserDefinedFileTypeIdentifier(); + userDefinedFileTypeIdentifier = new UserDefinedFileTypeIdentifier(); + try { + userDefinedFileTypeIdentifier.loadFileTypes(); + } catch (UserDefinedFileTypesManager.UserDefinedFileTypesException ex) { + logger.log(Level.SEVERE, "Failed to load file types", ex); + MessageNotifyUtil.Notify.error(FileTypeIdModuleFactory.getModuleName(), ex.getMessage()); + } } /** @@ -112,11 +119,10 @@ public class FileTypeIdIngestModule implements FileIngestModule { /** * Filter out very small files to minimize false positives. */ - // RJCTODO: Make this size a setting -// if (file.getSize() < MIN_FILE_SIZE) { -// return ProcessResult.OK; -// } - + if (settings.skipSmallFiles() && file.getSize() < settings.minFileSizeInBytes()) { + return ProcessResult.OK; + } + try { long startTime = System.currentTimeMillis(); FileType fileType = this.userDefinedFileTypeIdentifier.identify(file); @@ -133,7 +139,8 @@ public class FileTypeIdIngestModule implements FileIngestModule { /** * Use the MIME type as the category, i.e., the rule that - * determined this file belongs to the interesting files set. + * determined this file belongs to the interesting files + * set. */ BlackboardAttribute ruleNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY.getTypeID(), moduleName, fileType.getMimeType()); artifact.addAttribute(ruleNameAttribute); diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java index ddf5371045..2b774451a5 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java @@ -27,23 +27,26 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; public class FileTypeIdModuleSettings implements IngestModuleIngestJobSettings { private static final long serialVersionUID = 1L; - private volatile boolean skipKnownFiles = true; + private static final long MIN_FILE_SIZE_IN_BYTES = 512; + private boolean skipKnownFiles = true; + private boolean skipSmallFiles = true; FileTypeIdModuleSettings() { } - FileTypeIdModuleSettings(boolean skipKnownFiles) { + FileTypeIdModuleSettings(boolean skipKnownFiles, boolean skipSmallFiles) { this.skipKnownFiles = skipKnownFiles; + this.skipSmallFiles = skipSmallFiles; } - + /** * @inheritDoc */ @Override public long getVersionNumber() { return serialVersionUID; - } - + } + void setSkipKnownFiles(boolean enabled) { skipKnownFiles = enabled; } @@ -51,4 +54,17 @@ public class FileTypeIdModuleSettings implements IngestModuleIngestJobSettings { boolean skipKnownFiles() { return skipKnownFiles; } -} \ No newline at end of file + + void setSkipSmallFiles(boolean enabled) { + this.skipKnownFiles = enabled; + } + + boolean skipSmallFiles() { + return skipSmallFiles; + } + + long minFileSizeInBytes() { + return MIN_FILE_SIZE_IN_BYTES; + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDefinitions.xsd b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypes.xsd similarity index 81% rename from Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDefinitions.xsd rename to Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypes.xsd index f0ec8fa6c4..26aa720ff1 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDefinitions.xsd +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypes.xsd @@ -5,7 +5,7 @@ - + @@ -26,23 +26,23 @@ - + - + - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java index c93cc9a547..f756785585 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypeIdentifier.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.modules.filetypeid; +import java.util.HashMap; import java.util.Map; import org.sleuthkit.datamodel.AbstractFile; @@ -26,14 +27,25 @@ import org.sleuthkit.datamodel.AbstractFile; */ final class UserDefinedFileTypeIdentifier { - private final Map fileTypes; + private Map fileTypes; /** * Creates an object that can do file type identification for user-defined * file types. */ UserDefinedFileTypeIdentifier() { - this.fileTypes = UserDefinedFileTypesManager.getInstance().getFileTypes(); + fileTypes = new HashMap<>(); + } + + /** + * Gets the user-defined file types from the user-defined file types + * manager. + * + * @throws + * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException + */ + void loadFileTypes() throws UserDefinedFileTypesManager.UserDefinedFileTypesException { + fileTypes = UserDefinedFileTypesManager.getInstance().getFileTypes(); } /** diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java index c07607c41d..293ac805bd 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java @@ -36,6 +36,7 @@ import org.w3c.dom.Element; import org.w3c.dom.NodeList; import javax.xml.bind.DatatypeConverter; import javax.xml.transform.TransformerException; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.XMLUtil; @@ -50,18 +51,17 @@ import org.xml.sax.SAXException; * user-defined file types as a complete set - there is no concept of adding, * editing or deleting file types singly. This works because this class is not * exposed outside of this ingest module package and is ONLY used in a very - * specific paradigm where there is a single modal writer of file types in the - * form of a global settings panel that disables itself when ingest is running - * so that multiple readers in the form of file ingest modules get a consistent - * set of file type definitions. Moreover, there is no enforcement of compliance - * with this paradigm by this class - it merely participates in the scheme. + * specific paradigm. In this paradigm, there is a single modal writer of file + * types in the form of a global settings panel that disables itself when ingest + * is running so that multiple readers in the form of file ingest modules get a + * consistent set of file type definitions. *

* Thread-safe. */ final class UserDefinedFileTypesManager { private static final Logger logger = Logger.getLogger(UserDefinedFileTypesManager.class.getName()); - private static final String FILE_TYPE_DEFINITIONS_SCHEMA_FILE = "FileTypeDefinitions.xsd"; //NON-NLS + private static final String FILE_TYPE_DEFINITIONS_SCHEMA_FILE = "FileTypes.xsd"; //NON-NLS private static final String USER_DEFINED_TYPE_DEFINITIONS_FILE = "UserFileTypeDefinitions.xml"; //NON-NLS private static final String FILE_TYPES_TAG_NAME = "FileTypes"; //NON-NLS private static final String FILE_TYPE_TAG_NAME = "FileType"; //NON-NLS @@ -76,13 +76,6 @@ final class UserDefinedFileTypesManager { private static final String ASCII_ENCODING = "US-ASCII"; //NON-NLS private static UserDefinedFileTypesManager instance; - /** - * Predefined file types are stored in this mapping of MIME types to file - * types. Access to this map is guarded by the intrinsic lock of the - * user-defined file types manager for thread-safety. - */ - private final Map predefinedFileTypes = new HashMap<>(); - /** * File types to be persisted to the user-defined file type definitions file * are stored in this mapping of MIME types to file types. Access to this @@ -101,16 +94,17 @@ final class UserDefinedFileTypesManager { private final Map fileTypes = new HashMap<>(); /** - * Gets the manager of user-defined file types characterized by MIME type, - * signature, and optional membership in an interesting files set. + * Gets the singleton manager of user-defined file types characterized by + * MIME type, signature, and optional membership in an interesting files + * set. * * @return The user-defined file types manager singleton. */ synchronized static UserDefinedFileTypesManager getInstance() { - if (UserDefinedFileTypesManager.instance == null) { - UserDefinedFileTypesManager.instance = new UserDefinedFileTypesManager(); + if (instance == null) { + instance = new UserDefinedFileTypesManager(); } - return UserDefinedFileTypesManager.instance; + return instance; } /** @@ -120,29 +114,70 @@ final class UserDefinedFileTypesManager { private UserDefinedFileTypesManager() { } + /** + * Gets both the predefined and the user-defined file types. + * + * @return A mapping of file type names to file types, possibly empty. + * @throws + * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException + */ + synchronized Map getFileTypes() throws UserDefinedFileTypesException { + loadFileTypes(); + + /** + * It is safe to return references to the internal file type objects + * because they are immutable. Note that + * Collections.unmodifiableCollection() is not used here because this + * view of the file types is a snapshot. + */ + return new HashMap<>(fileTypes); + } + + /** + * Gets the user-defined file types. + * + * @return A mapping of file type names to file types, possibly empty. + * @throws + * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException + */ + synchronized Map getUserDefinedFileTypes() throws UserDefinedFileTypesException { + loadFileTypes(); + + /** + * It is safe to return references to the internal file type objects + * because they are immutable. Note that + * Collections.unmodifiableCollection() is not used here because this + * view of the file types is a snapshot. + */ + return new HashMap<>(userDefinedFileTypes); + } + + /** + * Loads the MIME type to file type mappings with predefined and + * user-defined types. + * + * @throws + * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException + */ + private void loadFileTypes() throws UserDefinedFileTypesException { + fileTypes.clear(); + userDefinedFileTypes.clear(); + /** + * Load the predefined types first so that they can be overwritten by + * any user-defined types with the same names. + */ + loadPredefinedFileTypes(); + loadUserDefinedFileTypes(); + } + /** * Adds the predefined file types to the in-memory mappings of MIME types to * file types. + * + * @throws + * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException */ - private void loadPredefinedFileTypes() { - // RJCTODO: Remove test file type. - /** - * Create a file type that should match $MBR in Small2 image. - */ - FileType fileType = new FileType("predefinedRAW", new Signature(new byte[]{(byte) 0x66, (byte) 0x73, (byte) 0x00}, 8L, FileType.Signature.Type.RAW), "Suspicious", true); - this.addPredefinedFileType(fileType); - - /** - * Create a file type that should match test.txt in the Small2 image. - */ - // RJCTODO: Remove test file type. - try { - fileType = new FileType("predefinedASCII", new Signature("hello".getBytes(UserDefinedFileTypesManager.ASCII_ENCODING), 0L, FileType.Signature.Type.ASCII), "Benign", true); - this.addPredefinedFileType(fileType); - } catch (UnsupportedEncodingException ex) { - UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Unable to create 'predefinedASCII' predefined file type definition", ex); //NON-NLS - } - + private void loadPredefinedFileTypes() throws UserDefinedFileTypesException { try { // RJCTODO: Remove this code from TikaFileTypeDetector.java. // try { @@ -166,39 +201,32 @@ final class UserDefinedFileTypesManager { // catch (IndexOutOfBoundsException e) { // // do nothing // } - fileType = new FileType("text/xml", new Signature(" getFileTypes() { - /** - * Load the predefined types first so that they can be overwritten by - * any user-defined types with the same names. - */ - loadPredefinedFileTypes(); - loadUserDefinedFileTypes(); - - /** - * It is safe to return references to the internal file type objects - * because they are immutable. - */ - return new HashMap<>(this.fileTypes); - } - - /** - * Gets the user-defined file types. - * - * @return A mapping of file type names to file types, possibly empty. - */ - synchronized Map getUserDefinedFileTypes() { - /** - * Load the predefined types first so that they can be overwritten by - * any user-defined types with the same names. - */ - loadPredefinedFileTypes(); - loadUserDefinedFileTypes(); - - /** - * It is safe to return references to the internal file type objects - * because they are immutable. - */ - return new HashMap<>(this.userDefinedFileTypes); + userDefinedFileTypes.put(fileType.getMimeType(), fileType); + fileTypes.put(fileType.getMimeType(), fileType); } /** @@ -269,35 +257,15 @@ final class UserDefinedFileTypesManager { * @param newFileTypes A mapping of file type names to user-defined file * types. */ - synchronized void setUserDefinedFileTypes(Map newFileTypes) throws UserDefinedFileTypesManager.UserDefinedFileTypesException { + synchronized void setUserDefinedFileTypes(Map newFileTypes) throws UserDefinedFileTypesException { try { - String filePath = UserDefinedFileTypesManager.getFileTypeDefinitionsFilePath(UserDefinedFileTypesManager.USER_DEFINED_TYPE_DEFINITIONS_FILE); - UserDefinedFileTypesManager.XmlWriter.writeFileTypes(newFileTypes.values(), filePath); - + String filePath = getFileTypeDefinitionsFilePath(USER_DEFINED_TYPE_DEFINITIONS_FILE); + XmlWriter.writeFileTypes(newFileTypes.values(), filePath); } catch (ParserConfigurationException | FileNotFoundException | UnsupportedEncodingException | TransformerException ex) { - UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Failed to write file types file", ex); - throw new UserDefinedFileTypesManager.UserDefinedFileTypesException(ex.getLocalizedMessage()); + throwUserDefinedFileTypesException(ex, "UserDefinedFileTypesManager.saveFileTypes.errorMessage"); } catch (IOException ex) { - UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Failed to write file types file", ex); - throw new UserDefinedFileTypesManager.UserDefinedFileTypesException(ex.getLocalizedMessage()); + throwUserDefinedFileTypesException(ex, "UserDefinedFileTypesManager.saveFileTypes.errorMessage"); } - - /** - * Clear and reinitialize the user-defined file type map. It is safe to - * hold references to file type objects obtained for the caller because - * they are immutable. - */ - this.userDefinedFileTypes.clear(); - this.userDefinedFileTypes.putAll(newFileTypes); - - /** - * Clear and reinitialize the combined file type map, loading the - * predefined types first so that they can be overwritten by any - * user-defined types with the same names. - */ - this.fileTypes.clear(); - this.fileTypes.putAll(this.predefinedFileTypes); - this.fileTypes.putAll(this.userDefinedFileTypes); } /** @@ -330,13 +298,13 @@ final class UserDefinedFileTypesManager { */ private static void writeFileTypes(Collection fileTypes, String filePath) throws ParserConfigurationException, IOException, FileNotFoundException, UnsupportedEncodingException, TransformerException { Document doc = XMLUtil.createDocument(); - Element fileTypesElem = doc.createElement(UserDefinedFileTypesManager.FILE_TYPES_TAG_NAME); + Element fileTypesElem = doc.createElement(FILE_TYPES_TAG_NAME); doc.appendChild(fileTypesElem); for (FileType fileType : fileTypes) { - Element fileTypeElem = UserDefinedFileTypesManager.XmlWriter.createFileTypeElement(fileType, doc); + Element fileTypeElem = XmlWriter.createFileTypeElement(fileType, doc); fileTypesElem.appendChild(fileTypeElem); } - XMLUtil.saveDocument(doc, UserDefinedFileTypesManager.ENCODING_FOR_XML_FILE, filePath); + XMLUtil.saveDocument(doc, ENCODING_FOR_XML_FILE, filePath); } /** @@ -347,7 +315,7 @@ final class UserDefinedFileTypesManager { * @return An XML element. */ private static Element createFileTypeElement(FileType fileType, Document doc) { - Element fileTypeElem = doc.createElement(UserDefinedFileTypesManager.FILE_TYPE_TAG_NAME); + Element fileTypeElem = doc.createElement(FILE_TYPE_TAG_NAME); XmlWriter.addMimeTypeElement(fileType, fileTypeElem, doc); XmlWriter.addSignatureElement(fileType, fileTypeElem, doc); XmlWriter.addInterestingFilesSetElement(fileType, fileTypeElem, doc); @@ -363,7 +331,7 @@ final class UserDefinedFileTypesManager { * @param doc The WC3 DOM object to use to create the XML. */ private static void addMimeTypeElement(FileType fileType, Element fileTypeElem, Document doc) { - Element typeNameElem = doc.createElement(UserDefinedFileTypesManager.MIME_TYPE_TAG_NAME); + Element typeNameElem = doc.createElement(MIME_TYPE_TAG_NAME); typeNameElem.setTextContent(fileType.getMimeType()); fileTypeElem.appendChild(typeNameElem); } @@ -377,17 +345,17 @@ final class UserDefinedFileTypesManager { */ private static void addSignatureElement(FileType fileType, Element fileTypeElem, Document doc) { Signature signature = fileType.getSignature(); - Element signatureElem = doc.createElement(UserDefinedFileTypesManager.SIGNATURE_TAG_NAME); + Element signatureElem = doc.createElement(SIGNATURE_TAG_NAME); - Element bytesElem = doc.createElement(UserDefinedFileTypesManager.BYTES_TAG_NAME); + Element bytesElem = doc.createElement(BYTES_TAG_NAME); bytesElem.setTextContent(DatatypeConverter.printHexBinary(signature.getSignatureBytes())); signatureElem.appendChild(bytesElem); - Element offsetElem = doc.createElement(UserDefinedFileTypesManager.OFFSET_TAG_NAME); + Element offsetElem = doc.createElement(OFFSET_TAG_NAME); offsetElem.setTextContent(DatatypeConverter.printLong(signature.getOffset())); signatureElem.appendChild(offsetElem); - signatureElem.setAttribute(UserDefinedFileTypesManager.SIGNATURE_TYPE_ATTRIBUTE, signature.getType().toString()); + signatureElem.setAttribute(SIGNATURE_TYPE_ATTRIBUTE, signature.getType().toString()); fileTypeElem.appendChild(signatureElem); } @@ -399,9 +367,11 @@ final class UserDefinedFileTypesManager { * @param doc The WC3 DOM object to use to create the XML. */ private static void addInterestingFilesSetElement(FileType fileType, Element fileTypeElem, Document doc) { - Element filesSetElem = doc.createElement(UserDefinedFileTypesManager.INTERESTING_FILES_SET_TAG_NAME); - filesSetElem.setTextContent(fileType.getFilesSetName()); - fileTypeElem.appendChild(filesSetElem); + if (!fileType.getFilesSetName().isEmpty()) { + Element filesSetElem = doc.createElement(INTERESTING_FILES_SET_TAG_NAME); + filesSetElem.setTextContent(fileType.getFilesSetName()); + fileTypeElem.appendChild(filesSetElem); + } } /** @@ -411,7 +381,7 @@ final class UserDefinedFileTypesManager { * @param fileTypeElem The parent file type element. */ private static void addAlertAttribute(FileType fileType, Element fileTypeElem) { - fileTypeElem.setAttribute(UserDefinedFileTypesManager.ALERT_ATTRIBUTE, Boolean.toString(fileType.alertOnMatch())); + fileTypeElem.setAttribute(ALERT_ATTRIBUTE, Boolean.toString(fileType.alertOnMatch())); } } @@ -430,12 +400,11 @@ final class UserDefinedFileTypesManager { */ private static List readFileTypes(String filePath) throws IOException, ParserConfigurationException, SAXException { List fileTypes = new ArrayList<>(); - Document doc = XMLUtil.loadDocument(filePath, UserDefinedFileTypesManager.class, UserDefinedFileTypesManager.FILE_TYPE_DEFINITIONS_SCHEMA_FILE); -// Document doc = XMLUtil.loadDocument(filePath); + Document doc = XMLUtil.loadDocument(filePath, UserDefinedFileTypesManager.class, FILE_TYPE_DEFINITIONS_SCHEMA_FILE); if (doc != null) { Element fileTypesElem = doc.getDocumentElement(); - if (fileTypesElem != null && fileTypesElem.getNodeName().equals(UserDefinedFileTypesManager.FILE_TYPES_TAG_NAME)) { - NodeList fileTypeElems = fileTypesElem.getElementsByTagName(UserDefinedFileTypesManager.FILE_TYPE_TAG_NAME); + if (fileTypesElem != null && fileTypesElem.getNodeName().equals(FILE_TYPES_TAG_NAME)) { + NodeList fileTypeElems = fileTypesElem.getElementsByTagName(FILE_TYPE_TAG_NAME); for (int i = 0; i < fileTypeElems.getLength(); ++i) { Element fileTypeElem = (Element) fileTypeElems.item(i); FileType fileType = XmlReader.parseFileType(fileTypeElem); @@ -469,7 +438,7 @@ final class UserDefinedFileTypesManager { * @return A MIME type string. */ private static String parseMimeType(Element fileTypeElem) { - return getChildElementTextContent(fileTypeElem, UserDefinedFileTypesManager.MIME_TYPE_TAG_NAME); + return getChildElementTextContent(fileTypeElem, MIME_TYPE_TAG_NAME); } /** @@ -479,16 +448,16 @@ final class UserDefinedFileTypesManager { * @return The signature. */ private static Signature parseSignature(Element fileTypeElem) throws IllegalArgumentException, NumberFormatException { - NodeList signatureElems = fileTypeElem.getElementsByTagName(UserDefinedFileTypesManager.SIGNATURE_TAG_NAME); + NodeList signatureElems = fileTypeElem.getElementsByTagName(SIGNATURE_TAG_NAME); Element signatureElem = (Element) signatureElems.item(0); - String sigTypeAttribute = signatureElem.getAttribute(UserDefinedFileTypesManager.SIGNATURE_TYPE_ATTRIBUTE); + String sigTypeAttribute = signatureElem.getAttribute(SIGNATURE_TYPE_ATTRIBUTE); Signature.Type signatureType = Signature.Type.valueOf(sigTypeAttribute); - String sigBytesString = getChildElementTextContent(signatureElem, UserDefinedFileTypesManager.BYTES_TAG_NAME); + String sigBytesString = getChildElementTextContent(signatureElem, BYTES_TAG_NAME); byte[] signatureBytes = DatatypeConverter.parseHexBinary(sigBytesString); - String offsetString = getChildElementTextContent(signatureElem, UserDefinedFileTypesManager.OFFSET_TAG_NAME); + String offsetString = getChildElementTextContent(signatureElem, OFFSET_TAG_NAME); long offset = DatatypeConverter.parseLong(offsetString); return new Signature(signatureBytes, offset, signatureType); @@ -502,7 +471,7 @@ final class UserDefinedFileTypesManager { */ private static String parseInterestingFilesSet(Element fileTypeElem) { String filesSetName = ""; - NodeList filesSetElems = fileTypeElem.getElementsByTagName(UserDefinedFileTypesManager.INTERESTING_FILES_SET_TAG_NAME); + NodeList filesSetElems = fileTypeElem.getElementsByTagName(INTERESTING_FILES_SET_TAG_NAME); if (filesSetElems.getLength() > 0) { Element filesSetElem = (Element) filesSetElems.item(0); filesSetName = filesSetElem.getTextContent(); @@ -517,7 +486,7 @@ final class UserDefinedFileTypesManager { * @return True or false; */ private static boolean parseAlert(Element fileTypeElem) { - String alertAttribute = fileTypeElem.getAttribute(UserDefinedFileTypesManager.ALERT_ATTRIBUTE); + String alertAttribute = fileTypeElem.getAttribute(ALERT_ATTRIBUTE); return Boolean.parseBoolean(alertAttribute); } @@ -536,6 +505,22 @@ final class UserDefinedFileTypesManager { } + /** + * Logs an exception, bundles the exception with a simple message in a + * uniform exception type, and throws the wrapper exception. + * + * @param ex The exception to wrap. + * @param messageKey A key into the bundle file that maps to the desired + * message. + * @throws + * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException + */ + private void throwUserDefinedFileTypesException(Exception ex, String messageKey) throws UserDefinedFileTypesException { + String message = NbBundle.getMessage(UserDefinedFileTypesManager.class, messageKey); + logger.log(Level.SEVERE, message, ex); + throw new UserDefinedFileTypesException(message, ex); + } + /** * Used to translate more implementation-details-specific exceptions (which * are logged by this class) into more generic exceptions for propagation to @@ -546,6 +531,10 @@ final class UserDefinedFileTypesManager { UserDefinedFileTypesException(String message) { super(message); } + + UserDefinedFileTypesException(String message, Throwable throwable) { + super(message, throwable); + } } } From f1262af4872970368c7b8addbf15109025cd1aa4 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 22 Dec 2014 21:29:16 -0500 Subject: [PATCH 26/27] Bug fixes for user-defined file types --- .../modules/filetypeid/Bundle.properties | 1 - .../FileTypeIdGlobalSettingsPanel.form | 10 ++-- .../FileTypeIdGlobalSettingsPanel.java | 46 +++++++++++++++---- .../filetypeid/FileTypeIdIngestModule.java | 3 ++ .../filetypeid/FileTypeIdModuleSettings.java | 2 +- 5 files changed, 47 insertions(+), 15 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties index b0dc119618..ef33f85fc6 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties @@ -28,7 +28,6 @@ FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignature.title=Missing Signatu FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message=Offset must be a positive integer. FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.title=Invalid Offset FileTypeIdGlobalSettingsPanel.JOptionPane.invalidRawSignatureBytes.message=The signature has one or more invalid hexadecimal digits. -FileTypeIdGlobalSettingsPanel.JOptionPane.invalidAsciiSignatureBytes.message=The signature must be able to be converted to UTF-8 bytes. FileTypeIdGlobalSettingsPanel.JOptionPane.invalidSignatureBytes.title=Invalid Signature FileTypeIdGlobalSettingsPanel.JOptionPane.invalidInterestingFilesSetName.message=Interesting files set name is required if alert is requests. FileTypeIdGlobalSettingsPanel.JOptionPane.invalidInterestingFilesSetName.title=Missing Interesting Files Set Name diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form index bf19d17803..c168205dad 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form @@ -134,10 +134,12 @@ - - + - + + + + @@ -147,7 +149,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java index abc61ac884..d0847fc63f 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.modules.filetypeid; import java.awt.EventQueue; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; @@ -33,6 +34,7 @@ import javax.swing.event.DocumentListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.xml.bind.DatatypeConverter; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -61,10 +63,13 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane /** * This panel implements a property change listener that listens to ingest - * job events to disable the buttons on the panel if ingest is running. This - * is done to prevent changes to user-defined types while the type - * definitions are in use. + * job events so it can disable the buttons on the panel if ingest is + * running. This is done to prevent changes to user-defined types while the + * type definitions are in use. */ + // TODO: Disabling during ingest would not be necessary if the file ingest + // modules obtained and shared a per data source ingest job snapshot of the + // file type definitions. IngestJobEventPropertyChangeListener ingestJobEventsListener; /** @@ -107,6 +112,11 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane signatureTypeComboBox.setSelectedItem(FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM); } + /** + * Adds a listener to the types list component so that the components in the + * file type details section of the panel can be populated and cleared based + * on the selection in the list. + */ private void addTypeListSelectionListener() { typesList.addListSelectionListener(new ListSelectionListener() { @Override @@ -156,6 +166,9 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane * prevent changes to user-defined types while the type definitions are in * use. */ + // TODO: Disabling during ingest would not be necessary if the file ingest + // modules obtained and shared a per data source ingest job snapshot of the + // file type definitions. private void addIngestJobEventsListener() { ingestJobEventsListener = new IngestJobEventPropertyChangeListener(); IngestManager.getInstance().addIngestJobEventListener(ingestJobEventsListener); @@ -239,11 +252,25 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane String mimeType = typesList.getSelectedValue(); FileType fileType = fileTypes.get(mimeType); if (null != fileType) { - mimeTypeTextField.setText(mimeType); + mimeTypeTextField.setText(fileType.getMimeType()); Signature signature = fileType.getSignature(); FileType.Signature.Type sigType = signature.getType(); signatureTypeComboBox.setSelectedItem(sigType == FileType.Signature.Type.RAW ? FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM : FileTypeIdGlobalSettingsPanel.ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM); - this.signatureTextField.setText(DatatypeConverter.printHexBinary(signature.getSignatureBytes())); + String signatureBytes; + if (Signature.Type.RAW == signature.getType()) { + signatureBytes = DatatypeConverter.printHexBinary(signature.getSignatureBytes()); + } else { + try { + signatureBytes = new String(signature.getSignatureBytes(), "UTF-8"); + } catch (UnsupportedEncodingException ex) { + JOptionPane.showMessageDialog(null, + ex.getLocalizedMessage(), + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.storeFailed.title"), + JOptionPane.ERROR_MESSAGE); + signatureBytes = ""; + } + } + signatureTextField.setText(signatureBytes); offsetTextField.setText(Long.toString(signature.getOffset())); postHitCheckBox.setSelected(fileType.alertOnMatch()); filesSetNameTextField.setEnabled(postHitCheckBox.isSelected()); @@ -499,16 +526,17 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane .addComponent(filesSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) .addComponent(typesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 219, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(deleteTypeButton) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(newTypeButton) - .addComponent(saveTypeButton))) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(deleteTypeButton) + .addComponent(saveTypeButton)))) .addGroup(layout.createSequentialGroup() .addGap(11, 11, 11) .addComponent(separator, javax.swing.GroupLayout.PREFERRED_SIZE, 257, javax.swing.GroupLayout.PREFERRED_SIZE))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(ingestRunningWarningLabel) - .addContainerGap(18, Short.MAX_VALUE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {deleteTypeButton, newTypeButton, saveTypeButton}); diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java index 2759180c26..c3c6bbcb5b 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java @@ -100,6 +100,9 @@ public class FileTypeIdIngestModule implements FileIngestModule { */ @Override public ProcessResult process(AbstractFile file) { + + String name = file.getName(); + /** * Skip unallocated space and unused blocks files. */ diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java index 2b774451a5..270c604d25 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java @@ -56,7 +56,7 @@ public class FileTypeIdModuleSettings implements IngestModuleIngestJobSettings { } void setSkipSmallFiles(boolean enabled) { - this.skipKnownFiles = enabled; + this.skipSmallFiles = enabled; } boolean skipSmallFiles() { From 2dc73333cbb5c6f2dd69091b50f80207c21de3b7 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 22 Dec 2014 21:53:12 -0500 Subject: [PATCH 27/27] Remove XML test from tika file type detector --- .../sleuthkit/autopsy/casemodule/Case.java | 2 +- .../autopsy/ingest/IngestManager.java | 3 +-- .../filetypeid/TikaFileTypeDetector.java | 12 ---------- .../UserDefinedFileTypesManager.java | 22 ------------------- 4 files changed, 2 insertions(+), 37 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 69c9034c15..cb409ad7c7 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -167,7 +167,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * * @throws IllegalStateException if there is no case open. */ - public static Case getCurrentCase() throws IllegalStateException { + public static Case getCurrentCase() { if (currentCase != null) { return currentCase; } else { diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java index 42f518b5e4..b0cb987710 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -470,8 +470,7 @@ public class IngestManager { } /** - * Queries whether or not any ingest jobs are in progress, at least at the - * moment of the query. + * Queries whether or not any ingest jobs are in progress. * * @return True or false. */ diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/TikaFileTypeDetector.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/TikaFileTypeDetector.java index a6ba0e5483..84d1434644 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/TikaFileTypeDetector.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/TikaFileTypeDetector.java @@ -69,18 +69,6 @@ public class TikaFileTypeDetector { buf = buffer; } - // the xml detection in Tika tries to parse the entire file and throws exceptions - // for files that are not valid XML - try { - String tagHeader = new String(buf, 0, 5); - if (tagHeader.equals("