Work on user-defined file types UI

This commit is contained in:
Richard Cordovano 2014-12-05 00:45:01 -05:00
parent a75ebe8028
commit a9bc43e320
5 changed files with 241 additions and 155 deletions

View File

@ -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

View File

@ -35,7 +35,6 @@
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="37" max="-2" attributes="0"/>
<Component id="saveTypeButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
@ -43,18 +42,17 @@
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Group type="103" groupAlignment="1" max="-2" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="signatureTypeLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="signatureTypeComboBox" min="-2" pref="82" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="signatureLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="hexPrefixLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
</Group>
@ -77,8 +75,6 @@
</Group>
</Group>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Component id="jScrollPane2" min="-2" pref="260" max="-2" attributes="0"/>
@ -88,12 +84,9 @@
<Component id="postHitCheckBox" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -141,14 +134,14 @@
</Group>
</Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="saveTypeButton" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<Component id="jSeparator1" min="-2" pref="260" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -167,6 +160,9 @@
<StringArray count="0"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
@ -223,6 +219,9 @@
<ResourceString bundle="org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties" key="FileTypeIdGlobalSettingsPanel.newTypeButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="newTypeButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="deleteTypeButton">
<Properties>
@ -230,6 +229,9 @@
<ResourceString bundle="org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties" key="FileTypeIdGlobalSettingsPanel.deleteTypeButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="deleteTypeButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="saveTypeButton">
<Properties>
@ -237,6 +239,9 @@
<ResourceString bundle="org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties" key="FileTypeIdGlobalSettingsPanel.saveTypeButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="saveTypeButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="hexPrefixLabel">
<Properties>
@ -248,13 +253,12 @@
<Component class="javax.swing.JComboBox" name="signatureTypeComboBox">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="3">
<StringItem index="0" value="Bytes (Hex)"/>
<StringItem index="1" value="String"/>
<StringItem index="2" value=" "/>
</StringArray>
<StringArray count="0"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="signatureLabel">
<Properties>

View File

@ -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<String, FileType> fileTypes = new HashMap<>();
private final HashMap<String, FileType> changedFileTypes = new HashMap<>();
private final HashMap<String, FileType> 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<String, FileType> 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<String> 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<String> 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<String>();
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<String>();
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()
@ -223,16 +272,13 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
.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()
.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())))
.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())
);
}// </editor-fold>//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<String> signatureTypeComboBox;
private javax.swing.JLabel signatureTypeLabel;
private javax.swing.JList typesList;
private javax.swing.JList<String> typesList;
private javax.swing.JScrollPane typesScrollPane;
// End of variables declaration//GEN-END:variables

View File

@ -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<FileType> fileTypes;
private final Map<String, FileType> fileTypes;
/**
* Creates an object that can do file type identification for user-defined
* file types.
*/
UserDefinedFileTypeIdentifier() {
this.fileTypes = new ArrayList<>();
List<FileType> 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;

View File

@ -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<String, FileType> 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("<?xml".getBytes(UserDefinedFileTypesManager.ASCII_ENCODING), 0L, FileType.Signature.Type.ASCII), false));
fileType = new FileType("text/xml", new Signature("<?xml".getBytes(UserDefinedFileTypesManager.ASCII_ENCODING), 0L, FileType.Signature.Type.ASCII), false);
this.addPredefinedFileType(fileType);
} catch (UnsupportedEncodingException ex) {
/**
* Using an all-or-none strategy.
* Using an all-or-none policy.
*/
UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Unable to create predefined file type definitions", ex); //NON-NLS
this.fileTypes.clear();
}
}
/**
* Adds a file type to the the predefined file types and combined file types
* maps.
*
* @param fileType The file type to add.
*/
private void addPredefinedFileType(FileType fileType) {
this.predefinedFileTypes.put(fileType.getTypeName(), fileType);
this.fileTypes.put(fileType.getTypeName(), fileType);
}
/**
* Reads user-defined file types into an in-memory mapping of file type
* names to file types.
@ -164,14 +189,13 @@ final class UserDefinedFileTypesManager {
File file = new File(filePath);
if (file.exists() && file.canRead()) {
for (FileType fileType : XMLReader.readFileTypes(filePath)) {
this.userDefinedFileTypes.put(fileType.getTypeName(), fileType);
this.fileTypes.put(fileType.getTypeName(), fileType);
this.addUserDefinedFileType(fileType);
}
}
} catch (UserDefinedFileTypesManager.InvalidXMLException ex) {
/**
* Using an all-or-none strategy.
* Using an all-or-none policy.
*/
UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Unable to load user-defined types", ex); //NON-NLS
this.fileTypes.clear();
@ -180,101 +204,79 @@ final class UserDefinedFileTypesManager {
}
/**
* Gets the user-defined file types.
* Adds a file type to the the user-defined file types and combined file
* types maps.
*
* @param fileType The file type to add.
*/
private void addUserDefinedFileType(FileType fileType) {
this.userDefinedFileTypes.put(fileType.getTypeName(), fileType);
this.fileTypes.put(fileType.getTypeName(), fileType);
}
/**
* Gets both the predefined and the user-defined file types.
*
* @return A mapping of file type names to file types, possibly empty.
*/
synchronized List<FileType> getFileTypes() {
synchronized Map<String, FileType> 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));
}
synchronized Map<String, FileType> getUserDefinedFileTypes() {
/**
* 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<FileType> newFileTypes) throws UserDefinedFileTypesException {
/**
* 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<FileType> 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<FileType> fileTypes, String filePath) throws UserDefinedFileTypesException {
synchronized void setUserDefinedFileTypes(Map<String, FileType> 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);
}
/**