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.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) FileTypeIdIngestJobSettingsPanel.skipKnownCheckBox.text=Skip known files (NSRL)
FileTypeIdGlobalSettingsPanel.hexPrefixLabel.text=0x FileTypeIdGlobalSettingsPanel.hexPrefixLabel.text=0x
FileTypeIdGlobalSettingsPanel.saveTypeButton.text=Save Type
FileTypeIdGlobalSettingsPanel.deleteTypeButton.text=DeleteType FileTypeIdGlobalSettingsPanel.deleteTypeButton.text=DeleteType
FileTypeIdGlobalSettingsPanel.newTypeButton.text=New Type FileTypeIdGlobalSettingsPanel.newTypeButton.text=New Type
FileTypeIdGlobalSettingsPanel.offsetTextField.text= FileTypeIdGlobalSettingsPanel.offsetTextField.text=
@ -21,3 +20,4 @@ FileTypeIdGlobalSettingsPanel.signatureTypeLabel.text=Signature Type
FileTypeIdGlobalSettingsPanel.mimeTypeTextField.text= FileTypeIdGlobalSettingsPanel.mimeTypeTextField.text=
FileTypeIdGlobalSettingsPanel.signatureLabel.text=Signature FileTypeIdGlobalSettingsPanel.signatureLabel.text=Signature
FileTypeIdGlobalSettingsPanel.mimeTypeLabel.text=Mime Type FileTypeIdGlobalSettingsPanel.mimeTypeLabel.text=Mime Type
FileTypeIdGlobalSettingsPanel.saveTypeButton.text=Save Type

View File

@ -35,7 +35,6 @@
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="37" max="-2" attributes="0"/> <EmptySpace min="-2" pref="37" max="-2" attributes="0"/>
<Component id="saveTypeButton" min="-2" max="-2" attributes="0"/> <Component id="saveTypeButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group> </Group>
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="18" max="-2" attributes="0"/> <EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
@ -43,18 +42,17 @@
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0"> <Group type="103" groupAlignment="1" max="-2" attributes="0">
<Group type="102" alignment="1" attributes="0"> <Group type="102" alignment="0" attributes="0">
<Component id="signatureTypeLabel" min="-2" max="-2" attributes="0"/> <Component id="signatureTypeLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/> <EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="signatureTypeComboBox" min="-2" pref="82" 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>
<Group type="102" alignment="1" attributes="0"> <Group type="102" alignment="1" attributes="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<Component id="signatureLabel" min="-2" max="-2" 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"/> <Component id="hexPrefixLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/> <EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
</Group> </Group>
@ -78,22 +76,17 @@
</Group> </Group>
</Group> </Group>
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0"> <EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Group type="102" attributes="0"> <Component id="jScrollPane2" min="-2" pref="260" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/> </Group>
<Component id="jScrollPane2" min="-2" pref="260" max="-2" attributes="0"/> <Group type="102" alignment="0" attributes="0">
</Group> <EmptySpace max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0"> <Component id="postHitCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="postHitCheckBox" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
<EmptySpace max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -141,14 +134,14 @@
</Group> </Group>
</Group> </Group>
<Group type="102" alignment="1" attributes="0"> <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"/> <Component id="saveTypeButton" min="-2" max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
</Group> </Group>
<Component id="jSeparator1" min="-2" pref="260" max="-2" attributes="0"/> <Component id="jSeparator1" min="-2" pref="260" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace max="32767" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -167,6 +160,9 @@
<StringArray count="0"/> <StringArray count="0"/>
</Property> </Property>
</Properties> </Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component> </Component>
</SubComponents> </SubComponents>
</Container> </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;)"/> <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> </Property>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="newTypeButtonActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JButton" name="deleteTypeButton"> <Component class="javax.swing.JButton" name="deleteTypeButton">
<Properties> <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;)"/> <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> </Property>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="deleteTypeButtonActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JButton" name="saveTypeButton"> <Component class="javax.swing.JButton" name="saveTypeButton">
<Properties> <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;)"/> <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> </Property>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="saveTypeButtonActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JLabel" name="hexPrefixLabel"> <Component class="javax.swing.JLabel" name="hexPrefixLabel">
<Properties> <Properties>
@ -248,13 +253,12 @@
<Component class="javax.swing.JComboBox" name="signatureTypeComboBox"> <Component class="javax.swing.JComboBox" name="signatureTypeComboBox">
<Properties> <Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor"> <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="3"> <StringArray count="0"/>
<StringItem index="0" value="Bytes (Hex)"/>
<StringItem index="1" value="String"/>
<StringItem index="2" value=" "/>
</StringArray>
</Property> </Property>
</Properties> </Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component> </Component>
<Component class="javax.swing.JLabel" name="signatureLabel"> <Component class="javax.swing.JLabel" name="signatureLabel">
<Properties> <Properties>

View File

@ -18,23 +18,30 @@
*/ */
package org.sleuthkit.autopsy.modules.filetypeid; 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.DefaultListModel;
import javax.swing.JOptionPane;
import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener; import javax.swing.event.ListSelectionListener;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
import org.sleuthkit.autopsy.modules.filetypeid.FileType.Signature; 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. * A panel to allow a user to make custom file type definitions.
*/ */
final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel {
private final HashMap<String, FileType> fileTypes = new HashMap<>(); private static final String RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM = "Bytes (Hex)"; // RJCTODO: Bundle
private final HashMap<String, FileType> changedFileTypes = new HashMap<>(); private static final String ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM = "String (ASCII)"; // RJCTODO: Bundle
private final HashMap<String, FileType> deletedFileTypes = new HashMap<>();
/**
* 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. * Creates a panel to allow a user to make custom file type definitions.
@ -56,19 +63,38 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
*/ */
@Override @Override
public void load() { 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<>(); DefaultListModel<String> fileTypesListModel = new DefaultListModel<>();
for (FileType fileType : UserDefinedFileTypesManager.getInstance().getFileTypes()) { for (FileType fileType : this.fileTypes.values()) {
fileTypes.put(fileType.getTypeName(), fileType);
fileTypesListModel.addElement(fileType.getTypeName()); 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()) { 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 @Override
public void store() { public void store() {
try { try {
UserDefinedFileTypesManager fileTypesManager = UserDefinedFileTypesManager.getInstance(); UserDefinedFileTypesManager.getInstance().setUserDefinedFileTypes(this.fileTypes);
fileTypesManager.addFileTypes(changedFileTypes.values()); } catch (UserDefinedFileTypesManager.UserDefinedFileTypesException ex) {
fileTypesManager.deleteFileTypes(deletedFileTypes.values());
} catch (UserDefinedFileTypesException ex) {
// RJCTODO // RJCTODO
} }
} }
@ -90,22 +114,36 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
@Override @Override
public void valueChanged(ListSelectionEvent e) { public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting() == false) { if (e.getValueIsAdjusting() == false) {
if (typesList.getSelectedIndex() == -1) { if (FileTypeIdGlobalSettingsPanel.this.typesList.getSelectedIndex() == -1) {
deleteTypeButton.setEnabled(false); FileTypeIdGlobalSettingsPanel.this.deleteTypeButton.setEnabled(false);
} else { } else {
String typeName = (String) typesList.getSelectedValue(); String typeName = FileTypeIdGlobalSettingsPanel.this.typesList.getSelectedValue();
FileType fileType = fileTypes.get(typeName); FileType fileType = FileTypeIdGlobalSettingsPanel.this.fileTypes.get(typeName);
Signature signature = fileType.getSignature(); Signature signature = fileType.getSignature();
mimeTypeTextField.setText(typeName); FileTypeIdGlobalSettingsPanel.this.mimeTypeTextField.setText(typeName);
offsetTextField.setText(Long.toString(signature.getOffset())); FileType.Signature.Type sigType = fileType.getSignature().getType();
deleteTypeButton.setEnabled(true); 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. * 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 * 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(); buttonGroup1 = new javax.swing.ButtonGroup();
typesScrollPane = new javax.swing.JScrollPane(); typesScrollPane = new javax.swing.JScrollPane();
typesList = new javax.swing.JList(); typesList = new javax.swing.JList<String>();
jSeparator1 = new javax.swing.JSeparator(); jSeparator1 = new javax.swing.JSeparator();
mimeTypeLabel = new javax.swing.JLabel(); mimeTypeLabel = new javax.swing.JLabel();
mimeTypeTextField = new javax.swing.JTextField(); mimeTypeTextField = new javax.swing.JTextField();
@ -129,7 +167,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
deleteTypeButton = new javax.swing.JButton(); deleteTypeButton = new javax.swing.JButton();
saveTypeButton = new javax.swing.JButton(); saveTypeButton = new javax.swing.JButton();
hexPrefixLabel = new javax.swing.JLabel(); hexPrefixLabel = new javax.swing.JLabel();
signatureTypeComboBox = new javax.swing.JComboBox(); signatureTypeComboBox = new javax.swing.JComboBox<String>();
signatureLabel = new javax.swing.JLabel(); signatureLabel = new javax.swing.JLabel();
jScrollPane2 = new javax.swing.JScrollPane(); jScrollPane2 = new javax.swing.JScrollPane();
jTextArea1 = new javax.swing.JTextArea(); 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 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 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 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 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 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 org.openide.awt.Mnemonics.setLocalizedText(signatureLabel, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.signatureLabel.text")); // NOI18N
jTextArea1.setEditable(false); jTextArea1.setEditable(false);
@ -190,25 +241,23 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addGap(37, 37, 37) .addGap(37, 37, 37)
.addComponent(saveTypeButton) .addComponent(saveTypeButton))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addGap(18, 18, 18) .addGap(18, 18, 18)
.addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 13, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 13, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addGroup(layout.createSequentialGroup() .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addComponent(signatureTypeLabel) .addComponent(signatureTypeLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(signatureTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 82, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(signatureTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 82, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(0, 0, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addComponent(signatureLabel) .addComponent(signatureLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(hexPrefixLabel) .addComponent(hexPrefixLabel)
.addGap(2, 2, 2)) .addGap(2, 2, 2))
.addGroup(layout.createSequentialGroup() .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) .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.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(6, 6, 6)
.addGroup(layout.createSequentialGroup() .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 260, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(6, 6, 6) .addGroup(layout.createSequentialGroup()
.addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 260, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createSequentialGroup() .addComponent(postHitCheckBox)))))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(postHitCheckBox)))
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())))
); );
layout.setVerticalGroup( layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -270,13 +316,50 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
.addComponent(newTypeButton) .addComponent(newTypeButton)
.addComponent(deleteTypeButton))) .addComponent(deleteTypeButton)))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .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(saveTypeButton))))
.addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 260, javax.swing.GroupLayout.PREFERRED_SIZE)) .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 }// </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 // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.ButtonGroup buttonGroup1; private javax.swing.ButtonGroup buttonGroup1;
@ -294,9 +377,9 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
private javax.swing.JButton saveTypeButton; private javax.swing.JButton saveTypeButton;
private javax.swing.JLabel signatureLabel; private javax.swing.JLabel signatureLabel;
private javax.swing.JTextField signatureTextField; private javax.swing.JTextField signatureTextField;
private javax.swing.JComboBox signatureTypeComboBox; private javax.swing.JComboBox<String> signatureTypeComboBox;
private javax.swing.JLabel signatureTypeLabel; private javax.swing.JLabel signatureTypeLabel;
private javax.swing.JList typesList; private javax.swing.JList<String> typesList;
private javax.swing.JScrollPane typesScrollPane; private javax.swing.JScrollPane typesScrollPane;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables

View File

@ -18,8 +18,7 @@
*/ */
package org.sleuthkit.autopsy.modules.filetypeid; package org.sleuthkit.autopsy.modules.filetypeid;
import java.util.ArrayList; import java.util.Map;
import java.util.List;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
/** /**
@ -27,16 +26,14 @@ import org.sleuthkit.datamodel.AbstractFile;
*/ */
final class UserDefinedFileTypeIdentifier { 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 * Creates an object that can do file type identification for user-defined
* file types. * file types.
*/ */
UserDefinedFileTypeIdentifier() { UserDefinedFileTypeIdentifier() {
this.fileTypes = new ArrayList<>(); this.fileTypes = UserDefinedFileTypesManager.getInstance().getFileTypes();
List<FileType> fileTypeDefs = UserDefinedFileTypesManager.getInstance().getFileTypes();
this.fileTypes.addAll(fileTypeDefs);
} }
/** /**
@ -48,7 +45,7 @@ final class UserDefinedFileTypeIdentifier {
*/ */
FileType identify(final AbstractFile file) { FileType identify(final AbstractFile file) {
FileType type = null; FileType type = null;
for (FileType fileType : this.fileTypes) { for (FileType fileType : this.fileTypes.values()) {
if (fileType.matches(file)) { if (fileType.matches(file)) {
type = fileType; type = fileType;
break; break;

View File

@ -62,6 +62,13 @@ final class UserDefinedFileTypesManager {
private static final String ASCII_ENCODING = "US-ASCII"; //NON-NLS private static final String ASCII_ENCODING = "US-ASCII"; //NON-NLS
private static UserDefinedFileTypesManager instance; 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 * 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 * 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. * (e.g., MIME type) and signatures.
*/ */
private UserDefinedFileTypesManager() { private UserDefinedFileTypesManager() {
/**
* Load the predefined types first so that they can be overwritten by
* any user-defined types with the same names.
*/
loadPredefinedFileTypes(); loadPredefinedFileTypes();
loadUserDefinedFileTypes(); loadUserDefinedFileTypes();
} }
@ -109,14 +120,16 @@ final class UserDefinedFileTypesManager {
/** /**
* Create a file type that should match $MBR in Small2 image. * 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. * Create a file type that should match test.txt in the Small2 image.
*/ */
// RJCTODO: Remove test type // RJCTODO: Remove test type
try { 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) { } catch (UnsupportedEncodingException ex) {
UserDefinedFileTypesManager.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
} }
@ -144,16 +157,28 @@ final class UserDefinedFileTypesManager {
// catch (IndexOutOfBoundsException e) { // catch (IndexOutOfBoundsException e) {
// // do nothing // // 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) { } 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 UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Unable to create predefined file type definitions", ex); //NON-NLS
this.fileTypes.clear(); 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 * Reads user-defined file types into an in-memory mapping of file type
* names to file types. * names to file types.
@ -164,14 +189,13 @@ final class UserDefinedFileTypesManager {
File file = new File(filePath); File file = new File(filePath);
if (file.exists() && file.canRead()) { if (file.exists() && file.canRead()) {
for (FileType fileType : XMLReader.readFileTypes(filePath)) { for (FileType fileType : XMLReader.readFileTypes(filePath)) {
this.userDefinedFileTypes.put(fileType.getTypeName(), fileType); this.addUserDefinedFileType(fileType);
this.fileTypes.put(fileType.getTypeName(), fileType);
} }
} }
} catch (UserDefinedFileTypesManager.InvalidXMLException ex) { } 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 UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Unable to load user-defined types", ex); //NON-NLS
this.fileTypes.clear(); 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. * @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 * It is safe to return references to the internal file type objects
* because they are immutable. * 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 * Gets the user-defined file types.
* with the same type name.
* *
* @param fileType The file type to add. * @return A mapping of file type names to file types, possibly empty.
* @throws
* org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException
*/ */
synchronized void addFileType(FileType fileType) throws UserDefinedFileTypesException { synchronized Map<String, FileType> getUserDefinedFileTypes() {
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<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. * because they are immutable.
*/ */
for (FileType fileType : newFileTypes) { return new HashMap<>(this.userDefinedFileTypes);
this.userDefinedFileTypes.put(fileType.getTypeName(), fileType);
this.fileTypes.put(fileType.getTypeName(), fileType);
}
this.saveUserDefinedTypes();
} }
/** /**
* 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 * @throws
* org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException
*/ */
synchronized void deleteFileType(FileType fileType) throws UserDefinedFileTypesException { synchronized void setUserDefinedFileTypes(Map<String, FileType> newFileTypes) throws UserDefinedFileTypesManager.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 {
try { 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) { } catch (ParserConfigurationException | IOException ex) {
UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Failed to write file types file", 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()); // 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);
} }
/** /**