From b777cf88e82204a88ea22c37ba9f4865b6512ec4 Mon Sep 17 00:00:00 2001 From: momo Date: Tue, 27 Oct 2015 09:26:21 -0400 Subject: [PATCH 01/24] preliminary implimentation --- .../autopsy/modules/filetypeid/FileType.java | 55 ++++++++++++++++++- .../UserDefinedFileTypesManager.java | 6 ++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java index e44a3b5adc..96f7b2b8b3 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java @@ -167,6 +167,49 @@ class FileType { this.offset = offset; this.type = Type.RAW; } + + /** + * Creates a file signature consisting of a sequence of bytes at a + * specific offset within a file with default offset. + * + * @param signatureBytes The signature bytes. + * @param isFooter Whether this is a footer or not + * @param type The type of data in the byte array. Impacts + * how it is displayed to the user in the UI. + */ + Signature(final byte[] signatureBytes, boolean isFooter, Type type) { + this.signatureBytes = Arrays.copyOf(signatureBytes, signatureBytes.length); + this.offset = isFooter ? -1 : 0; + this.type = type; + } + + /** + * Creates a file signature consisting of an ASCII string at a + * specific offset within a file with default offset. + * + * @param signatureString The ASCII string + * @param isFooter Whether this is a footer or not + */ + Signature(String signatureString, boolean isFooter) { + this.signatureBytes = signatureString.getBytes(StandardCharsets.US_ASCII); + this.offset = isFooter ? -1 : 0; + this.type = Type.ASCII; + } + + /** + * Creates a file signature consisting of a sequence of bytes at a + * specific offset within a file with default offset. If bytes + * correspond to an ASCII string, use one of the other constructors + * so that the string is displayed to the user instead of the raw bytes. + * + * @param signatureBytes The signature bytes. + * @param isFooter Whether this is a footer or not + */ + Signature(final byte[] signatureBytes, boolean isFooter) { + this.signatureBytes = Arrays.copyOf(signatureBytes, signatureBytes.length); + this.offset = isFooter ? -1 : 0; + this.type = Type.RAW; + } /** * Gets the byte sequence of the signature. @@ -203,7 +246,9 @@ class FileType { * * @return True or false. */ - boolean containedIn(final AbstractFile file) { + boolean containedIn(final AbstractFile file) { + if(offset == -1) + return containedAsFooter(file); if (file.getSize() < (offset + signatureBytes.length)) { return false; /// too small, can't contain this signature } @@ -221,6 +266,14 @@ class FileType { return false; } } + + private boolean containedAsFooter(final AbstractFile file) { + if(file.getSize() < signatureBytes.length) + return false; + long newOffset = file.getSize() - signatureBytes.length; + Signature newSignature = new Signature(signatureBytes, newOffset); + return newSignature.containedIn(file); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java index d5777cb281..3622cceaf6 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java @@ -224,6 +224,12 @@ final class UserDefinedFileTypesManager { // Add rule for .pfm fileType = new FileType("image/x-portable-floatmap", new Signature("PF", 0L), "", false); //NON-NLS fileTypes.put(fileType.getMimeType(), fileType); + + // Add rule for .tga + byteArray = DatatypeConverter.parseHexBinary("54525545564953494F4E2D5846494C452E00"); + fileType = new FileType("image/x-tga", new Signature(byteArray, true), "", false); // NON-NLS + fileTypes.put(fileType.getMimeType(), fileType); + } // parseHexBinary() throws this if the argument passed in is not Hex catch (IllegalArgumentException e) { From 98e43b766692f38127b58a9db111cf4f1ac511c7 Mon Sep 17 00:00:00 2001 From: momo Date: Tue, 27 Oct 2015 10:48:01 -0400 Subject: [PATCH 02/24] the -1 implementation --- .../modules/filetypeid/Bundle.properties | 2 +- .../FileTypeIdGlobalSettingsPanel.form | 116 ++++++++-------- .../FileTypeIdGlobalSettingsPanel.java | 124 +++++++++++------- 3 files changed, 143 insertions(+), 99 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties index cca8104c38..7ac6b9fc2c 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties @@ -46,4 +46,4 @@ FileTypeIdGlobalSettingsPanel.jLabel2.text=MIME Types: FileTypeIdGlobalSettingsPanel.jLabel3.text=Autopsy can automatically detect many file types. Add your custom file types here. FileTypeIdGlobalSettingsPanel.startUp.fileTypeDetectorInitializationException.msg=Error initializing the file type detector. FileTypeIdIngestModule.startUp.fileTypeDetectorInitializationException.msg=Error initializing the file type detector. - +FileTypeIdGlobalSettingsPanel.isFooterCheckBox.text=This signature is a footer diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form index 1d124ea29d..efa69fdafe 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form @@ -33,63 +33,63 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + @@ -108,7 +108,7 @@ - + @@ -140,6 +140,8 @@ + + @@ -351,5 +353,15 @@ + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java index cebce19890..349b6c3cea 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -203,7 +203,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane boolean requiredFieldsPopulated = !mimeTypeTextField.getText().isEmpty() - && !offsetTextField.getText().isEmpty() + && (isFooterCheckBox.isSelected() ? true : !offsetTextField.getText().isEmpty()) && !signatureTextField.getText().isEmpty() && (postHitCheckBox.isSelected() ? !filesSetNameTextField.getText().isEmpty() : true); saveTypeButton.setEnabled(!ingestIsRunning && requiredFieldsPopulated); @@ -271,7 +271,16 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane } } signatureTextField.setText(signatureBytes); - offsetTextField.setText(Long.toString(signature.getOffset())); + if(signature.getOffset() == -1) { + isFooterCheckBox.setSelected(true); + offsetTextField.setEnabled(false); + offsetTextField.setText(""); + } + else { + isFooterCheckBox.setSelected(false); + offsetTextField.setEnabled(true); + offsetTextField.setText(Long.toString(signature.getOffset())); + } postHitCheckBox.setSelected(fileType.alertOnMatch()); filesSetNameTextField.setEnabled(postHitCheckBox.isSelected()); filesSetNameTextField.setText(fileType.getFilesSetName()); @@ -289,6 +298,8 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane signatureTypeComboBox.setSelectedItem(FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM); hexPrefixLabel.setVisible(true); signatureTextField.setText("0000"); //NON-NLS + isFooterCheckBox.setSelected(false); + offsetTextField.setEnabled(true); offsetTextField.setText(""); //NON-NLS postHitCheckBox.setSelected(false); filesSetNameTextField.setText(""); //NON-NLS @@ -360,6 +371,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane jLabel1 = new javax.swing.JLabel(); jLabel2 = new javax.swing.JLabel(); jLabel3 = new javax.swing.JLabel(); + isFooterCheckBox = new javax.swing.JCheckBox(); setMaximumSize(new java.awt.Dimension(500, 300)); setPreferredSize(new java.awt.Dimension(500, 300)); @@ -439,6 +451,13 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.jLabel3.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(isFooterCheckBox, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.isFooterCheckBox.text")); // NOI18N + isFooterCheckBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + isFooterCheckBoxActionPerformed(evt); + } + }); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -451,51 +470,51 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane .addGap(30, 30, 30)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabel2) .addGroup(layout.createSequentialGroup() - .addGap(10, 10, 10) - .addComponent(deleteTypeButton, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addComponent(newTypeButton, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(typesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 180, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(separator, javax.swing.GroupLayout.PREFERRED_SIZE, 7, 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.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(mimeTypeLabel) - .addGap(30, 30, 30) - .addComponent(mimeTypeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 176, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(postHitCheckBox) - .addGroup(layout.createSequentialGroup() - .addComponent(signatureTypeLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(signatureTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 176, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addComponent(signatureLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 73, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(hexPrefixLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(signatureTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 160, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .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)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGap(21, 21, 21) - .addComponent(filesSetNameLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(filesSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 182, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(saveTypeButton) - .addGap(8, 8, 8))) - .addContainerGap()) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel2) + .addGroup(layout.createSequentialGroup() + .addGap(10, 10, 10) + .addComponent(deleteTypeButton, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addComponent(newTypeButton, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(typesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 180, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(separator, javax.swing.GroupLayout.PREFERRED_SIZE, 7, 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.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(mimeTypeLabel) + .addGap(30, 30, 30) + .addComponent(mimeTypeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 176, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(postHitCheckBox) + .addGroup(layout.createSequentialGroup() + .addComponent(signatureTypeLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(signatureTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 176, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(signatureLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 73, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(hexPrefixLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(signatureTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 160, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .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)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(21, 21, 21) + .addComponent(filesSetNameLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(filesSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 182, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(saveTypeButton) + .addGap(8, 8, 8)) + .addComponent(isFooterCheckBox))) .addComponent(jLabel1) .addComponent(jLabel3)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) + .addContainerGap(50, Short.MAX_VALUE)))) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -510,7 +529,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane .addGroup(layout.createSequentialGroup() .addComponent(jLabel2) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(typesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 177, Short.MAX_VALUE) + .addComponent(typesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 173, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(deleteTypeButton) @@ -534,6 +553,8 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane .addComponent(signatureTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(signatureLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(isFooterCheckBox) + .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)) @@ -614,7 +635,12 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane */ long offset; try { - offset = Long.parseUnsignedLong(offsetTextField.getText()); + if(isFooterCheckBox.isSelected()) { + offset = -1; + } + else { + offset = Long.parseUnsignedLong(offsetTextField.getText()); + } } catch (NumberFormatException ex) { JOptionPane.showMessageDialog(null, NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message"), @@ -664,12 +690,18 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane // TODO add your handling code here: }//GEN-LAST:event_signatureTextFieldActionPerformed + private void isFooterCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_isFooterCheckBoxActionPerformed + offsetTextField.setEnabled(!isFooterCheckBox.isSelected()); + enableButtons(); + }//GEN-LAST:event_isFooterCheckBoxActionPerformed + // 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.JLabel ingestRunningWarningLabel; + private javax.swing.JCheckBox isFooterCheckBox; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; From 14c91eb2dfd84081b03c01f65a8fde9c5278c17d Mon Sep 17 00:00:00 2001 From: momo Date: Tue, 27 Oct 2015 14:34:14 -0400 Subject: [PATCH 03/24] remove predefined sig to add to another pull request --- .../filetypeid/FileTypeIdGlobalSettingsPanel.java | 9 ++------- .../autopsy/modules/filetypeid/FileTypes.xsd | 12 +++++++++--- .../filetypeid/UserDefinedFileTypesManager.java | 6 ------ 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java index 349b6c3cea..2c84789a18 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -634,13 +634,8 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane * Get the offset. */ long offset; - try { - if(isFooterCheckBox.isSelected()) { - offset = -1; - } - else { - offset = Long.parseUnsignedLong(offsetTextField.getText()); - } + try { + offset = isFooterCheckBox.isSelected() ? -1 : Long.parseUnsignedLong(offsetTextField.getText()); } catch (NumberFormatException ex) { JOptionPane.showMessageDialog(null, NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message"), diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypes.xsd b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypes.xsd index 26aa720ff1..6ae9505c76 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypes.xsd +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypes.xsd @@ -13,19 +13,25 @@ - - + + + + + + + + - + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java index 3622cceaf6..d5777cb281 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java @@ -224,12 +224,6 @@ final class UserDefinedFileTypesManager { // Add rule for .pfm fileType = new FileType("image/x-portable-floatmap", new Signature("PF", 0L), "", false); //NON-NLS fileTypes.put(fileType.getMimeType(), fileType); - - // Add rule for .tga - byteArray = DatatypeConverter.parseHexBinary("54525545564953494F4E2D5846494C452E00"); - fileType = new FileType("image/x-tga", new Signature(byteArray, true), "", false); // NON-NLS - fileTypes.put(fileType.getMimeType(), fileType); - } // parseHexBinary() throws this if the argument passed in is not Hex catch (IllegalArgumentException e) { From 1d63ef0559dc78b7acf38552b7ea7202ff094495 Mon Sep 17 00:00:00 2001 From: momo Date: Tue, 27 Oct 2015 14:36:12 -0400 Subject: [PATCH 04/24] remove extra white space --- .../modules/filetypeid/FileTypeIdGlobalSettingsPanel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java index 2c84789a18..a7f3a78fe4 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -634,8 +634,8 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane * Get the offset. */ long offset; - try { - offset = isFooterCheckBox.isSelected() ? -1 : Long.parseUnsignedLong(offsetTextField.getText()); + try { + offset = isFooterCheckBox.isSelected() ? -1 : Long.parseUnsignedLong(offsetTextField.getText()); } catch (NumberFormatException ex) { JOptionPane.showMessageDialog(null, NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message"), From 806b4a91b01cf14aee1d7ed0874ca49cb3c10302 Mon Sep 17 00:00:00 2001 From: momo Date: Wed, 28 Oct 2015 10:21:31 -0400 Subject: [PATCH 05/24] allow offset with footer --- .../autopsy/modules/filetypeid/FileType.java | 62 ++----------------- .../FileTypeIdGlobalSettingsPanel.java | 19 +++--- .../autopsy/modules/filetypeid/FileTypes.xsd | 8 +-- 3 files changed, 17 insertions(+), 72 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java index cc12a95b5a..132f5b3317 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java @@ -191,49 +191,6 @@ class FileType { this.offset = offset; this.type = Type.RAW; } - - /** - * Creates a file signature consisting of a sequence of bytes at a - * specific offset within a file with default offset. - * - * @param signatureBytes The signature bytes. - * @param isFooter Whether this is a footer or not - * @param type The type of data in the byte array. Impacts - * how it is displayed to the user in the UI. - */ - Signature(final byte[] signatureBytes, boolean isFooter, Type type) { - this.signatureBytes = Arrays.copyOf(signatureBytes, signatureBytes.length); - this.offset = isFooter ? -1 : 0; - this.type = type; - } - - /** - * Creates a file signature consisting of an ASCII string at a - * specific offset within a file with default offset. - * - * @param signatureString The ASCII string - * @param isFooter Whether this is a footer or not - */ - Signature(String signatureString, boolean isFooter) { - this.signatureBytes = signatureString.getBytes(StandardCharsets.US_ASCII); - this.offset = isFooter ? -1 : 0; - this.type = Type.ASCII; - } - - /** - * Creates a file signature consisting of a sequence of bytes at a - * specific offset within a file with default offset. If bytes - * correspond to an ASCII string, use one of the other constructors - * so that the string is displayed to the user instead of the raw bytes. - * - * @param signatureBytes The signature bytes. - * @param isFooter Whether this is a footer or not - */ - Signature(final byte[] signatureBytes, boolean isFooter) { - this.signatureBytes = Arrays.copyOf(signatureBytes, signatureBytes.length); - this.offset = isFooter ? -1 : 0; - this.type = Type.RAW; - } /** * Gets the byte sequence of the signature. @@ -270,15 +227,16 @@ class FileType { * * @return True or false. */ - boolean containedIn(final AbstractFile file) { - if(offset == -1) - return containedAsFooter(file); - if (file.getSize() < (offset + signatureBytes.length)) { + boolean containedIn(final AbstractFile file) { + long actualOffset = offset; + if(offset < 0) + actualOffset = file.getSize() - signatureBytes.length + offset+1; + if (file.getSize() < (actualOffset + signatureBytes.length)) { return false; /// too small, can't contain this signature } try { byte[] buffer = new byte[signatureBytes.length]; - int bytesRead = file.read(buffer, offset, signatureBytes.length); + int bytesRead = file.read(buffer, actualOffset, signatureBytes.length); return ((bytesRead == signatureBytes.length) && (Arrays.equals(buffer, signatureBytes))); } catch (TskCoreException ex) { /** @@ -291,14 +249,6 @@ class FileType { } } - private boolean containedAsFooter(final AbstractFile file) { - if(file.getSize() < signatureBytes.length) - return false; - long newOffset = file.getSize() - signatureBytes.length; - Signature newSignature = new Signature(signatureBytes, newOffset); - return newSignature.containedIn(file); - } - @Override public boolean equals(Object other) { if (other != null && other instanceof Signature) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java index f45be34df6..712c82823c 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -203,7 +203,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane boolean requiredFieldsPopulated = !mimeTypeTextField.getText().isEmpty() - && (isFooterCheckBox.isSelected() ? true : !offsetTextField.getText().isEmpty()) + && !offsetTextField.getText().isEmpty() && !signatureTextField.getText().isEmpty() && (postHitCheckBox.isSelected() ? !filesSetNameTextField.getText().isEmpty() : true); saveTypeButton.setEnabled(!ingestIsRunning && requiredFieldsPopulated); @@ -270,14 +270,12 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane } } signatureTextField.setText(signatureBytes); - if(signature.getOffset() == -1) { + if(signature.getOffset() < 0) { isFooterCheckBox.setSelected(true); - offsetTextField.setEnabled(false); - offsetTextField.setText(""); + offsetTextField.setText(Long.toString(signature.getOffset()*-1 -1)); } else { isFooterCheckBox.setSelected(false); - offsetTextField.setEnabled(true); offsetTextField.setText(Long.toString(signature.getOffset())); } postHitCheckBox.setSelected(fileType.alertOnMatch()); @@ -299,7 +297,6 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane hexPrefixLabel.setVisible(true); signatureTextField.setText("0000"); //NON-NLS isFooterCheckBox.setSelected(false); - offsetTextField.setEnabled(true); offsetTextField.setText(""); //NON-NLS postHitCheckBox.setSelected(false); filesSetNameTextField.setText(""); //NON-NLS @@ -635,7 +632,12 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane */ long offset; try { - offset = isFooterCheckBox.isSelected() ? -1 : Long.parseUnsignedLong(offsetTextField.getText()); + if(isFooterCheckBox.isSelected()) { + offset = Long.parseUnsignedLong(offsetTextField.getText())*-1 -1; + } + else { + offset = Long.parseUnsignedLong(offsetTextField.getText()); + } } catch (NumberFormatException ex) { JOptionPane.showMessageDialog(null, NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message"), @@ -693,8 +695,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane }//GEN-LAST:event_signatureTextFieldActionPerformed private void isFooterCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_isFooterCheckBoxActionPerformed - offsetTextField.setEnabled(!isFooterCheckBox.isSelected()); - enableButtons(); + }//GEN-LAST:event_isFooterCheckBoxActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypes.xsd b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypes.xsd index 6ae9505c76..c923441e3d 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypes.xsd +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypes.xsd @@ -21,17 +21,11 @@ - - - - - - - + From 39bf598ca92aa9325bd8036343956218135e4043 Mon Sep 17 00:00:00 2001 From: momo Date: Wed, 28 Oct 2015 15:09:44 -0400 Subject: [PATCH 06/24] change implementation to use a boolean variable --- .../autopsy/modules/filetypeid/FileType.java | 62 +++++++++++++++++-- .../FileTypeIdGlobalSettingsPanel.java | 18 ++---- .../autopsy/modules/filetypeid/FileTypes.xsd | 3 +- .../UserDefinedFileTypesManager.java | 19 +++++- 4 files changed, 81 insertions(+), 21 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java index 132f5b3317..451c1d773c 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java @@ -51,7 +51,7 @@ class FileType { */ FileType(String mimeType, final Signature signature, String filesSetName, boolean alert) { this.mimeType = mimeType; - this.signature = new Signature(signature.getSignatureBytes(), signature.getOffset(), signature.getType()); + this.signature = new Signature(signature.getSignatureBytes(), signature.getOffset(), signature.getType(), signature.isTrailing()); this.interestingFilesSetName = filesSetName; this.alert = alert; } @@ -71,7 +71,7 @@ class FileType { * @return The signature. */ Signature getSignature() { - return new Signature(signature.getSignatureBytes(), signature.getOffset(), signature.getType()); + return new Signature(signature.getSignatureBytes(), signature.getOffset(), signature.getType(), signature.isTrailing()); } /** @@ -148,6 +148,7 @@ class FileType { private final byte[] signatureBytes; private final long offset; private final Type type; + private final boolean trailing; /** * Creates a file signature consisting of a sequence of bytes at a @@ -162,6 +163,7 @@ class FileType { this.signatureBytes = Arrays.copyOf(signatureBytes, signatureBytes.length); this.offset = offset; this.type = type; + this.trailing = false; } /** @@ -175,6 +177,7 @@ class FileType { this.signatureBytes = signatureString.getBytes(StandardCharsets.US_ASCII); this.offset = offset; this.type = Type.ASCII; + this.trailing = false; } /** @@ -190,6 +193,53 @@ class FileType { this.signatureBytes = Arrays.copyOf(signatureBytes, signatureBytes.length); this.offset = offset; this.type = Type.RAW; + this.trailing = false; + } + + /** + * 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 type of data in the byte array. Impacts + * how it is displayed to the user in the UI. + */ + Signature(final byte[] signatureBytes, long offset, Type type, boolean isFooter) { + this.signatureBytes = Arrays.copyOf(signatureBytes, signatureBytes.length); + this.offset = offset; + this.type = type; + this.trailing = isFooter; + } + + /** + * Creates a file signature consisting of an ASCII string at a + * specific offset within a file. + * + * @param signatureString The ASCII string + * @param offset The offset of the signature bytes. + */ + Signature(String signatureString, long offset, boolean isFooter) { + this.signatureBytes = signatureString.getBytes(StandardCharsets.US_ASCII); + this.offset = offset; + this.type = Type.ASCII; + this.trailing = isFooter; + } + + /** + * Creates a file signature consisting of a sequence of bytes at a + * specific offset within a file. If bytes correspond to an ASCII + * string, use one of the other constructors so that the string is + * displayed to the user instead of the raw bytes. + * + * @param signatureBytes The signature bytes. + * @param offset The offset of the signature bytes. + */ + Signature(final byte[] signatureBytes, long offset, boolean isFooter) { + this.signatureBytes = Arrays.copyOf(signatureBytes, signatureBytes.length); + this.offset = offset; + this.type = Type.RAW; + this.trailing = isFooter; } /** @@ -218,6 +268,10 @@ class FileType { Type getType() { return type; } + + boolean isTrailing() { + return trailing; + } /** * Determines whether or not the signature is contained within a given @@ -229,8 +283,8 @@ class FileType { */ boolean containedIn(final AbstractFile file) { long actualOffset = offset; - if(offset < 0) - actualOffset = file.getSize() - signatureBytes.length + offset+1; + if(trailing) + actualOffset = file.getSize() - signatureBytes.length - offset; if (file.getSize() < (actualOffset + signatureBytes.length)) { return false; /// too small, can't contain this signature } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java index 712c82823c..b721936057 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -270,14 +270,8 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane } } signatureTextField.setText(signatureBytes); - if(signature.getOffset() < 0) { - isFooterCheckBox.setSelected(true); - offsetTextField.setText(Long.toString(signature.getOffset()*-1 -1)); - } - else { - isFooterCheckBox.setSelected(false); - offsetTextField.setText(Long.toString(signature.getOffset())); - } + isFooterCheckBox.setSelected(signature.isTrailing()); + offsetTextField.setText(Long.toString(signature.getOffset())); postHitCheckBox.setSelected(fileType.alertOnMatch()); filesSetNameTextField.setEnabled(postHitCheckBox.isSelected()); filesSetNameTextField.setText(fileType.getFilesSetName()); @@ -632,12 +626,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane */ long offset; try { - if(isFooterCheckBox.isSelected()) { - offset = Long.parseUnsignedLong(offsetTextField.getText())*-1 -1; - } - else { offset = Long.parseUnsignedLong(offsetTextField.getText()); - } } catch (NumberFormatException ex) { JOptionPane.showMessageDialog(null, NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message"), @@ -664,7 +653,8 @@ 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); + boolean isTrailing = isFooterCheckBox.isSelected(); + FileType.Signature signature = new FileType.Signature(signatureBytes, offset, sigType, isFooterCheckBox.isSelected()); FileType fileType = new FileType(typeName, signature, filesSetName, postHitCheckBox.isSelected()); FileType selected = typesList.getSelectedValue(); if (selected != null) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypes.xsd b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypes.xsd index c923441e3d..63dab70d24 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypes.xsd +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypes.xsd @@ -25,7 +25,8 @@ - + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java index 47a3a0f97b..4d801c79be 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java @@ -38,6 +38,7 @@ 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.w3c.dom.Node; import org.xml.sax.SAXException; /** @@ -67,6 +68,7 @@ final class UserDefinedFileTypesManager { 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 TRAILING_TAG_NAME = "Trailing"; 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 @@ -372,6 +374,10 @@ final class UserDefinedFileTypesManager { Element offsetElem = doc.createElement(OFFSET_TAG_NAME); offsetElem.setTextContent(DatatypeConverter.printLong(signature.getOffset())); signatureElem.appendChild(offsetElem); + + Element trailingElem = doc.createElement(TRAILING_TAG_NAME); + trailingElem.setTextContent(DatatypeConverter.printBoolean(signature.isTrailing())); + signatureElem.appendChild(trailingElem); signatureElem.setAttribute(SIGNATURE_TYPE_ATTRIBUTE, signature.getType().toString()); fileTypeElem.appendChild(signatureElem); @@ -482,8 +488,14 @@ final class UserDefinedFileTypesManager { String offsetString = getChildElementTextContent(signatureElem, OFFSET_TAG_NAME); long offset = DatatypeConverter.parseLong(offsetString); + + String trailingString = getChildElementTextContent(signatureElem, TRAILING_TAG_NAME); + if(trailingString == null) + return new Signature(signatureBytes, offset, signatureType); + + boolean trailing = DatatypeConverter.parseBoolean(trailingString); - return new Signature(signatureBytes, offset, signatureType); + return new Signature(signatureBytes, offset, signatureType, trailing); } /** @@ -525,7 +537,10 @@ final class UserDefinedFileTypesManager { */ private static String getChildElementTextContent(Element elem, String tagName) { NodeList childElems = elem.getElementsByTagName(tagName); - Element childElem = (Element) childElems.item(0); + Node childNode = childElems.item(0); + if(childNode == null) + return null; + Element childElem = (Element) childNode; return childElem.getTextContent(); } From 796e4417654e87458fa0f685da2bf4b66edf813c Mon Sep 17 00:00:00 2001 From: momo Date: Wed, 28 Oct 2015 15:11:46 -0400 Subject: [PATCH 07/24] change variable names --- .../modules/filetypeid/Bundle.properties | 2 +- .../autopsy/modules/filetypeid/FileType.java | 17 +++++++----- .../FileTypeIdGlobalSettingsPanel.form | 10 +++---- .../FileTypeIdGlobalSettingsPanel.java | 26 +++++++++---------- 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties index 7ac6b9fc2c..bc99ea014f 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties @@ -46,4 +46,4 @@ FileTypeIdGlobalSettingsPanel.jLabel2.text=MIME Types: FileTypeIdGlobalSettingsPanel.jLabel3.text=Autopsy can automatically detect many file types. Add your custom file types here. FileTypeIdGlobalSettingsPanel.startUp.fileTypeDetectorInitializationException.msg=Error initializing the file type detector. FileTypeIdIngestModule.startUp.fileTypeDetectorInitializationException.msg=Error initializing the file type detector. -FileTypeIdGlobalSettingsPanel.isFooterCheckBox.text=This signature is a footer +FileTypeIdGlobalSettingsPanel.isTrailingCheckBox.text=This signature is a trailing diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java index 451c1d773c..133c1c6f84 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java @@ -203,13 +203,14 @@ class FileType { * @param signatureBytes The signature bytes. * @param offset The offset of the signature bytes. * @param type The type of data in the byte array. Impacts - * how it is displayed to the user in the UI. + * how it is displayed to the user in the UI. + * @param trailing Determines whether this signature is trailing. */ - Signature(final byte[] signatureBytes, long offset, Type type, boolean isFooter) { + Signature(final byte[] signatureBytes, long offset, Type type, boolean trailing) { this.signatureBytes = Arrays.copyOf(signatureBytes, signatureBytes.length); this.offset = offset; this.type = type; - this.trailing = isFooter; + this.trailing = trailing; } /** @@ -218,12 +219,13 @@ class FileType { * * @param signatureString The ASCII string * @param offset The offset of the signature bytes. + * @param trailing Determines whether this signature is trailing. */ - Signature(String signatureString, long offset, boolean isFooter) { + Signature(String signatureString, long offset, boolean trailing) { this.signatureBytes = signatureString.getBytes(StandardCharsets.US_ASCII); this.offset = offset; this.type = Type.ASCII; - this.trailing = isFooter; + this.trailing = trailing; } /** @@ -234,12 +236,13 @@ class FileType { * * @param signatureBytes The signature bytes. * @param offset The offset of the signature bytes. + * @param trailing Determines whether this signature is trailing. */ - Signature(final byte[] signatureBytes, long offset, boolean isFooter) { + Signature(final byte[] signatureBytes, long offset, boolean trailing) { this.signatureBytes = Arrays.copyOf(signatureBytes, signatureBytes.length); this.offset = offset; this.type = Type.RAW; - this.trailing = isFooter; + this.trailing = trailing; } /** diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form index 030695446f..0e51a3c6bc 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form @@ -83,7 +83,7 @@ - + @@ -140,7 +140,7 @@ - + @@ -353,14 +353,14 @@ - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java index b721936057..690cef660a 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -270,7 +270,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane } } signatureTextField.setText(signatureBytes); - isFooterCheckBox.setSelected(signature.isTrailing()); + isTrailingCheckBox.setSelected(signature.isTrailing()); offsetTextField.setText(Long.toString(signature.getOffset())); postHitCheckBox.setSelected(fileType.alertOnMatch()); filesSetNameTextField.setEnabled(postHitCheckBox.isSelected()); @@ -290,7 +290,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane signatureTypeComboBox.setSelectedItem(FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM); hexPrefixLabel.setVisible(true); signatureTextField.setText("0000"); //NON-NLS - isFooterCheckBox.setSelected(false); + isTrailingCheckBox.setSelected(false); offsetTextField.setText(""); //NON-NLS postHitCheckBox.setSelected(false); filesSetNameTextField.setText(""); //NON-NLS @@ -362,7 +362,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane jLabel1 = new javax.swing.JLabel(); jLabel2 = new javax.swing.JLabel(); jLabel3 = new javax.swing.JLabel(); - isFooterCheckBox = new javax.swing.JCheckBox(); + isTrailingCheckBox = new javax.swing.JCheckBox(); setMaximumSize(new java.awt.Dimension(500, 300)); setPreferredSize(new java.awt.Dimension(500, 300)); @@ -442,10 +442,10 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.jLabel3.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(isFooterCheckBox, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.isFooterCheckBox.text")); // NOI18N - isFooterCheckBox.addActionListener(new java.awt.event.ActionListener() { + org.openide.awt.Mnemonics.setLocalizedText(isTrailingCheckBox, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.isTrailingCheckBox.text")); // NOI18N + isTrailingCheckBox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - isFooterCheckBoxActionPerformed(evt); + isTrailingCheckBoxActionPerformed(evt); } }); @@ -502,7 +502,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addComponent(saveTypeButton) .addGap(8, 8, 8)) - .addComponent(isFooterCheckBox))) + .addComponent(isTrailingCheckBox))) .addComponent(jLabel1) .addComponent(jLabel3)) .addContainerGap(50, Short.MAX_VALUE)))) @@ -544,7 +544,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane .addComponent(signatureTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(signatureLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(isFooterCheckBox) + .addComponent(isTrailingCheckBox) .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) @@ -653,8 +653,8 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane /** * Put it all together and reset the file types list component. */ - boolean isTrailing = isFooterCheckBox.isSelected(); - FileType.Signature signature = new FileType.Signature(signatureBytes, offset, sigType, isFooterCheckBox.isSelected()); + boolean isTrailing = isTrailingCheckBox.isSelected(); + FileType.Signature signature = new FileType.Signature(signatureBytes, offset, sigType, isTrailingCheckBox.isSelected()); FileType fileType = new FileType(typeName, signature, filesSetName, postHitCheckBox.isSelected()); FileType selected = typesList.getSelectedValue(); if (selected != null) { @@ -684,9 +684,9 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane // TODO add your handling code here: }//GEN-LAST:event_signatureTextFieldActionPerformed - private void isFooterCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_isFooterCheckBoxActionPerformed + private void isTrailingCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_isTrailingCheckBoxActionPerformed - }//GEN-LAST:event_isFooterCheckBoxActionPerformed + }//GEN-LAST:event_isTrailingCheckBoxActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton deleteTypeButton; @@ -694,7 +694,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane private javax.swing.JTextField filesSetNameTextField; private javax.swing.JLabel hexPrefixLabel; private javax.swing.JLabel ingestRunningWarningLabel; - private javax.swing.JCheckBox isFooterCheckBox; + private javax.swing.JCheckBox isTrailingCheckBox; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; From a09548f79a1ef4427bfd4cdf5652db6b763f6f6f Mon Sep 17 00:00:00 2001 From: Mohammad Yahya Date: Wed, 28 Oct 2015 15:26:51 -0400 Subject: [PATCH 08/24] remove extra indentation --- .../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 690cef660a..b74b7e67cc 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -626,7 +626,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane */ long offset; try { - offset = Long.parseUnsignedLong(offsetTextField.getText()); + offset = Long.parseUnsignedLong(offsetTextField.getText()); } catch (NumberFormatException ex) { JOptionPane.showMessageDialog(null, NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message"), From b02c78bea76d392e7fb43c342a1cf579ac6d5d92 Mon Sep 17 00:00:00 2001 From: Mohammad Yahya Date: Wed, 28 Oct 2015 15:28:51 -0400 Subject: [PATCH 09/24] Delete debug line --- .../modules/filetypeid/FileTypeIdGlobalSettingsPanel.java | 1 - 1 file changed, 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 b74b7e67cc..58afdd266a 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -653,7 +653,6 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane /** * Put it all together and reset the file types list component. */ - boolean isTrailing = isTrailingCheckBox.isSelected(); FileType.Signature signature = new FileType.Signature(signatureBytes, offset, sigType, isTrailingCheckBox.isSelected()); FileType fileType = new FileType(typeName, signature, filesSetName, postHitCheckBox.isSelected()); FileType selected = typesList.getSelectedValue(); From d59fcb8172d793e87712a025585e776b32940161 Mon Sep 17 00:00:00 2001 From: Mohammad Yahya Date: Wed, 28 Oct 2015 16:04:16 -0400 Subject: [PATCH 10/24] change wording --- .../org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties index bc99ea014f..4c0eca959b 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties @@ -46,4 +46,4 @@ FileTypeIdGlobalSettingsPanel.jLabel2.text=MIME Types: FileTypeIdGlobalSettingsPanel.jLabel3.text=Autopsy can automatically detect many file types. Add your custom file types here. FileTypeIdGlobalSettingsPanel.startUp.fileTypeDetectorInitializationException.msg=Error initializing the file type detector. FileTypeIdIngestModule.startUp.fileTypeDetectorInitializationException.msg=Error initializing the file type detector. -FileTypeIdGlobalSettingsPanel.isTrailingCheckBox.text=This signature is a trailing +FileTypeIdGlobalSettingsPanel.isTrailingCheckBox.text=This is a trailing signature From e2b4f59738b12913b1bd69b85d497aa73b47e14f Mon Sep 17 00:00:00 2001 From: millmanorama Date: Fri, 6 Nov 2015 10:15:04 -0500 Subject: [PATCH 11/24] fix scroll speed management simplify scroll speed management, and scroll bounds WIP, cleanup cleanup and comments --- .../ui/detailview/DetailViewPane.java | 156 ++++++++---------- .../ui/detailview/EventDetailsChart.java | 5 +- 2 files changed, 74 insertions(+), 87 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java index a881b4ff5a..e9f184c0bf 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java @@ -54,8 +54,6 @@ import static javafx.scene.input.KeyCode.PAGE_DOWN; import static javafx.scene.input.KeyCode.PAGE_UP; import static javafx.scene.input.KeyCode.UP; import javafx.scene.input.KeyEvent; -import javafx.scene.input.MouseEvent; -import javafx.scene.input.ScrollEvent; import javafx.scene.layout.HBox; import javafx.scene.layout.Pane; import javafx.scene.layout.Priority; @@ -93,53 +91,91 @@ public class DetailViewPane extends AbstractVisualizationPane>> treeSelectionModel; + private static final double LINE_SCROLL_PERCENTAGE = .10; + private static final double PAGE_SCROLL_PERCENTAGE = .70; - //these three could be injected from fxml but it was causing npe's private final DateAxis dateAxis = new DateAxis(); - private final Axis verticalAxis = new EventAxis(); + private final ScrollBar vertScrollBar = new ScrollBar(); + private final Region scrollBarSpacer = new Region(); + + private MultipleSelectionModel>> treeSelectionModel; + private final ObservableList> highlightedNodes = FXCollections.synchronizedObservableList(FXCollections.observableArrayList()); //private access to barchart data private final Map> eventTypeToSeriesMap = new ConcurrentHashMap<>(); - private final ScrollBar vertScrollBar = new ScrollBar(); - - private final Region region = new Region(); - - private final ObservableList> highlightedNodes = FXCollections.synchronizedObservableList(FXCollections.observableArrayList()); - public ObservableList> getEventBundles() { return chart.getEventBundles(); } + public DetailViewPane(TimeLineController controller, Pane partPane, Pane contextPane, Region bottomLeftSpacer) { + super(controller, partPane, contextPane, bottomLeftSpacer); + settingsNodes = new ArrayList<>(new DetailViewSettingsPane().getChildrenUnmodifiable()); - public DetailViewPane(TimeLineController controller, Pane partPane, Pane contextPane, Region spacer) { - super(controller, partPane, contextPane, spacer); + //initialize chart; chart = new EventDetailsChart(controller, dateAxis, verticalAxis, selectedNodes); - setChartClickHandler(); + setChartClickHandler(); //can we push this into chart chart.setData(dataSets); setCenter(chart); - - chart.setPrefHeight(USE_COMPUTED_SIZE); - - settingsNodes = new ArrayList<>(new DetailViewSettingsPane().getChildrenUnmodifiable()); - - vertScrollBar.setOrientation(Orientation.VERTICAL); - VBox vBox = new VBox(); - VBox.setVgrow(vertScrollBar, Priority.ALWAYS); - vBox.getChildren().add(vertScrollBar); - vBox.getChildren().add(region); - setRight(vBox); - + //bind layout fo axes and spacers + dateAxis.setTickLabelGap(0); dateAxis.setAutoRanging(false); - region.minHeightProperty().bind(dateAxis.heightProperty()); - vertScrollBar.visibleAmountProperty().bind(chart.heightProperty().multiply(100).divide(chart.maxVScrollProperty())); - requestLayout(); + dateAxis.setTickLabelsVisible(false); + dateAxis.getTickMarks().addListener((Observable observable) -> layoutDateLabels()); + dateAxis.getTickSpacing().addListener(observable -> layoutDateLabels()); + bottomLeftSpacer.minWidthProperty().bind(verticalAxis.widthProperty().add(verticalAxis.tickLengthProperty())); + bottomLeftSpacer.prefWidthProperty().bind(verticalAxis.widthProperty().add(verticalAxis.tickLengthProperty())); + bottomLeftSpacer.maxWidthProperty().bind(verticalAxis.widthProperty().add(verticalAxis.tickLengthProperty())); + + scrollBarSpacer.minHeightProperty().bind(dateAxis.heightProperty()); + + //configure scrollbar + vertScrollBar.setOrientation(Orientation.VERTICAL); + vertScrollBar.maxProperty().bind(chart.maxVScrollProperty().subtract(chart.heightProperty())); + vertScrollBar.visibleAmountProperty().bind(chart.heightProperty()); + vertScrollBar.visibleProperty().bind(vertScrollBar.visibleAmountProperty().greaterThanOrEqualTo(0)); + VBox.setVgrow(vertScrollBar, Priority.ALWAYS); + setRight(new VBox(vertScrollBar, scrollBarSpacer)); + + //interpret scroll events to the scrollBar + this.setOnScroll(scrollEvent -> + vertScrollBar.valueProperty().set(clampScroll(vertScrollBar.getValue() - scrollEvent.getDeltaY()))); + + //request focus for keyboard scrolling + setOnMouseClicked(mouseEvent -> requestFocus()); + + //interpret scroll related keys to scrollBar + this.setOnKeyPressed((KeyEvent t) -> { + switch (t.getCode()) { + case PAGE_UP: + incrementScrollValue(-PAGE_SCROLL_PERCENTAGE); + t.consume(); + break; + case PAGE_DOWN: + incrementScrollValue(PAGE_SCROLL_PERCENTAGE); + t.consume(); + break; + case KP_UP: + case UP: + incrementScrollValue(-LINE_SCROLL_PERCENTAGE); + t.consume(); + break; + case KP_DOWN: + case DOWN: + incrementScrollValue(LINE_SCROLL_PERCENTAGE); + t.consume(); + break; + } + }); + + //scrollbar value change handler. This forwards changes in scroll bar to chart + this.vertScrollBar.valueProperty().addListener(observable -> chart.setVScroll(vertScrollBar.getValue())); + + //maintain highlighted effect on correct nodes highlightedNodes.addListener((ListChangeListener.Change> change) -> { - while (change.next()) { change.getAddedSubList().forEach(node -> { node.applyHighlightEffect(true); @@ -149,71 +185,24 @@ public class DetailViewPane extends AbstractVisualizationPane { - requestFocus(); - }); - - //These scroll related handlers don't affect any other view or the model, so they are handled internally - //mouse wheel scroll handler - this.onScrollProperty().set((ScrollEvent t) -> { - vertScrollBar.valueProperty().set(Math.max(0, Math.min(100, vertScrollBar.getValue() - t.getDeltaY() / 200.0))); - }); - - this.setOnKeyPressed((KeyEvent t) -> { - switch (t.getCode()) { - case PAGE_UP: - incrementScrollValue(-70); - break; - case PAGE_DOWN: - incrementScrollValue(70); - break; - case KP_UP: - case UP: - incrementScrollValue(-10); - break; - case KP_DOWN: - case DOWN: - incrementScrollValue(10); - break; - } - t.consume(); - }); - - //scrollbar handler - this.vertScrollBar.valueProperty().addListener((o, oldValue, newValue) -> { - chart.setVScroll(newValue.doubleValue() / 100.0); - }); - spacer.minWidthProperty().bind(verticalAxis.widthProperty().add(verticalAxis.tickLengthProperty())); - spacer.prefWidthProperty().bind(verticalAxis.widthProperty().add(verticalAxis.tickLengthProperty())); - spacer.maxWidthProperty().bind(verticalAxis.widthProperty().add(verticalAxis.tickLengthProperty())); - - dateAxis.setTickLabelsVisible(false); - - dateAxis.getTickMarks().addListener((Observable observable) -> { - layoutDateLabels(); - }); - dateAxis.getTickSpacing().addListener((Observable observable) -> { - layoutDateLabels(); - }); - - dateAxis.setTickLabelGap(0); selectedNodes.addListener((Observable observable) -> { highlightedNodes.clear(); selectedNodes.stream().forEach((tn) -> { - for (EventBundleNodeBase n : chart.getNodes((EventBundleNodeBase t) -> t.getDescription().equals(tn.getDescription()))) { highlightedNodes.add(n); } }); }); - } - private void incrementScrollValue(int factor) { - vertScrollBar.valueProperty().set(Math.max(0, Math.min(100, vertScrollBar.getValue() + factor * (chart.getHeight() / chart.maxVScrollProperty().get())))); + private void incrementScrollValue(double factor) { + vertScrollBar.valueProperty().set(clampScroll(vertScrollBar.getValue() + factor * chart.getHeight())); + } + + private Double clampScroll(Double value) { + return Math.max(0, Math.min(vertScrollBar.getMax() + 50, value)); } public void setSelectionModel(MultipleSelectionModel>> selectionModel) { @@ -472,5 +461,4 @@ public class DetailViewPane extends AbstractVisualizationPane imp return getNodes(x -> true); } - synchronized void setVScroll(double d) { - final double h = maxY.get() - (getHeight() * .9); - nodeGroup.setTranslateY(-d * h); + synchronized void setVScroll(double vScrollValue) { + nodeGroup.setTranslateY(-vScrollValue); } private void clearGuideLine() { From c4d6c45ed9157c6c7d3dfbf334d0ea964284b34f Mon Sep 17 00:00:00 2001 From: momo Date: Mon, 9 Nov 2015 11:18:19 -0500 Subject: [PATCH 12/24] change feature layout and design --- .../modules/filetypeid/Bundle.properties | 5 +- .../autopsy/modules/filetypeid/FileType.java | 42 +++---- .../FileTypeIdGlobalSettingsPanel.form | 93 +++++++++------ .../FileTypeIdGlobalSettingsPanel.java | 110 +++++++++++------- .../autopsy/modules/filetypeid/FileTypes.xsd | 11 +- .../UserDefinedFileTypesManager.java | 18 ++- 6 files changed, 164 insertions(+), 115 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties index bc99ea014f..bf6adc0de3 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties @@ -23,10 +23,13 @@ FileTypeIdGlobalSettingsPanel.mimeTypeLabel.text=MIME Type FileTypeIdGlobalSettingsPanel.saveTypeButton.text=Save FileTypeIdGlobalSettingsPanel.signatureComboBox.rawItem=Bytes (Hex) FileTypeIdGlobalSettingsPanel.signatureComboBox.asciiItem=String (ASCII) +FileTypeIdGlobalSettingsPanel.offsetComboBox.startItem=Start +FileTypeIdGlobalSettingsPanel.offsetComboBox.endItem=End 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.length=Offset must not be smaller than signature size. 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. @@ -46,4 +49,4 @@ FileTypeIdGlobalSettingsPanel.jLabel2.text=MIME Types: FileTypeIdGlobalSettingsPanel.jLabel3.text=Autopsy can automatically detect many file types. Add your custom file types here. FileTypeIdGlobalSettingsPanel.startUp.fileTypeDetectorInitializationException.msg=Error initializing the file type detector. FileTypeIdIngestModule.startUp.fileTypeDetectorInitializationException.msg=Error initializing the file type detector. -FileTypeIdGlobalSettingsPanel.isTrailingCheckBox.text=This signature is a trailing +FileTypeIdGlobalSettingsPanel.offsetRelativeToLabel.text=Offset is relative to diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java index 133c1c6f84..a1f96d54d8 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java @@ -51,7 +51,7 @@ class FileType { */ FileType(String mimeType, final Signature signature, String filesSetName, boolean alert) { this.mimeType = mimeType; - this.signature = new Signature(signature.getSignatureBytes(), signature.getOffset(), signature.getType(), signature.isTrailing()); + this.signature = new Signature(signature.getSignatureBytes(), signature.getOffset(), signature.getType(), signature.isRelativeToStart()); this.interestingFilesSetName = filesSetName; this.alert = alert; } @@ -71,7 +71,7 @@ class FileType { * @return The signature. */ Signature getSignature() { - return new Signature(signature.getSignatureBytes(), signature.getOffset(), signature.getType(), signature.isTrailing()); + return new Signature(signature.getSignatureBytes(), signature.getOffset(), signature.getType(), signature.isRelativeToStart()); } /** @@ -148,7 +148,7 @@ class FileType { private final byte[] signatureBytes; private final long offset; private final Type type; - private final boolean trailing; + private final boolean isRelativeToStart; /** * Creates a file signature consisting of a sequence of bytes at a @@ -163,7 +163,7 @@ class FileType { this.signatureBytes = Arrays.copyOf(signatureBytes, signatureBytes.length); this.offset = offset; this.type = type; - this.trailing = false; + this.isRelativeToStart = true; } /** @@ -177,7 +177,7 @@ class FileType { this.signatureBytes = signatureString.getBytes(StandardCharsets.US_ASCII); this.offset = offset; this.type = Type.ASCII; - this.trailing = false; + this.isRelativeToStart = true; } /** @@ -193,7 +193,7 @@ class FileType { this.signatureBytes = Arrays.copyOf(signatureBytes, signatureBytes.length); this.offset = offset; this.type = Type.RAW; - this.trailing = false; + this.isRelativeToStart = true; } /** @@ -204,13 +204,13 @@ class FileType { * @param offset The offset of the signature bytes. * @param type The type of data in the byte array. Impacts * how it is displayed to the user in the UI. - * @param trailing Determines whether this signature is trailing. + * @param isRelativeToStart Determines whether this signature is relative to start. */ - Signature(final byte[] signatureBytes, long offset, Type type, boolean trailing) { + Signature(final byte[] signatureBytes, long offset, Type type, boolean isRelativeToStart) { this.signatureBytes = Arrays.copyOf(signatureBytes, signatureBytes.length); this.offset = offset; this.type = type; - this.trailing = trailing; + this.isRelativeToStart = isRelativeToStart; } /** @@ -219,13 +219,13 @@ class FileType { * * @param signatureString The ASCII string * @param offset The offset of the signature bytes. - * @param trailing Determines whether this signature is trailing. + * @param isRelativeToStart Determines whether this signature is relative to start. */ - Signature(String signatureString, long offset, boolean trailing) { + Signature(String signatureString, long offset, boolean isRelativeToStart) { this.signatureBytes = signatureString.getBytes(StandardCharsets.US_ASCII); this.offset = offset; this.type = Type.ASCII; - this.trailing = trailing; + this.isRelativeToStart = isRelativeToStart; } /** @@ -234,15 +234,15 @@ class FileType { * string, use one of the other constructors so that the string is * displayed to the user instead of the raw bytes. * - * @param signatureBytes The signature bytes. - * @param offset The offset of the signature bytes. - * @param trailing Determines whether this signature is trailing. + * @param signatureBytes The signature bytes. + * @param offset The offset of the signature bytes. + * @param isRelativeToStart Determines whether this signature is relative to start. */ - Signature(final byte[] signatureBytes, long offset, boolean trailing) { + Signature(final byte[] signatureBytes, long offset, boolean isRelativeToStart) { this.signatureBytes = Arrays.copyOf(signatureBytes, signatureBytes.length); this.offset = offset; this.type = Type.RAW; - this.trailing = trailing; + this.isRelativeToStart = isRelativeToStart; } /** @@ -272,8 +272,8 @@ class FileType { return type; } - boolean isTrailing() { - return trailing; + boolean isRelativeToStart() { + return isRelativeToStart; } /** @@ -286,8 +286,8 @@ class FileType { */ boolean containedIn(final AbstractFile file) { long actualOffset = offset; - if(trailing) - actualOffset = file.getSize() - signatureBytes.length - offset; + if(!isRelativeToStart) + actualOffset = file.getSize() - offset; if (file.getSize() < (actualOffset + signatureBytes.length)) { return false; /// too small, can't contain this signature } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form index 0e51a3c6bc..2b4647356c 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.form @@ -49,47 +49,56 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + - + @@ -108,7 +117,7 @@ - + @@ -139,14 +148,17 @@ - - + + + + + - - + + - + @@ -353,15 +365,22 @@ - + - - + + + + + + + + + + + + - - - diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java index 690cef660a..42c89f3386 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -52,6 +52,8 @@ 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"); + private static final String START_OFFSET_RELATIVE_COMBO_BOX_ITEM = NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.offsetComboBox.startItem"); + private static final String END_OFFSET_RELATIVE_COMBO_BOX_ITEM = NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.offsetComboBox.endItem"); /** * The list model for the file types list component of this panel is the set * of MIME types associated with the user-defined file types. A mapping of @@ -88,6 +90,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane private void customizeComponents() { setFileTypesListModel(); setSignatureTypeComboBoxModel(); + setOffsetRealtiveToComboBoxModel(); clearTypeDetailsComponents(); addTypeListSelectionListener(); addTextFieldListeners(); @@ -111,6 +114,17 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane signatureTypeComboBox.setModel(sigTypeComboBoxModel); signatureTypeComboBox.setSelectedItem(FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM); } + + /** + * Sets the model for the signature type combo box. + */ + private void setOffsetRealtiveToComboBoxModel() { + DefaultComboBoxModel offsetRelComboBoxModel = new DefaultComboBoxModel<>(); + offsetRelComboBoxModel.addElement(FileTypeIdGlobalSettingsPanel.START_OFFSET_RELATIVE_COMBO_BOX_ITEM); + offsetRelComboBoxModel.addElement(FileTypeIdGlobalSettingsPanel.END_OFFSET_RELATIVE_COMBO_BOX_ITEM); + offsetRelativeToComboBox.setModel(offsetRelComboBoxModel); + offsetRelativeToComboBox.setSelectedItem(FileTypeIdGlobalSettingsPanel.START_OFFSET_RELATIVE_COMBO_BOX_ITEM); + } /** * Adds a listener to the types list component so that the components in the @@ -270,7 +284,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane } } signatureTextField.setText(signatureBytes); - isTrailingCheckBox.setSelected(signature.isTrailing()); + offsetRelativeToComboBox.setSelectedItem(signature.isRelativeToStart() ? FileTypeIdGlobalSettingsPanel.START_OFFSET_RELATIVE_COMBO_BOX_ITEM : FileTypeIdGlobalSettingsPanel.END_OFFSET_RELATIVE_COMBO_BOX_ITEM); offsetTextField.setText(Long.toString(signature.getOffset())); postHitCheckBox.setSelected(fileType.alertOnMatch()); filesSetNameTextField.setEnabled(postHitCheckBox.isSelected()); @@ -290,7 +304,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane signatureTypeComboBox.setSelectedItem(FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM); hexPrefixLabel.setVisible(true); signatureTextField.setText("0000"); //NON-NLS - isTrailingCheckBox.setSelected(false); + offsetRelativeToComboBox.setSelectedItem(FileTypeIdGlobalSettingsPanel.START_OFFSET_RELATIVE_COMBO_BOX_ITEM); offsetTextField.setText(""); //NON-NLS postHitCheckBox.setSelected(false); filesSetNameTextField.setText(""); //NON-NLS @@ -362,7 +376,8 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane jLabel1 = new javax.swing.JLabel(); jLabel2 = new javax.swing.JLabel(); jLabel3 = new javax.swing.JLabel(); - isTrailingCheckBox = new javax.swing.JCheckBox(); + offsetRelativeToComboBox = new javax.swing.JComboBox(); + offsetRelativeToLabel = new javax.swing.JLabel(); setMaximumSize(new java.awt.Dimension(500, 300)); setPreferredSize(new java.awt.Dimension(500, 300)); @@ -442,12 +457,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.jLabel3.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(isTrailingCheckBox, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.isTrailingCheckBox.text")); // NOI18N - isTrailingCheckBox.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - isTrailingCheckBoxActionPerformed(evt); - } - }); + org.openide.awt.Mnemonics.setLocalizedText(offsetRelativeToLabel, org.openide.util.NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.offsetRelativeToLabel.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -475,37 +485,43 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(mimeTypeLabel) - .addGap(30, 30, 30) - .addComponent(mimeTypeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 176, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(postHitCheckBox) - .addGroup(layout.createSequentialGroup() - .addComponent(signatureTypeLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(signatureTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 176, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addComponent(signatureLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 73, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(hexPrefixLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(signatureTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 160, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .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)) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGap(21, 21, 21) .addComponent(filesSetNameLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(filesSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 182, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(filesSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 182, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(mimeTypeLabel) + .addGap(30, 30, 30) + .addComponent(mimeTypeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 176, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(postHitCheckBox) + .addGroup(layout.createSequentialGroup() + .addComponent(signatureTypeLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(signatureTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 176, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(signatureLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 73, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(hexPrefixLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(signatureTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 160, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .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))) + .addGap(6, 6, 6))) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addComponent(saveTypeButton) .addGap(8, 8, 8)) - .addComponent(isTrailingCheckBox))) + .addGroup(layout.createSequentialGroup() + .addComponent(offsetRelativeToLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(offsetRelativeToComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))) .addComponent(jLabel1) .addComponent(jLabel3)) - .addContainerGap(50, Short.MAX_VALUE)))) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -520,7 +536,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane .addGroup(layout.createSequentialGroup() .addComponent(jLabel2) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(typesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 173, Short.MAX_VALUE) + .addComponent(typesScrollPane) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(deleteTypeButton) @@ -543,13 +559,15 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane .addComponent(hexPrefixLabel) .addComponent(signatureTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(signatureLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(isTrailingCheckBox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(offsetLabel) + .addComponent(offsetTextField, 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(offsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(offsetLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(offsetRelativeToComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(offsetRelativeToLabel)) + .addGap(16, 16, 16) .addComponent(postHitCheckBox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) @@ -625,8 +643,16 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane * Get the offset. */ long offset; + boolean isRelativeToStart = offsetRelativeToComboBox.getSelectedItem() == FileTypeIdGlobalSettingsPanel.START_OFFSET_RELATIVE_COMBO_BOX_ITEM; try { offset = Long.parseUnsignedLong(offsetTextField.getText()); + if(!isRelativeToStart && sigString.length() > offset) { + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.length"), + NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.title"), + JOptionPane.ERROR_MESSAGE); + return; + } } catch (NumberFormatException ex) { JOptionPane.showMessageDialog(null, NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message"), @@ -653,8 +679,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane /** * Put it all together and reset the file types list component. */ - boolean isTrailing = isTrailingCheckBox.isSelected(); - FileType.Signature signature = new FileType.Signature(signatureBytes, offset, sigType, isTrailingCheckBox.isSelected()); + FileType.Signature signature = new FileType.Signature(signatureBytes, offset, sigType, isRelativeToStart); FileType fileType = new FileType(typeName, signature, filesSetName, postHitCheckBox.isSelected()); FileType selected = typesList.getSelectedValue(); if (selected != null) { @@ -684,17 +709,12 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane // TODO add your handling code here: }//GEN-LAST:event_signatureTextFieldActionPerformed - private void isTrailingCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_isTrailingCheckBoxActionPerformed - - }//GEN-LAST:event_isTrailingCheckBoxActionPerformed - // 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.JLabel ingestRunningWarningLabel; - private javax.swing.JCheckBox isTrailingCheckBox; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; @@ -702,6 +722,8 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane private javax.swing.JTextField mimeTypeTextField; private javax.swing.JButton newTypeButton; private javax.swing.JLabel offsetLabel; + private javax.swing.JComboBox offsetRelativeToComboBox; + private javax.swing.JLabel offsetRelativeToLabel; private javax.swing.JTextField offsetTextField; private javax.swing.JCheckBox postHitCheckBox; private javax.swing.JButton saveTypeButton; diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypes.xsd b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypes.xsd index 63dab70d24..d5812bcf19 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypes.xsd +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypes.xsd @@ -15,6 +15,14 @@ + + + + + + + + @@ -25,8 +33,7 @@ - - + diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java index 4d801c79be..2be7579081 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java @@ -68,7 +68,7 @@ final class UserDefinedFileTypesManager { 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 TRAILING_TAG_NAME = "Trailing"; + private static final String RELATIVE_ATTRIBUTE = "RelativeToStart"; 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 @@ -373,11 +373,8 @@ final class UserDefinedFileTypesManager { Element offsetElem = doc.createElement(OFFSET_TAG_NAME); offsetElem.setTextContent(DatatypeConverter.printLong(signature.getOffset())); + offsetElem.setAttribute(RELATIVE_ATTRIBUTE, String.valueOf(signature.isRelativeToStart())); signatureElem.appendChild(offsetElem); - - Element trailingElem = doc.createElement(TRAILING_TAG_NAME); - trailingElem.setTextContent(DatatypeConverter.printBoolean(signature.isTrailing())); - signatureElem.appendChild(trailingElem); signatureElem.setAttribute(SIGNATURE_TYPE_ATTRIBUTE, signature.getType().toString()); fileTypeElem.appendChild(signatureElem); @@ -486,16 +483,17 @@ final class UserDefinedFileTypesManager { String sigBytesString = getChildElementTextContent(signatureElem, BYTES_TAG_NAME); byte[] signatureBytes = DatatypeConverter.parseHexBinary(sigBytesString); - String offsetString = getChildElementTextContent(signatureElem, OFFSET_TAG_NAME); + Element offsetElem = (Element) signatureElem.getElementsByTagName(OFFSET_TAG_NAME).item(0); + String offsetString = offsetElem.getTextContent(); long offset = DatatypeConverter.parseLong(offsetString); - String trailingString = getChildElementTextContent(signatureElem, TRAILING_TAG_NAME); - if(trailingString == null) + String relativeString = offsetElem.getAttribute(RELATIVE_ATTRIBUTE); + if(relativeString == null) return new Signature(signatureBytes, offset, signatureType); - boolean trailing = DatatypeConverter.parseBoolean(trailingString); + boolean isRelative = DatatypeConverter.parseBoolean(relativeString); - return new Signature(signatureBytes, offset, signatureType, trailing); + return new Signature(signatureBytes, offset, signatureType, isRelative); } /** From e19e338db61bf0db6d57cb06c0b7b18eed265435 Mon Sep 17 00:00:00 2001 From: momo Date: Mon, 9 Nov 2015 12:58:12 -0500 Subject: [PATCH 13/24] some formatting --- .../autopsy/modules/filetypeid/Bundle.properties | 2 +- .../autopsy/modules/filetypeid/FileType.java | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties index c2cb3b4765..bf6adc0de3 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties @@ -49,4 +49,4 @@ FileTypeIdGlobalSettingsPanel.jLabel2.text=MIME Types: FileTypeIdGlobalSettingsPanel.jLabel3.text=Autopsy can automatically detect many file types. Add your custom file types here. FileTypeIdGlobalSettingsPanel.startUp.fileTypeDetectorInitializationException.msg=Error initializing the file type detector. FileTypeIdIngestModule.startUp.fileTypeDetectorInitializationException.msg=Error initializing the file type detector. -FileTypeIdGlobalSettingsPanel.offsetRelativeToLabel.text=Offset is relative to \ No newline at end of file +FileTypeIdGlobalSettingsPanel.offsetRelativeToLabel.text=Offset is relative to diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java index a1f96d54d8..9b65bcb63c 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java @@ -200,10 +200,10 @@ 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 offset The offset of the signature bytes. - * @param type The type of data in the byte array. Impacts - * how it is displayed to the user in the UI. + * @param signatureBytes The signature bytes. + * @param offset The offset of the signature bytes. + * @param type The type of data in the byte array. Impacts + * how it is displayed to the user in the UI. * @param isRelativeToStart Determines whether this signature is relative to start. */ Signature(final byte[] signatureBytes, long offset, Type type, boolean isRelativeToStart) { @@ -217,8 +217,8 @@ class FileType { * Creates a file signature consisting of an ASCII string at a * specific offset within a file. * - * @param signatureString The ASCII string - * @param offset The offset of the signature bytes. + * @param signatureString The ASCII string + * @param offset The offset of the signature bytes. * @param isRelativeToStart Determines whether this signature is relative to start. */ Signature(String signatureString, long offset, boolean isRelativeToStart) { From 6601110345a17fd9fbe0d4bc8477f73863212072 Mon Sep 17 00:00:00 2001 From: momo Date: Mon, 9 Nov 2015 13:07:50 -0500 Subject: [PATCH 14/24] support old format --- .../autopsy/modules/filetypeid/UserDefinedFileTypesManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java index 2be7579081..0418f1013e 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java @@ -488,7 +488,7 @@ final class UserDefinedFileTypesManager { long offset = DatatypeConverter.parseLong(offsetString); String relativeString = offsetElem.getAttribute(RELATIVE_ATTRIBUTE); - if(relativeString == null) + if(relativeString == null || relativeString.equals("")) return new Signature(signatureBytes, offset, signatureType); boolean isRelative = DatatypeConverter.parseBoolean(relativeString); From e58987e05df99c8e71c7dcec3a1554fe20c5d501 Mon Sep 17 00:00:00 2001 From: momo Date: Mon, 9 Nov 2015 13:14:37 -0500 Subject: [PATCH 15/24] clarifying comment --- .../autopsy/modules/filetypeid/UserDefinedFileTypesManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java index 0418f1013e..557c14a9a5 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java @@ -531,7 +531,7 @@ final class UserDefinedFileTypesManager { * @param elem The parent element. * @param tagName The tag name of the child element. * - * @return The text content. + * @return The text content or null if the tag doesn't exist. */ private static String getChildElementTextContent(Element elem, String tagName) { NodeList childElems = elem.getElementsByTagName(tagName); From 00f4f4309ffbb54bdec3b9baa2105601bb350e4c Mon Sep 17 00:00:00 2001 From: jmillman Date: Fri, 6 Nov 2015 16:39:54 -0500 Subject: [PATCH 16/24] fix tooltip on GuideLine --- .../timeline/ui/detailview/Bundle.properties | 1 - .../timeline/ui/detailview/GuideLine.java | 39 ++++++++++++------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/Bundle.properties b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/Bundle.properties index 091926228a..77bc1dd893 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/Bundle.properties @@ -1,4 +1,3 @@ -Timeline.ui.detailview.tooltip.text={0}\nRight-click to remove.\nRight-drag to reposition. DetailViewPane.loggedTask.name=Update Details DetailViewPane.loggedTask.preparing=preparing DetailViewPane.loggedTask.queryDb=querying db diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/GuideLine.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/GuideLine.java index 3a2dad163b..7d6ef47f50 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/GuideLine.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/GuideLine.java @@ -18,10 +18,10 @@ */ package org.sleuthkit.autopsy.timeline.ui.detailview; +import javafx.beans.binding.StringBinding; import javafx.scene.Cursor; import javafx.scene.chart.Axis; import javafx.scene.control.Tooltip; -import javafx.scene.input.MouseEvent; import javafx.scene.paint.Color; import javafx.scene.shape.Line; import org.joda.time.DateTime; @@ -31,44 +31,53 @@ import org.sleuthkit.autopsy.timeline.TimeLineController; /** * */ +@NbBundle.Messages({"GuideLine.tooltip.text={0}\nRight-click to remove.\nRight-drag to reposition."}) class GuideLine extends Line { private final Axis dateAxis; + private Tooltip tooltip = new Tooltip(); private double startLayoutX; - - protected Tooltip tooltip; - private double dragStartX = 0; GuideLine(double startX, double startY, double endX, double endY, Axis axis) { super(startX, startY, endX, endY); dateAxis = axis; + //TODO: assign via css setCursor(Cursor.E_RESIZE); getStrokeDashArray().setAll(5.0, 5.0); setStroke(Color.RED); setOpacity(.5); setStrokeWidth(3); - setOnMouseEntered((MouseEvent event) -> { - setTooltip(); - }); + Tooltip.install(this, tooltip); + tooltip.textProperty().bind(new StringBinding() { + { + bind(layoutXProperty()); + } - setOnMousePressed((MouseEvent event) -> { + @Override + protected String computeValue() { + return Bundle.GuideLine_tooltip_text(formatSpan(getDateTime())); + } + }); +// setOnMouseEntered(enteredEvent -> updateToolTipText()); + setOnMousePressed(pressedEvent -> { startLayoutX = getLayoutX(); - dragStartX = event.getScreenX(); + dragStartX = pressedEvent.getScreenX(); }); - setOnMouseDragged((MouseEvent event) -> { - double dX = event.getScreenX() - dragStartX; - + setOnMouseDragged(dragEvent -> { + double dX = dragEvent.getScreenX() - dragStartX; relocate(startLayoutX + dX, 0); +// updateToolTipText(); + dragEvent.consume(); }); } - private void setTooltip() { + private void updateToolTipText() { Tooltip.uninstall(this, tooltip); - tooltip = new Tooltip( - NbBundle.getMessage(this.getClass(), "Timeline.ui.detailview.tooltip.text", formatSpan(getDateTime()))); + + tooltip = new Tooltip(Bundle.GuideLine_tooltip_text(formatSpan(getDateTime()))); Tooltip.install(this, tooltip); } From 20debd55e730d0dbd98308cd74628129181f57cb Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 9 Nov 2015 17:16:56 -0500 Subject: [PATCH 17/24] improve default chart tooltip. fixe guideline tooltip. fix guideline drag mouse event handler --- .../ui/AbstractVisualizationPane.java | 15 +++-- .../ui/countsview/CountsViewPane.java | 2 +- .../ui/detailview/EventBundleNodeBase.java | 4 +- .../ui/detailview/EventDetailsChart.java | 14 ++--- .../timeline/ui/detailview/GuideLine.java | 56 +++++++++---------- 5 files changed, 40 insertions(+), 51 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java index 9ba8977757..52d64c0c1f 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java @@ -72,13 +72,12 @@ import org.sleuthkit.autopsy.timeline.events.RefreshRequestedEvent; * common history context menu items out of derived classes? -jm */ public abstract class AbstractVisualizationPane & TimeLineChart> extends BorderPane { - - @NbBundle.Messages("AbstractVisualization.Drag_Tooltip.text=Drag the mouse to select a time interval to zoom into.") - private static final Tooltip DRAG_TOOLTIP = new Tooltip(Bundle.AbstractVisualization_Drag_Tooltip_text()); + @NbBundle.Messages("AbstractVisualization.Default_Tooltip.text=Drag the mouse to select a time interval to zoom into.\nRight-click for more actions.") + private static final Tooltip DEFAULT_TOOLTIP = new Tooltip(Bundle.AbstractVisualization_Default_Tooltip_text()); private static final Logger LOGGER = Logger.getLogger(AbstractVisualizationPane.class.getName()); - public static Tooltip getDragTooltip() { - return DRAG_TOOLTIP; + public static Tooltip getDefaultTooltip() { + return DEFAULT_TOOLTIP; } protected final SimpleBooleanProperty hasEvents = new SimpleBooleanProperty(true); @@ -242,16 +241,16 @@ public abstract class AbstractVisualizationPane }); TimeLineController.getTimeZone().addListener(invalidationListener); - + //show tooltip text in status bar hoverProperty().addListener((observable, oldActivated, newActivated) -> { if (newActivated) { - controller.setStatus(DRAG_TOOLTIP.getText()); + controller.setStatus(DEFAULT_TOOLTIP.getText()); } else { controller.setStatus(""); } }); - + update(); } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/CountsViewPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/CountsViewPane.java index f33e4e53fe..ff5a3d4798 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/CountsViewPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/CountsViewPane.java @@ -267,7 +267,7 @@ public class CountsViewPane extends AbstractVisualizationPane(new CountsViewSettingsPane().getChildrenUnmodifiable()); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventBundleNodeBase.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventBundleNodeBase.java index 6c028f8dc6..de3e33abce 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventBundleNodeBase.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventBundleNodeBase.java @@ -175,7 +175,7 @@ public abstract class EventBundleNodeBase imp projectionMap.clear(); controller.selectEventIDs(Collections.emptyList()); }); - Tooltip.install(this, AbstractVisualizationPane.getDragTooltip()); + Tooltip.install(this, AbstractVisualizationPane.getDefaultTooltip()); dateAxis.setAutoRanging(false); @@ -430,7 +429,7 @@ public final class EventDetailsChart extends XYChart imp nodeGroup.setTranslateY(-d * h); } - private void clearGuideLine() { + void clearGuideLine() { getChartChildren().remove(guideLine); guideLine = null; } @@ -612,16 +611,11 @@ public final class EventDetailsChart extends XYChart imp setGraphic(new ImageView(MARKER)); // NON-NLS setEventHandler(actionEvent -> { if (guideLine == null) { - guideLine = new GuideLine(0, 0, 0, getHeight(), getXAxis()); + guideLine = new GuideLine(0, 0, 0, getHeight(), EventDetailsChart.this); guideLine.relocate(sceneToLocal(clickEvent.getSceneX(), 0).getX(), 0); guideLine.endYProperty().bind(heightProperty().subtract(getXAxis().heightProperty().subtract(getXAxis().tickLengthProperty()))); getChartChildren().add(guideLine); - guideLine.setOnMouseClicked(mouseEvent -> { - if (mouseEvent.getButton() == MouseButton.SECONDARY) { - clearGuideLine(); - mouseEvent.consume(); - } - }); + } else { guideLine.relocate(sceneToLocal(clickEvent.getSceneX(), 0).getX(), 0); } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/GuideLine.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/GuideLine.java index 7d6ef47f50..547db5a84c 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/GuideLine.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/GuideLine.java @@ -18,31 +18,40 @@ */ package org.sleuthkit.autopsy.timeline.ui.detailview; -import javafx.beans.binding.StringBinding; import javafx.scene.Cursor; -import javafx.scene.chart.Axis; import javafx.scene.control.Tooltip; +import javafx.scene.input.MouseButton; import javafx.scene.paint.Color; import javafx.scene.shape.Line; -import org.joda.time.DateTime; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.timeline.TimeLineController; +import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane; /** * */ -@NbBundle.Messages({"GuideLine.tooltip.text={0}\nRight-click to remove.\nRight-drag to reposition."}) +@NbBundle.Messages({"GuideLine.tooltip.text={0}\nRight-click to remove.\nDrag to reposition."}) class GuideLine extends Line { - private final Axis dateAxis; + private static final Tooltip CHART_DEFAULT_TOOLTIP = AbstractVisualizationPane.getDefaultTooltip(); + private Tooltip tooltip = new Tooltip(); private double startLayoutX; private double dragStartX = 0; + private final EventDetailsChart chart; - GuideLine(double startX, double startY, double endX, double endY, Axis axis) { + /** + * + * @param startX + * @param startY + * @param endX + * @param endY + * @param chart + */ + GuideLine(double startX, double startY, double endX, double endY, EventDetailsChart chart) { super(startX, startY, endX, endY); - dateAxis = axis; + this.chart = chart; //TODO: assign via css setCursor(Cursor.E_RESIZE); getStrokeDashArray().setAll(5.0, 5.0); @@ -51,17 +60,16 @@ class GuideLine extends Line { setStrokeWidth(3); Tooltip.install(this, tooltip); - tooltip.textProperty().bind(new StringBinding() { - { - bind(layoutXProperty()); - } - - @Override - protected String computeValue() { - return Bundle.GuideLine_tooltip_text(formatSpan(getDateTime())); + tooltip.setOnShowing(windowEvent -> tooltip.setText(Bundle.GuideLine_tooltip_text(getDateTimeAsString()))); + setOnMouseEntered(entered -> Tooltip.uninstall(chart, CHART_DEFAULT_TOOLTIP)); + setOnMouseExited(exited -> Tooltip.install(chart, CHART_DEFAULT_TOOLTIP)); + setOnMouseClicked(mouseEvent -> { + if (mouseEvent.getButton() == MouseButton.SECONDARY + && mouseEvent.isStillSincePress() == false) { + chart.clearGuideLine(); + mouseEvent.consume(); } }); -// setOnMouseEntered(enteredEvent -> updateToolTipText()); setOnMousePressed(pressedEvent -> { startLayoutX = getLayoutX(); dragStartX = pressedEvent.getScreenX(); @@ -69,24 +77,12 @@ class GuideLine extends Line { setOnMouseDragged(dragEvent -> { double dX = dragEvent.getScreenX() - dragStartX; relocate(startLayoutX + dX, 0); -// updateToolTipText(); dragEvent.consume(); }); } - private void updateToolTipText() { - Tooltip.uninstall(this, tooltip); - - tooltip = new Tooltip(Bundle.GuideLine_tooltip_text(formatSpan(getDateTime()))); - Tooltip.install(this, tooltip); - } - - private String formatSpan(DateTime date) { - return date.toString(TimeLineController.getZonedFormatter()); - } - - private DateTime getDateTime() { - return dateAxis.getValueForDisplay(dateAxis.parentToLocal(getLayoutX(), 0).getX()); + private String getDateTimeAsString() { + return chart.getDateTimeForPosition(getLayoutX()).toString(TimeLineController.getZonedFormatter()); } } From 4118514afc3b07c57a86f72ad14a20866425c0b8 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 10 Nov 2015 11:06:12 -0500 Subject: [PATCH 18/24] cleanup GuideLine.java : comments, reduce arguments to constructor, style via css cleanup EventDetailsChart.java: move GuideLine resizing behavior into GuideLine.java, add stylesheet --- .../ui/detailview/EventDetailsChart.java | 18 ++++-- .../ui/detailview/EventsDetailsChart.css | 7 +++ .../timeline/ui/detailview/GuideLine.java | 56 +++++++++---------- 3 files changed, 48 insertions(+), 33 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventsDetailsChart.css diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventDetailsChart.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventDetailsChart.java index da3ecf6053..9e8b7504dc 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventDetailsChart.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventDetailsChart.java @@ -50,6 +50,7 @@ import javafx.event.ActionEvent; import javafx.geometry.Insets; import javafx.scene.Cursor; import javafx.scene.Group; +import javafx.scene.Scene; import javafx.scene.chart.Axis; import javafx.scene.chart.NumberAxis; import javafx.scene.chart.XYChart; @@ -67,6 +68,7 @@ import org.controlsfx.control.action.ActionUtils; import org.joda.time.DateTime; import org.joda.time.Interval; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.datamodel.EventBundle; import org.sleuthkit.autopsy.timeline.datamodel.EventCluster; @@ -96,6 +98,7 @@ import org.sleuthkit.autopsy.timeline.zooming.DescriptionLoD; */ public final class EventDetailsChart extends XYChart implements TimeLineChart { + private static final String styleSheet = GuideLine.class.getResource("EventsDetailsChart.css").toExternalForm(); private static final Image HIDE = new Image("/org/sleuthkit/autopsy/timeline/images/eye--minus.png"); // NON-NLS private static final Image SHOW = new Image("/org/sleuthkit/autopsy/timeline/images/eye--plus.png"); // NON-NLS private static final Image MARKER = new Image("/org/sleuthkit/autopsy/timeline/images/marker.png", 16, 16, true, true, true); @@ -108,6 +111,7 @@ public final class EventDetailsChart extends XYChart imp private ContextMenu chartContextMenu; + @Override public ContextMenu getChartContextMenu() { return chartContextMenu; } @@ -115,6 +119,7 @@ public final class EventDetailsChart extends XYChart imp /** * a user positionable vertical line to help compare events */ + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) private Line guideLine; /** @@ -192,6 +197,13 @@ public final class EventDetailsChart extends XYChart imp this.controller = controller; this.filteredEvents = this.controller.getEventsModel(); + sceneProperty().addListener(observable -> { + Scene scene = getScene(); + if (scene != null && scene.getStylesheets().contains(styleSheet) == false) { + scene.getStylesheets().add(styleSheet); + } + }); + filteredEvents.zoomParametersProperty().addListener(o -> { clearGuideLine(); clearIntervalSelector(); @@ -199,15 +211,14 @@ public final class EventDetailsChart extends XYChart imp projectionMap.clear(); controller.selectEventIDs(Collections.emptyList()); }); + Tooltip.install(this, AbstractVisualizationPane.getDefaultTooltip()); dateAxis.setAutoRanging(false); - verticalAxis.setVisible(false);//TODO: why doesn't this hide the vertical axis, instead we have to turn off all parts individually? -jm verticalAxis.setTickLabelsVisible(false); verticalAxis.setTickMarkVisible(false); setLegendVisible(false); - setPadding(Insets.EMPTY); setAlternativeColumnFillVisible(true); @@ -611,9 +622,8 @@ public final class EventDetailsChart extends XYChart imp setGraphic(new ImageView(MARKER)); // NON-NLS setEventHandler(actionEvent -> { if (guideLine == null) { - guideLine = new GuideLine(0, 0, 0, getHeight(), EventDetailsChart.this); + guideLine = new GuideLine(EventDetailsChart.this); guideLine.relocate(sceneToLocal(clickEvent.getSceneX(), 0).getX(), 0); - guideLine.endYProperty().bind(heightProperty().subtract(getXAxis().heightProperty().subtract(getXAxis().tickLengthProperty()))); getChartChildren().add(guideLine); } else { diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventsDetailsChart.css b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventsDetailsChart.css new file mode 100644 index 0000000000..c89d12a374 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventsDetailsChart.css @@ -0,0 +1,7 @@ +.guide-line{ + -fx-opacity: .5; + -fx-stroke: red; + -fx-stroke-dash-array: 5 5; + -fx-stroke-width: 3; + -fx-cursor: h-resize; +} \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/GuideLine.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/GuideLine.java index 547db5a84c..0c8cbfeffd 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/GuideLine.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/GuideLine.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2014-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,56 +18,55 @@ */ package org.sleuthkit.autopsy.timeline.ui.detailview; -import javafx.scene.Cursor; +import javafx.scene.chart.Axis; import javafx.scene.control.Tooltip; import javafx.scene.input.MouseButton; -import javafx.scene.paint.Color; import javafx.scene.shape.Line; +import org.joda.time.DateTime; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane; /** - * + * Subclass of {@link Line} with appropriate behavior (mouse listeners) to act + * as a visual reference point in the details view. */ -@NbBundle.Messages({"GuideLine.tooltip.text={0}\nRight-click to remove.\nDrag to reposition."}) +@NbBundle.Messages({"# {0} - date/time at guideline position", + "GuideLine.tooltip.text={0}\nRight-click to remove.\nDrag to reposition."}) class GuideLine extends Line { private static final Tooltip CHART_DEFAULT_TOOLTIP = AbstractVisualizationPane.getDefaultTooltip(); - private Tooltip tooltip = new Tooltip(); - - private double startLayoutX; - private double dragStartX = 0; + private final Tooltip tooltip = new Tooltip(); private final EventDetailsChart chart; + //used across invocations of mouse event handlers to maintain state + private double startLayoutX; + private double dragStartX = 0; + /** - * - * @param startX - * @param startY - * @param endX - * @param endY - * @param chart + * @param chart the chart this GuideLine belongs to. */ - GuideLine(double startX, double startY, double endX, double endY, EventDetailsChart chart) { - super(startX, startY, endX, endY); + GuideLine(EventDetailsChart chart) { + super(0, 0, 0, 0); this.chart = chart; - //TODO: assign via css - setCursor(Cursor.E_RESIZE); - getStrokeDashArray().setAll(5.0, 5.0); - setStroke(Color.RED); - setOpacity(.5); - setStrokeWidth(3); + Axis xAxis = chart.getXAxis(); + endYProperty().bind(chart.heightProperty().subtract(xAxis.heightProperty().subtract(xAxis.tickLengthProperty()))); + + getStyleClass().add("guide-line"); Tooltip.install(this, tooltip); - tooltip.setOnShowing(windowEvent -> tooltip.setText(Bundle.GuideLine_tooltip_text(getDateTimeAsString()))); + tooltip.setOnShowing(showing -> tooltip.setText(Bundle.GuideLine_tooltip_text(getDateTimeAsString()))); + + //this is a hack to override the tooltip of the enclosing chart. setOnMouseEntered(entered -> Tooltip.uninstall(chart, CHART_DEFAULT_TOOLTIP)); setOnMouseExited(exited -> Tooltip.install(chart, CHART_DEFAULT_TOOLTIP)); - setOnMouseClicked(mouseEvent -> { - if (mouseEvent.getButton() == MouseButton.SECONDARY - && mouseEvent.isStillSincePress() == false) { + + setOnMouseClicked(clickedEvent -> { + if (clickedEvent.getButton() == MouseButton.SECONDARY + && clickedEvent.isStillSincePress() == false) { chart.clearGuideLine(); - mouseEvent.consume(); + clickedEvent.consume(); } }); setOnMousePressed(pressedEvent -> { @@ -84,5 +83,4 @@ class GuideLine extends Line { private String getDateTimeAsString() { return chart.getDateTimeForPosition(getLayoutX()).toString(TimeLineController.getZonedFormatter()); } - } From 8b383096e220093db1815b6014aacff820214aae Mon Sep 17 00:00:00 2001 From: millmanorama Date: Tue, 10 Nov 2015 13:49:43 -0500 Subject: [PATCH 19/24] add "back" to actions available form no events dialog adjust layout of no events dialog move strings from Bundle.properties to NbBundle.Messages annotations --- .../autopsy/timeline/actions/Back.java | 9 +- .../timeline/actions/Bundle.properties | 4 - .../autopsy/timeline/actions/Forward.java | 3 +- .../timeline/actions/ResetFilters.java | 5 +- .../autopsy/timeline/ui/NoEventsDialog.fxml | 146 +++++++++++------- .../timeline/ui/VisualizationPanel.java | 17 +- 6 files changed, 107 insertions(+), 77 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/timeline/actions/Bundle.properties diff --git a/Core/src/org/sleuthkit/autopsy/timeline/actions/Back.java b/Core/src/org/sleuthkit/autopsy/timeline/actions/Back.java index af77a6231d..1313b18483 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/actions/Back.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/actions/Back.java @@ -32,13 +32,16 @@ import org.sleuthkit.autopsy.timeline.TimeLineController; */ //TODO: This and the corresponding imageanalyzer action are identical except for the type of the controller... abstract something! -jm public class Back extends Action { - + private static final Image BACK_IMAGE = new Image("/org/sleuthkit/autopsy/timeline/images/arrow-180.png", 16, 16, true, true, true); // NON-NLS private final TimeLineController controller; - + + @NbBundle.Messages({"Back.text=Back", + "Back.longText=Go back to the last view settings."}) public Back(TimeLineController controller) { - super(NbBundle.getMessage(Back.class, "Back.actions.name.text")); + super(Bundle.Back_text()); + setLongText(Bundle.Back_longText()); setGraphic(new ImageView(BACK_IMAGE)); setAccelerator(new KeyCodeCombination(KeyCode.LEFT, KeyCodeCombination.ALT_DOWN)); this.controller = controller; diff --git a/Core/src/org/sleuthkit/autopsy/timeline/actions/Bundle.properties b/Core/src/org/sleuthkit/autopsy/timeline/actions/Bundle.properties deleted file mode 100644 index 1140e0d19b..0000000000 --- a/Core/src/org/sleuthkit/autopsy/timeline/actions/Bundle.properties +++ /dev/null @@ -1,4 +0,0 @@ -Back.actions.name.text=Back -DefaultFilters.action.name.text=apply default filters -Forward.action.name.text=Forward - diff --git a/Core/src/org/sleuthkit/autopsy/timeline/actions/Forward.java b/Core/src/org/sleuthkit/autopsy/timeline/actions/Forward.java index 41df360a3a..b0b7e3e29b 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/actions/Forward.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/actions/Forward.java @@ -37,8 +37,9 @@ public class Forward extends Action { private final TimeLineController controller; + @NbBundle.Messages("Forward.text=Forward") public Forward(TimeLineController controller) { - super(NbBundle.getMessage(Forward.class, "Forward.action.name.text")); + super(Bundle.Forward_text()); setGraphic(new ImageView(BACK_IMAGE)); setAccelerator(new KeyCodeCombination(KeyCode.RIGHT, KeyCodeCombination.ALT_DOWN)); this.controller = controller; diff --git a/Core/src/org/sleuthkit/autopsy/timeline/actions/ResetFilters.java b/Core/src/org/sleuthkit/autopsy/timeline/actions/ResetFilters.java index c869c871c8..3d38fb0e4e 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/actions/ResetFilters.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/actions/ResetFilters.java @@ -32,8 +32,11 @@ public class ResetFilters extends Action { private FilteredEventsModel eventsModel; + @NbBundle.Messages({"ResetFilters.text=Reset all filters", + "RestFilters.longText=Reset all filters to their default state."}) public ResetFilters(final TimeLineController controller) { - super(NbBundle.getMessage(ResetFilters.class, "DefaultFilters.action.name.text")); + super(Bundle.ResetFilters_text()); + setLongText(Bundle.RestFilters_longText()); eventsModel = controller.getEventsModel(); disabledProperty().bind(new BooleanBinding() { { diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/NoEventsDialog.fxml b/Core/src/org/sleuthkit/autopsy/timeline/ui/NoEventsDialog.fxml index 418df66a39..d4352a23b9 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/NoEventsDialog.fxml +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/NoEventsDialog.fxml @@ -7,68 +7,94 @@ - - - + + + + + + + + + + - - - - - - - - - - - + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java index 6d0985eaf6..afa2f7a895 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java @@ -37,7 +37,6 @@ import javafx.geometry.Insets; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.MenuButton; -import javafx.scene.control.TitledPane; import javafx.scene.control.Toggle; import javafx.scene.control.ToggleButton; import javafx.scene.control.ToolBar; @@ -74,6 +73,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.timeline.FXMLConstructor; import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.VisualizationMode; +import org.sleuthkit.autopsy.timeline.actions.Back; import org.sleuthkit.autopsy.timeline.actions.ResetFilters; import org.sleuthkit.autopsy.timeline.actions.SaveSnapshotAsReport; import org.sleuthkit.autopsy.timeline.actions.ZoomIn; @@ -537,8 +537,10 @@ final public class VisualizationPanel extends BorderPane { } } - private class NoEventsDialog extends TitledPane { + private class NoEventsDialog extends StackPane { + @FXML + private Button backButton; @FXML private Button resetFiltersButton; @FXML @@ -562,13 +564,12 @@ final public class VisualizationPanel extends BorderPane { assert zoomButton != null : "fx:id=\"zoomButton\" was not injected: check your FXML file 'NoEventsDialog.fxml'."; // NON-NLS noEventsDialogLabel.setText(NbBundle.getMessage(NoEventsDialog.class, "VisualizationPanel.noEventsDialogLabel.text")); // NON-NLS - ActionUtils.configureButton(new ZoomToEvents(controller), zoomButton); - + dismissButton.setOnAction(actionEvent -> closeCallback.run()); - Action defaultFiltersAction = new ResetFilters(controller); - resetFiltersButton.setOnAction(defaultFiltersAction); - resetFiltersButton.disableProperty().bind(defaultFiltersAction.disabledProperty()); - resetFiltersButton.setText(NbBundle.getMessage(NoEventsDialog.class, "VisualizationPanel.resetFiltersButton.text")); // NON-NLS + + ActionUtils.configureButton(new ZoomToEvents(controller), zoomButton); + ActionUtils.configureButton(new Back(controller), backButton); + ActionUtils.configureButton(new ResetFilters(controller), resetFiltersButton); } } From de96de9c491b6181f0fdbf9a4037773a20a3bc52 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Tue, 10 Nov 2015 15:07:09 -0500 Subject: [PATCH 20/24] WIP --- .../actions/SaveSnapshotAsReport.java | 56 +++++++++++++------ 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java b/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java index e3a06617c7..f9aa166ae5 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2014-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,21 +25,26 @@ import java.io.IOException; import java.io.InputStream; import java.io.Writer; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.function.Consumer; import java.util.logging.Level; import javafx.embed.swing.SwingFXUtils; import javafx.event.ActionEvent; import javafx.scene.Node; +import javafx.scene.control.Alert; +import javafx.scene.control.ButtonType; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.image.WritableImage; -import javafx.stage.DirectoryChooser; import javafx.util.Pair; import javax.imageio.ImageIO; import org.controlsfx.control.action.Action; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; @@ -57,7 +62,7 @@ public class SaveSnapshotAsReport extends Action { private static final Logger LOGGER = Logger.getLogger(SaveSnapshotAsReport.class.getName()); - @NbBundle.Messages({"SaveSnapshot.action.name.text=Snapshot", + @NbBundle.Messages({"SaveSnapshot.action.name.text=Snapshot Report", "SaveSnapshot.action.longText=Save a screen capture of the visualization as a report.", "SaveSnapshot.fileChoose.title.text=Save snapshot to",}) public SaveSnapshotAsReport(TimeLineController controller, Node node) { @@ -69,17 +74,14 @@ public class SaveSnapshotAsReport extends Action { @Override public void accept(ActionEvent t) { //choose location/name - DirectoryChooser fileChooser = new DirectoryChooser(); - fileChooser.setTitle(Bundle.SaveSnapshot_fileChoose_title_text()); - fileChooser.setInitialDirectory(new File(Case.getCurrentCase().getReportDirectory())); - File reportDirectory = fileChooser.showDialog(null); - if (reportDirectory == null) { - return; + ZonedDateTime now = ZonedDateTime.now(); + String reportName = "timeline-report-" + now.toString(); + Path reportPath = Paths.get(Case.getCurrentCase().getReportDirectory(), reportName).toAbsolutePath(); + try { + Files.createDirectories(reportPath); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); } - reportDirectory.mkdir(); - String reportName = reportDirectory.getName(); - String reportPath = reportDirectory.getPath(); - //gather metadata List> reportMetaData = new ArrayList<>(); @@ -95,7 +97,7 @@ public class SaveSnapshotAsReport extends Action { try { WritableImage snapshot = node.snapshot(null, null); ImageIO.write(SwingFXUtils.fromFXImage(snapshot, null), "png", - new File(reportPath, reportName + REPORT_IMAGE_EXTENSION)); // NON-NLS + reportPath.resolve(reportName + REPORT_IMAGE_EXTENSION).toFile()); // NON-NLS } catch (IOException ex) { LOGGER.log(Level.WARNING, "failed to write snapshot to disk", ex); // NON-NLS return; @@ -104,15 +106,15 @@ public class SaveSnapshotAsReport extends Action { //build html string StringBuilder wrapper = new StringBuilder(); wrapper.append("\n\n\t").append("timeline snapshot").append("\n\t\n\n\n"); // NON-NLS - wrapper.append("
\n

").append(reportDirectory.getName()).append("

\n"); // NON-NLS - wrapper.append("\"snaphot\""); // NON-NLS + wrapper.append("
\n

").append(reportName).append("

\n"); // NON-NLS + wrapper.append("\"snaphot\""); // NON-NLS wrapper.append("\n"); // NON-NLS for (Pair pair : reportMetaData) { wrapper.append("\n"); // NON-NLS } wrapper.append("
").append(pair.getKey()).append(": ").append(pair.getValue()).append("
\n"); // NON-NLS wrapper.append("
\n\n"); // NON-NLS - File reportHTMLFIle = new File(reportDirectory, reportName + HTML_EXT); + File reportHTMLFIle = reportPath.resolve(reportName + HTML_EXT).toFile(); //write html wrapper try (Writer htmlWriter = new FileWriter(reportHTMLFIle)) { @@ -127,7 +129,7 @@ public class SaveSnapshotAsReport extends Action { //copy css try (InputStream resource = this.getClass().getResourceAsStream("/org/sleuthkit/autopsy/timeline/index.css")) { // NON-NLS - Files.copy(resource, Paths.get(reportPath, "index.css")); // NON-NLS + Files.copy(resource, reportPath.resolve("index.css")); // NON-NLS } catch (IOException ex) { LOGGER.log(Level.WARNING, "failed to copy css file", ex); // NON-NLS } @@ -138,6 +140,24 @@ public class SaveSnapshotAsReport extends Action { } catch (TskCoreException ex) { LOGGER.log(Level.WARNING, "failed add html wrapper as a report", ex); // NON-NLS } + + ButtonType show = new ButtonType("Show in Autopsy"); + ButtonType open = new ButtonType("Open"); + + Optional showAndWait = new Alert(Alert.AlertType.INFORMATION, "Snapshot saved at " + reportPath, open, show, ButtonType.OK).showAndWait(); + + showAndWait.ifPresent((ButtonType t1) -> { + if (t1 == show) { + //do something + System.out.println("show"); + } else if (t1 == open) { + //do something + System.out.println("open"); + } else { + //do something + System.out.println("nothing"); + } + }); } }); } From 7fa37d460b3e365d3335ba2e0797ba768ea0af27 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Tue, 10 Nov 2015 15:31:40 -0500 Subject: [PATCH 21/24] escape file name --- .../autopsy/timeline/actions/SaveSnapshotAsReport.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java b/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java index f9aa166ae5..4f2ee8b5b8 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java @@ -47,6 +47,7 @@ import org.controlsfx.control.action.Action; import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.zooming.ZoomParams; @@ -75,7 +76,10 @@ public class SaveSnapshotAsReport extends Action { public void accept(ActionEvent t) { //choose location/name ZonedDateTime now = ZonedDateTime.now(); - String reportName = "timeline-report-" + now.toString(); + + String reportName = "timeline-report-" + FileUtil.escapeFileName(now.toString()); + System.out.println(reportName); + System.out.println(Case.getCurrentCase().getReportDirectory()); Path reportPath = Paths.get(Case.getCurrentCase().getReportDirectory(), reportName).toAbsolutePath(); try { Files.createDirectories(reportPath); From a340a9542fd6d725bdb3dd6d763cd575e5f0b3a6 Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 11 Nov 2015 14:30:18 -0500 Subject: [PATCH 22/24] fix NPE caused by faulty reordering of steps in constructor --- .../autopsy/timeline/ui/detailview/DetailViewPane.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java index e9f184c0bf..6a8e6355f2 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java @@ -111,7 +111,6 @@ public class DetailViewPane extends AbstractVisualizationPane(new DetailViewSettingsPane().getChildrenUnmodifiable()); //initialize chart; chart = new EventDetailsChart(controller, dateAxis, verticalAxis, selectedNodes); @@ -119,6 +118,8 @@ public class DetailViewPane extends AbstractVisualizationPane(new DetailViewSettingsPane().getChildrenUnmodifiable()); + //bind layout fo axes and spacers dateAxis.setTickLabelGap(0); dateAxis.setAutoRanging(false); @@ -398,7 +399,7 @@ public class DetailViewPane extends AbstractVisualizationPane Date: Wed, 11 Nov 2015 11:28:52 -0500 Subject: [PATCH 23/24] cleanup --- .../actions/SaveSnapshotAsReport.java | 237 +++++++++++------- 1 file changed, 141 insertions(+), 96 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java b/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java index 4f2ee8b5b8..ec80b5180d 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java @@ -18,8 +18,8 @@ */ package org.sleuthkit.autopsy.timeline.actions; +import java.awt.Desktop; import java.io.File; -import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; @@ -27,24 +27,23 @@ import java.io.Writer; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; +import java.time.LocalDateTime; import java.util.function.Consumer; import java.util.logging.Level; import javafx.embed.swing.SwingFXUtils; import javafx.event.ActionEvent; import javafx.scene.Node; import javafx.scene.control.Alert; +import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonType; import javafx.scene.image.Image; import javafx.scene.image.ImageView; -import javafx.scene.image.WritableImage; -import javafx.util.Pair; +import javafx.stage.Modality; +import javafx.stage.StageStyle; import javax.imageio.ImageIO; +import javax.swing.JOptionPane; +import org.controlsfx.control.HyperlinkLabel; import org.controlsfx.control.action.Action; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.FileUtil; @@ -54,18 +53,28 @@ import org.sleuthkit.autopsy.timeline.zooming.ZoomParams; import org.sleuthkit.datamodel.TskCoreException; /** + * Save a snapshot of the given node as an autopsy report. */ public class SaveSnapshotAsReport extends Action { - private static final Image SNAP_SHOT = new Image("org/sleuthkit/autopsy/timeline/images/image.png", 16, 16, true, true); - private static final String HTML_EXT = ".html"; - private static final String REPORT_IMAGE_EXTENSION = ".png"; - private static final Logger LOGGER = Logger.getLogger(SaveSnapshotAsReport.class.getName()); + private static final Image SNAP_SHOT = new Image("org/sleuthkit/autopsy/timeline/images/image.png", 16, 16, true, true); // NON-NLS + private static final String HTML_EXT = ".html"; // NON-NLS + private static final String REPORT_IMAGE_EXTENSION = ".png"; // NON-NLS + private static final ButtonType open = new ButtonType(Bundle.OpenReportAction_DisplayName(), ButtonBar.ButtonData.NO); + private static final ButtonType ok = new ButtonType(ButtonType.OK.getText(), ButtonBar.ButtonData.CANCEL_CLOSE); @NbBundle.Messages({"SaveSnapshot.action.name.text=Snapshot Report", "SaveSnapshot.action.longText=Save a screen capture of the visualization as a report.", - "SaveSnapshot.fileChoose.title.text=Save snapshot to",}) + "SaveSnapshot.fileChoose.title.text=Save snapshot to", + "# {0} - report file path", + "SaveSnapShotAsReport.ReportSavedAt=Report saved at [{0}]", + "Timeline.ModuleName=Timeline", "SaveSnapShotAsReport.Success=Success", + "# {0} - uniqueness identifier, local date time at report creation time", + "SaveSnapsHotAsReport.ReportName=timeline-report-{0}", + "SaveSnapShotAsReport.FailedToAddReport=Failed to add snaphot as a report. See log for details", + "# {0} - report name", + "SaveSnapShotAsReport.ErrorWritingReport=Error writing report {0} to disk. See log for details",}) public SaveSnapshotAsReport(TimeLineController controller, Node node) { super(Bundle.SaveSnapshot_action_name_text()); setLongText(Bundle.SaveSnapshot_action_longText()); @@ -73,96 +82,132 @@ public class SaveSnapshotAsReport extends Action { setEventHandler(new Consumer() { @Override - public void accept(ActionEvent t) { - //choose location/name - ZonedDateTime now = ZonedDateTime.now(); - - String reportName = "timeline-report-" + FileUtil.escapeFileName(now.toString()); - System.out.println(reportName); - System.out.println(Case.getCurrentCase().getReportDirectory()); + public void accept(ActionEvent actioneEvent) { + String escapedLocalDateTime = FileUtil.escapeFileName(LocalDateTime.now().toString()); + String reportName = Bundle.SaveSnapsHotAsReport_ReportName(escapedLocalDateTime); Path reportPath = Paths.get(Case.getCurrentCase().getReportDirectory(), reportName).toAbsolutePath(); - try { - Files.createDirectories(reportPath); - } catch (IOException ex) { - Exceptions.printStackTrace(ex); - } - //gather metadata - List> reportMetaData = new ArrayList<>(); - - reportMetaData.add(new Pair<>("Case", Case.getCurrentCase().getName())); // NON-NLS - - ZoomParams zoomParams = controller.getEventsModel().zoomParametersProperty().get(); - reportMetaData.add(new Pair<>("Time Range", zoomParams.getTimeRange().toString())); // NON-NLS - reportMetaData.add(new Pair<>("Description Level of Detail", zoomParams.getDescriptionLOD().getDisplayName())); // NON-NLS - reportMetaData.add(new Pair<>("Event Type Zoom Level", zoomParams.getTypeZoomLevel().getDisplayName())); // NON-NLS - reportMetaData.add(new Pair<>("Filters", zoomParams.getFilter().getHTMLReportString())); // NON-NLS - - //save snapshot as png - try { - WritableImage snapshot = node.snapshot(null, null); - ImageIO.write(SwingFXUtils.fromFXImage(snapshot, null), "png", - reportPath.resolve(reportName + REPORT_IMAGE_EXTENSION).toFile()); // NON-NLS - } catch (IOException ex) { - LOGGER.log(Level.WARNING, "failed to write snapshot to disk", ex); // NON-NLS - return; - } - - //build html string - StringBuilder wrapper = new StringBuilder(); - wrapper.append("\n\n\t").append("timeline snapshot").append("\n\t\n\n\n"); // NON-NLS - wrapper.append("
\n

").append(reportName).append("

\n"); // NON-NLS - wrapper.append("\"snaphot\""); // NON-NLS - wrapper.append("\n"); // NON-NLS - for (Pair pair : reportMetaData) { - wrapper.append("\n"); // NON-NLS - } - wrapper.append("
").append(pair.getKey()).append(": ").append(pair.getValue()).append("
\n"); // NON-NLS - wrapper.append("
\n\n"); // NON-NLS File reportHTMLFIle = reportPath.resolve(reportName + HTML_EXT).toFile(); - //write html wrapper - try (Writer htmlWriter = new FileWriter(reportHTMLFIle)) { - htmlWriter.write(wrapper.toString()); - } catch (FileNotFoundException ex) { - LOGGER.log(Level.WARNING, "failed to open html wrapper file for writing ", ex); // NON-NLS - return; - } catch (IOException ex) { - LOGGER.log(Level.WARNING, "failed to write html wrapper file", ex); // NON-NLS - return; - } + ZoomParams zoomParams = controller.getEventsModel().zoomParametersProperty().get(); - //copy css - try (InputStream resource = this.getClass().getResourceAsStream("/org/sleuthkit/autopsy/timeline/index.css")) { // NON-NLS - Files.copy(resource, reportPath.resolve("index.css")); // NON-NLS - } catch (IOException ex) { - LOGGER.log(Level.WARNING, "failed to copy css file", ex); // NON-NLS - } - - //add html file as report to case try { - Case.getCurrentCase().addReport(reportHTMLFIle.getPath(), "Timeline", reportName + HTML_EXT); // NON-NLS - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "failed add html wrapper as a report", ex); // NON-NLS - } - - ButtonType show = new ButtonType("Show in Autopsy"); - ButtonType open = new ButtonType("Open"); - - Optional showAndWait = new Alert(Alert.AlertType.INFORMATION, "Snapshot saved at " + reportPath, open, show, ButtonType.OK).showAndWait(); - - showAndWait.ifPresent((ButtonType t1) -> { - if (t1 == show) { - //do something - System.out.println("show"); - } else if (t1 == open) { - //do something - System.out.println("open"); - } else { - //do something - System.out.println("nothing"); + //ensure directory exists and write html file + Files.createDirectories(reportPath); + try (Writer htmlWriter = new FileWriter(reportHTMLFIle)) { + writeHTMLFile(reportName, htmlWriter, zoomParams); } - }); + + //take snapshot and save in report directory + ImageIO.write(SwingFXUtils.fromFXImage(node.snapshot(null, null), null), "png", // NON-NLS + reportPath.resolve(reportName + REPORT_IMAGE_EXTENSION).toFile()); // NON-NLS + + //copy report css + try (InputStream resource = this.getClass().getResourceAsStream("/org/sleuthkit/autopsy/timeline/index.css")) { // NON-NLS + Files.copy(resource, reportPath.resolve("index.css")); // NON-NLS + } + + //add html file as report to case + try { + Case.getCurrentCase().addReport(reportHTMLFIle.getPath(), Bundle.Timeline_ModuleName(), reportName + HTML_EXT); // NON-NLS + } catch (TskCoreException ex) { + LOGGER.log(Level.WARNING, "failed to add html wrapper as a report", ex); // NON-NLS + new Alert(Alert.AlertType.ERROR, Bundle.SaveSnapShotAsReport_FailedToAddReport()).showAndWait(); + } + + //create alert to notify user of report location + final Alert alert = new Alert(Alert.AlertType.INFORMATION, null, open, ok); + alert.setTitle(Bundle.SaveSnapshot_action_name_text()); + alert.setHeaderText(Bundle.SaveSnapShotAsReport_Success()); + alert.initStyle(StageStyle.UTILITY); + alert.initOwner(node.getScene().getWindow()); + alert.initModality(Modality.APPLICATION_MODAL); + + //make action to open report, and hyperlinklable to invoke action + final OpenReportAction openReportAction = new OpenReportAction(reportHTMLFIle); + HyperlinkLabel hyperlinkLabel = new HyperlinkLabel(Bundle.SaveSnapShotAsReport_ReportSavedAt(reportHTMLFIle.getPath())); + hyperlinkLabel.setOnAction(openReportAction); + alert.getDialogPane().setContent(hyperlinkLabel); + + alert.showAndWait().ifPresent(buttonType -> { + if (buttonType == open) { + openReportAction.handle(null); + } + }); + + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Error writing report " + reportPath + " to disk", e); // NON-NLS + new Alert(Alert.AlertType.ERROR, Bundle.SaveSnapShotAsReport_ErrorWritingReport(reportPath)).showAndWait(); + } } }); } + + private static void writeHTMLFile(String reportName, final Writer htmlWriter, ZoomParams zoomParams) throws IOException { + + //write html wrapper file + htmlWriter.write("\n\n\ttimeline snapshot\n\t\n\n\n"); // NON-NLS + htmlWriter.write("
\n

" + reportName + "

\n"); // NON-NLS + //embed snapshot + htmlWriter.write("\"snaphot\""); // NON-NLS + //write view paramaters + htmlWriter.write("\n"); // NON-NLS + writeTableRow(htmlWriter, "Case", Case.getCurrentCase().getName()); // NON-NLS + writeTableRow(htmlWriter, "Time Range", zoomParams.getTimeRange().toString()); // NON-NLS + writeTableRow(htmlWriter, "Description Level of Detail", zoomParams.getDescriptionLOD().getDisplayName()); // NON-NLS + writeTableRow(htmlWriter, "Event Type Zoom Level", zoomParams.getTypeZoomLevel().getDisplayName()); // NON-NLS + writeTableRow(htmlWriter, "Filters", zoomParams.getFilter().getHTMLReportString()); // NON-NLS + //end table and html + htmlWriter.write("
\n"); // NON-NLS + htmlWriter.write("
\n\n"); // NON-NLS + } + + /** + * + * @param htmlWriter the value of htmlWriter + * @param key the value of Key + * @param value the value of value + * + * @throws IOException + */ + private static void writeTableRow(final Writer htmlWriter, final String key, final String value) throws IOException { + htmlWriter.write("" + key + ": " + value + "\n"); // NON-NLS + } + + @NbBundle.Messages({"OpenReportAction.DisplayName=Open Report", + "OpenReportAction.NoAssociatedEditorMessage=There is no associated editor for reports of this type or the associated application failed to launch.", + "OpenReportAction.MessageBoxTitle=Open Report Failure", + "OpenReportAction.NoOpenInEditorSupportMessage=This platform (operating system) does not support opening a file in an editor this way.", + "OpenReportAction.MissingReportFileMessage=The report file no longer exists.", + "OpenReportAction.ReportFileOpenPermissionDeniedMessage=Permission to open the report file was denied."}) + private class OpenReportAction extends Action { + + OpenReportAction(File reportHTMLFIle) { + super(Bundle.OpenReportAction_DisplayName()); + setEventHandler(actionEvent -> { + try { + Desktop.getDesktop().open(reportHTMLFIle); + } catch (IOException ex) { + JOptionPane.showMessageDialog(null, + Bundle.OpenReportAction_NoAssociatedEditorMessage(), + Bundle.OpenReportAction_MessageBoxTitle(), + JOptionPane.ERROR_MESSAGE); + } catch (UnsupportedOperationException ex) { + JOptionPane.showMessageDialog(null, + Bundle.OpenReportAction_NoOpenInEditorSupportMessage(), + Bundle.OpenReportAction_MessageBoxTitle(), + JOptionPane.ERROR_MESSAGE); + } catch (IllegalArgumentException ex) { + JOptionPane.showMessageDialog(null, + Bundle.OpenReportAction_MissingReportFileMessage(), + Bundle.OpenReportAction_MessageBoxTitle(), + JOptionPane.ERROR_MESSAGE); + } catch (SecurityException ex) { + JOptionPane.showMessageDialog(null, + Bundle.OpenReportAction_ReportFileOpenPermissionDeniedMessage(), + Bundle.OpenReportAction_MessageBoxTitle(), + JOptionPane.ERROR_MESSAGE); + } + }); + } + } } From 6fdfe73afdf0dc57091f8911165097c1525992c4 Mon Sep 17 00:00:00 2001 From: momo Date: Thu, 12 Nov 2015 10:38:43 -0500 Subject: [PATCH 24/24] start from offset 0 at the end --- .../src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java | 2 +- .../modules/filetypeid/FileTypeIdGlobalSettingsPanel.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java index 9b65bcb63c..84e4186975 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileType.java @@ -287,7 +287,7 @@ class FileType { boolean containedIn(final AbstractFile file) { long actualOffset = offset; if(!isRelativeToStart) - actualOffset = file.getSize() - offset; + actualOffset = file.getSize() - 1 - offset; if (file.getSize() < (actualOffset + signatureBytes.length)) { return false; /// too small, can't contain this signature } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java index 42c89f3386..410851b648 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdGlobalSettingsPanel.java @@ -627,6 +627,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane byte[] signatureBytes; if (FileType.Signature.Type.RAW == sigType) { try { + sigString = sigString.replaceAll("\\s", ""); signatureBytes = DatatypeConverter.parseHexBinary(sigString); } catch (IllegalArgumentException ex) { JOptionPane.showMessageDialog(null, @@ -646,7 +647,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane boolean isRelativeToStart = offsetRelativeToComboBox.getSelectedItem() == FileTypeIdGlobalSettingsPanel.START_OFFSET_RELATIVE_COMBO_BOX_ITEM; try { offset = Long.parseUnsignedLong(offsetTextField.getText()); - if(!isRelativeToStart && sigString.length() > offset) { + if(!isRelativeToStart && signatureBytes.length > offset+1) { JOptionPane.showMessageDialog(null, NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.length"), NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.title"),