From 8079f2ca691b2aee73d27186a2516bfa8dcc2e7b Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Tue, 28 May 2024 12:50:37 -0400 Subject: [PATCH 1/8] ImageDSP Panel Change Added bitlocker password to ImageDSP panel --- .../autopsy/casemodule/AddImageTask.java | 4 +- .../autopsy/casemodule/Bundle.properties | 2 + .../casemodule/Bundle.properties-MERGED | 2 + .../autopsy/casemodule/ImageDSProcessor.java | 5 +- .../autopsy/casemodule/ImageFilePanel.form | 82 ++++++++++++------- .../autopsy/casemodule/ImageFilePanel.java | 74 +++++++++++------ 6 files changed, 112 insertions(+), 57 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java index 310051b7f5..1bd4be83e9 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java @@ -319,8 +319,9 @@ class AddImageTask implements Runnable { String sha1; String sha256; ImageWriterSettings imageWriterSettings; + String bitlockerPassword; - ImageDetails(String deviceId, Image image, int sectorSize, String timeZone, boolean ignoreFatOrphanFiles, String md5, String sha1, String sha256, ImageWriterSettings imageWriterSettings) { + ImageDetails(String deviceId, Image image, int sectorSize, String timeZone, boolean ignoreFatOrphanFiles, String md5, String sha1, String sha256, ImageWriterSettings imageWriterSettings, String bitlockerPassword) { this.deviceId = deviceId; this.image = image; this.sectorSize = sectorSize; @@ -330,6 +331,7 @@ class AddImageTask implements Runnable { this.sha1 = sha1; this.sha256 = sha256; this.imageWriterSettings = imageWriterSettings; + this.bitlockerPassword = bitlockerPassword; } String getImagePath() { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 92b64b840b..b18fe8c6fb 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -270,3 +270,5 @@ LocalFilesPanel.timestampToIncludeLabel.text=Timestamps To Include: LocalFilesPanel.accessTimeCheckBox.text=Access Time - Can be changed when the file is opened LocalFilesPanel.timeStampToIncludeLabel.text=Timestamps To Include: LocalFilesPanel.timeStampNoteLabel.text=NOTE: Time stamps may have changed when the files were copied to the current location. +ImageFilePanel.bitlockerPasswordLabel.text=Bitlocker Password (optional): +ImageFilePanel.bitlockerPasswordTextField.text= diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED index 14465bba03..df1a068d9d 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED @@ -504,3 +504,5 @@ LocalFilesPanel.timestampToIncludeLabel.text=Timestamps To Include: LocalFilesPanel.accessTimeCheckBox.text=Access Time - Can be changed when the file is opened LocalFilesPanel.timeStampToIncludeLabel.text=Timestamps To Include: LocalFilesPanel.timeStampNoteLabel.text=NOTE: Time stamps may have changed when the files were copied to the current location. +ImageFilePanel.bitlockerPasswordLabel.text=Bitlocker Password (optional): +ImageFilePanel.bitlockerPasswordTextField.text=jTextField1 diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java index 9b174f28f7..3989577867 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java @@ -82,6 +82,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour private String sha1; private String sha256; private Host host = null; + private String bitlockerPassword; static { filtersList.add(allFilter); @@ -315,6 +316,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour if (sha256.isEmpty()) { sha256 = null; } + bitlockerPassword = configPanel.getBitlockerPassword(); } /** @@ -413,7 +415,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour return; } - AddImageTask.ImageDetails imageDetails = new AddImageTask.ImageDetails(deviceId, image, sectorSize, timeZone, ignoreFatOrphanFiles, md5, sha1, sha256, null); + AddImageTask.ImageDetails imageDetails = new AddImageTask.ImageDetails(deviceId, image, sectorSize, timeZone, ignoreFatOrphanFiles, md5, sha1, sha256, null, null); addImageTask = new AddImageTask(imageDetails, progressMonitor, new StreamingAddDataSourceCallbacks(ingestStream), @@ -449,6 +451,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour timeZone = null; ignoreFatOrphanFiles = false; host = null; + bitlockerPassword = null; configPanel.reset(); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form index 0c634afc24..2484a1f550 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form @@ -38,36 +38,39 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -95,9 +98,14 @@ - - + + + + + + + @@ -116,7 +124,7 @@ - + @@ -265,5 +273,19 @@ + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index eda7149f66..84a03da647 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java @@ -129,6 +129,10 @@ public class ImageFilePanel extends JPanel implements DocumentListener { return sha256HashTextField; } + private JTextField getBitlockerPasswordTextField() { + return bitlockerPasswordTextField; + } + private JFileChooser getChooser() { if(fileChooser == null) { fileChooser = fileChooserHelper.getChooser(); @@ -169,6 +173,8 @@ public class ImageFilePanel extends JPanel implements DocumentListener { md5HashLabel = new javax.swing.JLabel(); hashValuesLabel = new javax.swing.JLabel(); hashValuesNoteLabel = new javax.swing.JLabel(); + bitlockerPasswordLabel = new javax.swing.JLabel(); + bitlockerPasswordTextField = new javax.swing.JTextField(); setMinimumSize(new java.awt.Dimension(0, 65)); setPreferredSize(new java.awt.Dimension(403, 65)); @@ -220,6 +226,10 @@ public class ImageFilePanel extends JPanel implements DocumentListener { org.openide.awt.Mnemonics.setLocalizedText(hashValuesNoteLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.hashValuesNoteLabel.text")); // NOI18N hashValuesNoteLabel.setEnabled(false); + org.openide.awt.Mnemonics.setLocalizedText(bitlockerPasswordLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.bitlockerPasswordLabel.text")); // NOI18N + + bitlockerPasswordTextField.setText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.bitlockerPasswordTextField.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -235,30 +245,33 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .addComponent(noFatOrphansCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 262, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGap(0, 368, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addComponent(errorLabel) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addGroup(layout.createSequentialGroup() - .addComponent(timeZoneLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 455, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addComponent(sectorSizeLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(sectorSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 455, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addComponent(md5HashLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(md5HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 455, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addComponent(sha1HashLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(sha1HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 455, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addComponent(sha256HashLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(sha256HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 455, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(timeZoneLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 455, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(sectorSizeLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(sectorSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 455, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(md5HashLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(md5HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 455, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(sha1HashLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(sha1HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 455, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(sha256HashLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(sha256HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 455, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(hashValuesNoteLabel) + .addGroup(layout.createSequentialGroup() + .addComponent(bitlockerPasswordLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bitlockerPasswordTextField)) .addComponent(hashValuesLabel)) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); @@ -280,9 +293,13 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(sectorSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(sectorSizeLabel)) - .addGap(39, 39, 39) - .addComponent(hashValuesLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(bitlockerPasswordLabel) + .addComponent(bitlockerPasswordTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(hashValuesLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(md5HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(md5HashLabel)) @@ -298,7 +315,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .addComponent(hashValuesNoteLabel) .addGap(18, 18, 18) .addComponent(errorLabel) - .addContainerGap(51, Short.MAX_VALUE)) + .addContainerGap(52, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -345,6 +362,8 @@ public class ImageFilePanel extends JPanel implements DocumentListener { }//GEN-LAST:event_browseButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel bitlockerPasswordLabel; + private javax.swing.JTextField bitlockerPasswordTextField; private javax.swing.JButton browseButton; private javax.swing.JLabel errorLabel; private javax.swing.JLabel hashValuesLabel; @@ -436,6 +455,10 @@ public class ImageFilePanel extends JPanel implements DocumentListener { String getSha256() { return this.sha256HashTextField.getText(); } + + String getBitlockerPassword() { + return this.getBitlockerPasswordTextField.getText(); + } public void reset() { //reset the UI elements to default @@ -443,6 +466,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { this.md5HashTextField.setText(null); this.sha1HashTextField.setText(null); this.sha256HashTextField.setText(null); + this.bitlockerPasswordTextField.setText(null); } /** From fb79eb37ba74ce873879b72d973a4411bde2b307 Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Tue, 28 May 2024 12:53:08 -0400 Subject: [PATCH 2/8] Empty and Null Check if password is empty and set to null --- .../src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java | 3 +++ Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java index 3989577867..b586edc707 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java @@ -317,6 +317,9 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour sha256 = null; } bitlockerPassword = configPanel.getBitlockerPassword(); + if (bitlockerPassword.isEmpty()) { + bitlockerPassword = null; + } } /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index 84a03da647..dd981aaefd 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java @@ -457,7 +457,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { } String getBitlockerPassword() { - return this.getBitlockerPasswordTextField.getText(); + return this.bitlockerPasswordTextField.getText(); } public void reset() { From 471c99a66133d8f96b1613d422a5a95d33a66f0d Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Fri, 13 Dec 2024 10:40:18 -0500 Subject: [PATCH 3/8] Initial Bit locker support Initial Bitlocker support --- .../autopsy/casemodule/AddImageTask.java | 6 +-- .../autopsy/casemodule/Bundle.properties | 4 +- .../casemodule/Bundle.properties-MERGED | 6 +-- .../autopsy/casemodule/ImageDSProcessor.java | 50 +++++++++++-------- .../autopsy/casemodule/ImageFilePanel.form | 18 +++---- .../autopsy/casemodule/ImageFilePanel.java | 32 ++++++------ .../casemodule/LocalDiskDSProcessor.java | 7 +-- .../autopsy/coreutils/DataSourceUtils.java | 23 +++++++++ .../dsp/AddMultipleImagesTask.java | 2 +- .../PortableCaseReportModule.java | 2 +- 10 files changed, 92 insertions(+), 58 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java index 1bd4be83e9..599bf56110 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java @@ -319,9 +319,9 @@ class AddImageTask implements Runnable { String sha1; String sha256; ImageWriterSettings imageWriterSettings; - String bitlockerPassword; + String password; - ImageDetails(String deviceId, Image image, int sectorSize, String timeZone, boolean ignoreFatOrphanFiles, String md5, String sha1, String sha256, ImageWriterSettings imageWriterSettings, String bitlockerPassword) { + ImageDetails(String deviceId, Image image, int sectorSize, String timeZone, boolean ignoreFatOrphanFiles, String md5, String sha1, String sha256, ImageWriterSettings imageWriterSettings, String password) { this.deviceId = deviceId; this.image = image; this.sectorSize = sectorSize; @@ -331,7 +331,7 @@ class AddImageTask implements Runnable { this.sha1 = sha1; this.sha256 = sha256; this.imageWriterSettings = imageWriterSettings; - this.bitlockerPassword = bitlockerPassword; + this.password = password; } String getImagePath() { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index b18fe8c6fb..c53c3085a9 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -270,5 +270,5 @@ LocalFilesPanel.timestampToIncludeLabel.text=Timestamps To Include: LocalFilesPanel.accessTimeCheckBox.text=Access Time - Can be changed when the file is opened LocalFilesPanel.timeStampToIncludeLabel.text=Timestamps To Include: LocalFilesPanel.timeStampNoteLabel.text=NOTE: Time stamps may have changed when the files were copied to the current location. -ImageFilePanel.bitlockerPasswordLabel.text=Bitlocker Password (optional): -ImageFilePanel.bitlockerPasswordTextField.text= +ImageFilePanel.passwordLabel.text=Bitlocker Password (optional): +ImageFilePanel.passwordTextField.text= diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED index df1a068d9d..3e2e6c4199 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED @@ -151,7 +151,7 @@ GeneralFilter.encaseImageDesc.text=Encase Images (*.e01) GeneralFilter.executableDesc.text=Executables (*.exe) GeneralFilter.graphicImageDesc.text=Images (*.png, *.jpg, *.jpeg, *.gif, *.bmp) GeneralFilter.rawImageDesc.text=Raw Images (*.img, *.dd, *.001, *.aa, *.raw, *.bin) -GeneralFilter.virtualMachineImageDesc.text=Virtual Machines (*.vmdk, *.vhd) +GeneralFilter.virtualMachineImageDesc.text=Virtual Machines (*.vmdk, *.vhd, *.vhdx) ImageFilePanel.000.confirmationMessage=The selected file has extenson .001 but there is a .000 file in the sequence of raw images.\nShould the .000 file be used as the start, instead of the selected .001 file?\n ImageFilePanel.moduleErr=Module Error ImageFilePanel.moduleErr.msg=A module caused an error listening to ImageFilePanel updates. See log to determine which module. Some data could be incomplete.\n @@ -504,5 +504,5 @@ LocalFilesPanel.timestampToIncludeLabel.text=Timestamps To Include: LocalFilesPanel.accessTimeCheckBox.text=Access Time - Can be changed when the file is opened LocalFilesPanel.timeStampToIncludeLabel.text=Timestamps To Include: LocalFilesPanel.timeStampNoteLabel.text=NOTE: Time stamps may have changed when the files were copied to the current location. -ImageFilePanel.bitlockerPasswordLabel.text=Bitlocker Password (optional): -ImageFilePanel.bitlockerPasswordTextField.text=jTextField1 +ImageFilePanel.passwordLabel.text=Bitlocker Password (optional): +ImageFilePanel.passwordTextField.text= diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java index b586edc707..0b219c3d4d 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java @@ -82,7 +82,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour private String sha1; private String sha256; private Host host = null; - private String bitlockerPassword; + private String password; static { filtersList.add(allFilter); @@ -207,7 +207,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour this.host = host; try { image = SleuthkitJNI.addImageToDatabase(Case.getCurrentCase().getSleuthkitCase(), - new String[]{imagePath}, sectorSize, timeZone, md5, sha1, sha256, deviceId, this.host); + new String[]{imagePath}, sectorSize, timeZone, md5, sha1, sha256, deviceId, this.host, this.password); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error adding data source with path " + imagePath + " to database", ex); final List errors = new ArrayList<>(); @@ -216,7 +216,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour return; } - doAddImageProcess(deviceId, imagePath, sectorSize, timeZone, ignoreFatOrphanFiles, md5, sha1, sha256, progressMonitor, callback); + doAddImageProcess(deviceId, imagePath, sectorSize, timeZone, ignoreFatOrphanFiles, md5, sha1, sha256, this.password, progressMonitor, callback); } /** @@ -271,7 +271,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour // Set up the data source before creating the ingest stream try { image = SleuthkitJNI.addImageToDatabase(Case.getCurrentCase().getSleuthkitCase(), - new String[]{imagePath}, sectorSize, timeZone, md5, sha1, sha256, deviceId, this.host); + new String[]{imagePath}, sectorSize, timeZone, md5, sha1, sha256, deviceId, this.host, this.password); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error adding data source with path " + imagePath + " to database", ex); final List errors = new ArrayList<>(); @@ -291,7 +291,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour ingestStream = new DefaultIngestStream(); } - doAddImageProcess(deviceId, imagePath, sectorSize, timeZone, ignoreFatOrphanFiles, md5, sha1, sha256, progress, callBack); + doAddImageProcess(deviceId, imagePath, sectorSize, timeZone, ignoreFatOrphanFiles, md5, sha1, sha256, this.password, progress, callBack); } /** @@ -316,9 +316,9 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour if (sha256.isEmpty()) { sha256 = null; } - bitlockerPassword = configPanel.getBitlockerPassword(); - if (bitlockerPassword.isEmpty()) { - bitlockerPassword = null; + password = configPanel.getPassword(); + if (password.isEmpty()) { + password = null; } } @@ -366,7 +366,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour return; } - doAddImageProcess(deviceId, imagePath, 0, timeZone, ignoreFatOrphanFiles, null, null, null, progressMonitor, callback); + doAddImageProcess(deviceId, imagePath, 0, timeZone, ignoreFatOrphanFiles, null, null, null, this.password, progressMonitor, callback); } /** @@ -398,7 +398,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour * during processing. * @param callback Callback to call when processing is done. */ - private void doAddImageProcess(String deviceId, String imagePath, int sectorSize, String timeZone, boolean ignoreFatOrphanFiles, String md5, String sha1, String sha256, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { + private void doAddImageProcess(String deviceId, String imagePath, int sectorSize, String timeZone, boolean ignoreFatOrphanFiles, String md5, String sha1, String sha256, String password, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { // If the data source or ingest stream haven't been initialized, stop processing if (ingestStream == null) { @@ -418,7 +418,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour return; } - AddImageTask.ImageDetails imageDetails = new AddImageTask.ImageDetails(deviceId, image, sectorSize, timeZone, ignoreFatOrphanFiles, md5, sha1, sha256, null, null); + AddImageTask.ImageDetails imageDetails = new AddImageTask.ImageDetails(deviceId, image, sectorSize, timeZone, ignoreFatOrphanFiles, md5, sha1, sha256, null, password); addImageTask = new AddImageTask(imageDetails, progressMonitor, new StreamingAddDataSourceCallbacks(ingestStream), @@ -454,7 +454,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour timeZone = null; ignoreFatOrphanFiles = false; host = null; - bitlockerPassword = null; + password = null; configPanel.reset(); } @@ -476,10 +476,20 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour } try { - // verify that the image has a file system that TSK can process - if (!DataSourceUtils.imageHasFileSystem(dataSourcePath)) { - // image does not have a file system that TSK can process - return 0; + if (password == null) { + + // verify that the image has a file system that TSK can process + if (!DataSourceUtils.imageHasFileSystem(dataSourcePath)) { + // image does not have a file system that TSK can process + return 0; + } + } else { + // verify that the image has a file system that TSK can process + if (!DataSourceUtils.imageHasFileSystem(dataSourcePath, password)) { + // image does not have a file system that TSK can process + return 0; + } + } } catch (Exception ex) { throw new AutoIngestDataSourceProcessorException("Exception inside canProcess() method", ex); @@ -507,7 +517,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour ingestStream = new DefaultIngestStream(); try { image = SleuthkitJNI.addImageToDatabase(Case.getCurrentCase().getSleuthkitCase(), - new String[]{imagePath}, sectorSize, timeZone, "", "", "", deviceId, host); + new String[]{imagePath}, sectorSize, timeZone, "", "", "", deviceId, host, this.password); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error adding data source with path " + imagePath + " to database", ex); final List errors = new ArrayList<>(); @@ -516,7 +526,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour return; } - doAddImageProcess(deviceId, dataSourcePath.toString(), sectorSize, timeZone, ignoreFatOrphanFiles, null, null, null, progressMonitor, callBack); + doAddImageProcess(deviceId, dataSourcePath.toString(), sectorSize, timeZone, ignoreFatOrphanFiles, null, null, null, null, progressMonitor, callBack); } @Override @@ -537,7 +547,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour // Set up the data source before creating the ingest stream try { image = SleuthkitJNI.addImageToDatabase(Case.getCurrentCase().getSleuthkitCase(), - new String[]{imagePath}, sectorSize, timeZone, md5, sha1, sha256, deviceId, host); + new String[]{imagePath}, sectorSize, timeZone, md5, sha1, sha256, deviceId, host, this.password); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error adding data source with path " + imagePath + " to database", ex); final List errors = new ArrayList<>(); @@ -557,7 +567,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour return null; } - doAddImageProcess(deviceId, dataSourcePath.toString(), sectorSize, timeZone, ignoreFatOrphanFiles, null, null, null, progressMonitor, callBack); + doAddImageProcess(deviceId, dataSourcePath.toString(), sectorSize, timeZone, ignoreFatOrphanFiles, null, null, null, null, progressMonitor, callBack); return ingestStream; } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form index 2484a1f550..2fa29a1a8f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form @@ -67,9 +67,9 @@ - + - + @@ -100,8 +100,8 @@ - - + + @@ -124,7 +124,7 @@ - + @@ -273,17 +273,17 @@ - + - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index dd981aaefd..7be2a01c95 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java @@ -129,8 +129,8 @@ public class ImageFilePanel extends JPanel implements DocumentListener { return sha256HashTextField; } - private JTextField getBitlockerPasswordTextField() { - return bitlockerPasswordTextField; + private JTextField getPasswordTextField() { + return passwordTextField; } private JFileChooser getChooser() { @@ -173,8 +173,8 @@ public class ImageFilePanel extends JPanel implements DocumentListener { md5HashLabel = new javax.swing.JLabel(); hashValuesLabel = new javax.swing.JLabel(); hashValuesNoteLabel = new javax.swing.JLabel(); - bitlockerPasswordLabel = new javax.swing.JLabel(); - bitlockerPasswordTextField = new javax.swing.JTextField(); + passwordLabel = new javax.swing.JLabel(); + passwordTextField = new javax.swing.JTextField(); setMinimumSize(new java.awt.Dimension(0, 65)); setPreferredSize(new java.awt.Dimension(403, 65)); @@ -226,9 +226,9 @@ public class ImageFilePanel extends JPanel implements DocumentListener { org.openide.awt.Mnemonics.setLocalizedText(hashValuesNoteLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.hashValuesNoteLabel.text")); // NOI18N hashValuesNoteLabel.setEnabled(false); - org.openide.awt.Mnemonics.setLocalizedText(bitlockerPasswordLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.bitlockerPasswordLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(passwordLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.passwordLabel.text")); // NOI18N - bitlockerPasswordTextField.setText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.bitlockerPasswordTextField.text")); // NOI18N + passwordTextField.setText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.passwordTextField.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -269,9 +269,9 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .addComponent(sha256HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 455, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(hashValuesNoteLabel) .addGroup(layout.createSequentialGroup() - .addComponent(bitlockerPasswordLabel) + .addComponent(passwordLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bitlockerPasswordTextField)) + .addComponent(passwordTextField)) .addComponent(hashValuesLabel)) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); @@ -295,8 +295,8 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .addComponent(sectorSizeLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(bitlockerPasswordLabel) - .addComponent(bitlockerPasswordTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(passwordLabel) + .addComponent(passwordTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(hashValuesLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) @@ -315,7 +315,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .addComponent(hashValuesNoteLabel) .addGap(18, 18, 18) .addComponent(errorLabel) - .addContainerGap(52, Short.MAX_VALUE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -362,8 +362,6 @@ public class ImageFilePanel extends JPanel implements DocumentListener { }//GEN-LAST:event_browseButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel bitlockerPasswordLabel; - private javax.swing.JTextField bitlockerPasswordTextField; private javax.swing.JButton browseButton; private javax.swing.JLabel errorLabel; private javax.swing.JLabel hashValuesLabel; @@ -371,6 +369,8 @@ public class ImageFilePanel extends JPanel implements DocumentListener { private javax.swing.JLabel md5HashLabel; private javax.swing.JTextField md5HashTextField; private javax.swing.JCheckBox noFatOrphansCheckbox; + private javax.swing.JLabel passwordLabel; + private javax.swing.JTextField passwordTextField; private javax.swing.JLabel pathLabel; private javax.swing.JTextField pathTextField; private javax.swing.JComboBox sectorSizeComboBox; @@ -456,8 +456,8 @@ public class ImageFilePanel extends JPanel implements DocumentListener { return this.sha256HashTextField.getText(); } - String getBitlockerPassword() { - return this.bitlockerPasswordTextField.getText(); + String getPassword() { + return this.passwordTextField.getText(); } public void reset() { @@ -466,7 +466,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { this.md5HashTextField.setText(null); this.sha1HashTextField.setText(null); this.sha256HashTextField.setText(null); - this.bitlockerPasswordTextField.setText(null); + this.passwordTextField.setText(null); } /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java index c659727d74..5843220af4 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java @@ -59,6 +59,7 @@ public class LocalDiskDSProcessor implements DataSourceProcessor { private Host host; private ImageWriterSettings imageWriterSettings; private boolean ignoreFatOrphanFiles; + private String password; /** * Constructs a local drive data source processor that implements the @@ -172,7 +173,7 @@ public class LocalDiskDSProcessor implements DataSourceProcessor { try { image = SleuthkitJNI.addImageToDatabase(Case.getCurrentCase().getSleuthkitCase(), new String[]{drivePath}, sectorSize, - timeZone, null, null, null, deviceId, this.host); + timeZone, null, null, null, deviceId, this.host, this.password); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error adding local disk with path " + drivePath + " to database", ex); final List errors = new ArrayList<>(); @@ -182,7 +183,7 @@ public class LocalDiskDSProcessor implements DataSourceProcessor { } addDiskTask = new AddImageTask( - new AddImageTask.ImageDetails(deviceId, image, sectorSize, timeZone, ignoreFatOrphanFiles, null, null, null, imageWriterSettings), + new AddImageTask.ImageDetails(deviceId, image, sectorSize, timeZone, ignoreFatOrphanFiles, null, null, null, imageWriterSettings, password), progressMonitor, new StreamingAddDataSourceCallbacks(new DefaultIngestStream()), new StreamingAddImageTaskCallback(new DefaultIngestStream(), callback)); @@ -250,7 +251,7 @@ public class LocalDiskDSProcessor implements DataSourceProcessor { return; } - addDiskTask = new AddImageTask(new AddImageTask.ImageDetails(deviceId, image, sectorSize, timeZone, ignoreFatOrphanFiles, null, null, null, imageWriterSettings), + addDiskTask = new AddImageTask(new AddImageTask.ImageDetails(deviceId, image, sectorSize, timeZone, ignoreFatOrphanFiles, null, null, null, imageWriterSettings, password), progressMonitor, new StreamingAddDataSourceCallbacks(new DefaultIngestStream()), new StreamingAddImageTaskCallback(new DefaultIngestStream(), callback)); diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/DataSourceUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/DataSourceUtils.java index 61191125bd..707c6b6645 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/DataSourceUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/DataSourceUtils.java @@ -21,6 +21,8 @@ package org.sleuthkit.autopsy.coreutils; import org.sleuthkit.datamodel.SleuthkitJNI; import java.io.IOException; import java.nio.file.Path; +import java.text.MessageFormat; +import org.apache.commons.lang3.StringUtils; /** * Utility methods for working with data sources. @@ -41,4 +43,25 @@ public class DataSourceUtils { public static boolean imageHasFileSystem(Path dataSourcePath) throws IOException { return SleuthkitJNI.isImageSupported(dataSourcePath.toString()); } + + public static boolean imageHasFileSystem(Path dataSourcePath, String password) throws IOException { + try { +// LOGGER.info("Testing if disk image {} can be opened", hostPath); + SleuthkitJNI.TestOpenImageResult openImageResult = SleuthkitJNI.testOpenImage(dataSourcePath.toString(), password); + if (!openImageResult.wasSuccessful()) { + String message = MessageFormat.format("An error occurred while opening {0}: {1}", + dataSourcePath.toString(), + openImageResult == null || StringUtils.isBlank(openImageResult.getMessage()) + ? "" + : openImageResult.getMessage()); + return false; + } + } catch (Throwable ex) { + String message = "An error occurred while opening " + dataSourcePath.toString(); + return false; + } + return SleuthkitJNI.isImageSupported(dataSourcePath.toString()); + + } } + diff --git a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/AddMultipleImagesTask.java b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/AddMultipleImagesTask.java index 95484341c7..4cf0503679 100644 --- a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/AddMultipleImagesTask.java +++ b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/AddMultipleImagesTask.java @@ -128,7 +128,7 @@ class AddMultipleImagesTask implements Runnable { for (String imageFilePath : imageFilePaths) { try { currentImage = SleuthkitJNI.addImageToDatabase(currentCase.getSleuthkitCase(), new String[]{imageFilePath}, - 0, timeZone, "", "", "", deviceId, host); + 0, timeZone, "", "", "", deviceId, host, null); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error adding image " + imageFilePath + " to database", ex); errorMessages.add(Bundle.AddMultipleImagesTask_imageError(imageFilePath)); diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java index 860739f91b..137850ee17 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java @@ -1230,7 +1230,7 @@ public class PortableCaseReportModule implements ReportModule { if (content instanceof Image) { Image image = (Image) content; newContent = portableSkCase.addImage(image.getType(), image.getSsize(), image.getSize(), image.getName(), - new ArrayList<>(), image.getTimeZone(), md5, sha1, sha256, image.getDeviceId(), newHost, trans); + new ArrayList<>(), image.getTimeZone(), md5, sha1, sha256, image.getDeviceId(), newHost, null, trans); } else if (content instanceof VolumeSystem) { VolumeSystem vs = (VolumeSystem) content; newContent = portableSkCase.addVolumeSystem(parentId, vs.getType(), vs.getOffset(), vs.getBlockSize(), trans); From 56f7ad5578505d5b6d78a265e25e9dfa577c3509 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 16 Dec 2024 15:03:43 -0500 Subject: [PATCH 4/8] initial work in integrating bitlocker --- .../autopsy/casemodule/AddImageTask.java | 2 +- .../casemodule/Bundle.properties-MERGED | 4 + .../autopsy/casemodule/ImageDSProcessor.java | 9 +- .../autopsy/casemodule/ImageFilePanel.form | 239 ++++++----- .../autopsy/casemodule/ImageFilePanel.java | 390 +++++++++++++----- .../casemodule/LocalDiskDSProcessor.java | 2 +- .../dsp/AddMultipleImagesTask.java | 2 +- .../PortableCaseReportModule.java | 2 +- 8 files changed, 420 insertions(+), 230 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java index 599bf56110..793d90bae3 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java @@ -107,7 +107,7 @@ class AddImageTask implements Runnable { try { synchronized (tskAddImageProcessLock) { if (!tskAddImageProcessStopped) { - tskAddImageProcess = currentCase.getSleuthkitCase().makeAddImageProcess(imageDetails.timeZone, true, imageDetails.ignoreFatOrphanFiles, imageWriterPath); + tskAddImageProcess = currentCase.getSleuthkitCase().makeAddImageProcess(imageDetails.timeZone, true, imageDetails.ignoreFatOrphanFiles, imageWriterPath, imageDetails.password); } else { return; } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED index 3e2e6c4199..9e7e2d7e81 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED @@ -159,6 +159,10 @@ ImageFilePanel.validatePanel.dataSourceOnCDriveError=Warning: Path to multi-user ImageFilePanel.validatePanel.invalidMD5=Invalid MD5 hash ImageFilePanel.validatePanel.invalidSHA1=Invalid SHA1 hash ImageFilePanel.validatePanel.invalidSHA256=Invalid SHA256 hash +# {0} - imageOpenError +ImageFilePanel_validatePanel_imageOpenError=

An error occurred while opening the image:{0}

+ImageFilePanel_validatePanel_unknownError=

An unknown error occurred while attempting to validate the image

+ImageFilePanel_validatePanel_unknownErrorMsg= IngestJobInfoPanel.IngestJobTableModel.EndTime.header=End Time IngestJobInfoPanel.IngestJobTableModel.IngestStatus.header=Ingest Status IngestJobInfoPanel.IngestJobTableModel.StartTime.header=Start Time diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java index 0b219c3d4d..c1fef28484 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java @@ -207,7 +207,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour this.host = host; try { image = SleuthkitJNI.addImageToDatabase(Case.getCurrentCase().getSleuthkitCase(), - new String[]{imagePath}, sectorSize, timeZone, md5, sha1, sha256, deviceId, this.host, this.password); + new String[]{imagePath}, sectorSize, timeZone, md5, sha1, sha256, deviceId, this.host); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error adding data source with path " + imagePath + " to database", ex); final List errors = new ArrayList<>(); @@ -271,7 +271,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour // Set up the data source before creating the ingest stream try { image = SleuthkitJNI.addImageToDatabase(Case.getCurrentCase().getSleuthkitCase(), - new String[]{imagePath}, sectorSize, timeZone, md5, sha1, sha256, deviceId, this.host, this.password); + new String[]{imagePath}, sectorSize, timeZone, md5, sha1, sha256, deviceId, this.host); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error adding data source with path " + imagePath + " to database", ex); final List errors = new ArrayList<>(); @@ -394,6 +394,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour * @param md5 The MD5 hash of the image, may be null. * @param sha1 The SHA-1 hash of the image, may be null. * @param sha256 The SHA-256 hash of the image, may be null. + * @param password Password for image decryption. May be null. * @param progressMonitor Progress monitor for reporting progress * during processing. * @param callback Callback to call when processing is done. @@ -517,7 +518,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour ingestStream = new DefaultIngestStream(); try { image = SleuthkitJNI.addImageToDatabase(Case.getCurrentCase().getSleuthkitCase(), - new String[]{imagePath}, sectorSize, timeZone, "", "", "", deviceId, host, this.password); + new String[]{imagePath}, sectorSize, timeZone, "", "", "", deviceId, host); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error adding data source with path " + imagePath + " to database", ex); final List errors = new ArrayList<>(); @@ -547,7 +548,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour // Set up the data source before creating the ingest stream try { image = SleuthkitJNI.addImageToDatabase(Case.getCurrentCase().getSleuthkitCase(), - new String[]{imagePath}, sectorSize, timeZone, md5, sha1, sha256, deviceId, host, this.password); + new String[]{imagePath}, sectorSize, timeZone, md5, sha1, sha256, deviceId, host); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error adding data source with path " + imagePath + " to database", ex); final List errors = new ArrayList<>(); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form index 2fa29a1a8f..c46749306b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form @@ -19,116 +19,10 @@ + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -136,6 +30,11 @@ + + + + + @@ -146,6 +45,11 @@ + + + + + @@ -153,6 +57,11 @@ + + + + + @@ -160,6 +69,11 @@ + + + + + @@ -171,6 +85,11 @@ + + + + + @@ -181,6 +100,11 @@ + + + + + @@ -190,7 +114,22 @@ + + + + + + + + + + + + + + + @@ -198,6 +137,11 @@ + + + + + @@ -208,6 +152,11 @@ + + + + + @@ -216,6 +165,11 @@ + + + + + @@ -224,6 +178,11 @@ + + + + + @@ -232,6 +191,11 @@ + + + + + @@ -240,6 +204,11 @@ + + + + + @@ -248,6 +217,11 @@ + + + + + @@ -256,6 +230,11 @@ + + + + + @@ -264,6 +243,11 @@ + + + + + @@ -272,6 +256,11 @@ + + + + + @@ -279,6 +268,11 @@ + + + + + @@ -286,6 +280,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index 7be2a01c95..7cf1f85183 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java @@ -18,9 +18,14 @@ */ package org.sleuthkit.autopsy.casemodule; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.io.File; import java.util.Calendar; import java.util.List; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.JPanel; @@ -32,11 +37,14 @@ import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.DriveUtils; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PathValidator; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; import org.sleuthkit.datamodel.HashUtility; +import org.sleuthkit.datamodel.SleuthkitJNI; +import org.sleuthkit.datamodel.SleuthkitJNI.TestOpenImageResult; /** * Panel for adding an image file such as .img, .E0x, .00x, etc. Allows the user @@ -44,8 +52,10 @@ import org.sleuthkit.datamodel.HashUtility; * files in FAT32. */ @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives -public class ImageFilePanel extends JPanel implements DocumentListener { +public class ImageFilePanel extends JPanel { + private static final Logger logger = Logger.getLogger(AddImageTask.class.getName()); + private static final long serialVersionUID = 1L; private static final String PROP_LASTIMAGE_PATH = "LBL_LastImage_PATH"; //NON-NLS private static final String[] SECTOR_SIZE_CHOICES = {"Auto Detect", "512", "1024", "2048", "4096"}; @@ -53,6 +63,11 @@ public class ImageFilePanel extends JPanel implements DocumentListener { private JFileChooser fileChooser; private final String contextName; private final List fileChooserFilters; + + private static int VALIDATE_TIMEOUT_MILLIS = 1500; + static ScheduledThreadPoolExecutor delayedValidationService = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("ImageFilePanel delayed validation").build()); + + private Future validateAction = null; /** * Creates new form ImageFilePanel @@ -105,11 +120,17 @@ public class ImageFilePanel extends JPanel implements DocumentListener { */ public static synchronized ImageFilePanel createInstance(String context, List fileChooserFilters) { ImageFilePanel instance = new ImageFilePanel(context, fileChooserFilters); + DocumentListener delayedValidationListener = instance.new DelayedValidationDocListener(); + // post-constructor initialization of listener support without leaking references of uninitialized objects - instance.getPathTextField().getDocument().addDocumentListener(instance); - instance.getMd5TextFieldField().getDocument().addDocumentListener(instance); - instance.getSha1TextField().getDocument().addDocumentListener(instance); - instance.getSha256TextField().getDocument().addDocumentListener(instance); + for (JTextField textField: List.of( + instance.getPathTextField(), + instance.getMd5TextFieldField(), + instance.getSha1TextField(), + instance.getSha256TextField(), + instance.getPasswordTextField())) { + textField.getDocument().addDocumentListener(delayedValidationListener); + } return instance; } @@ -155,6 +176,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { */ // //GEN-BEGIN:initComponents private void initComponents() { + java.awt.GridBagConstraints gridBagConstraints; pathLabel = new javax.swing.JLabel(); browseButton = new javax.swing.JButton(); @@ -175,11 +197,22 @@ public class ImageFilePanel extends JPanel implements DocumentListener { hashValuesNoteLabel = new javax.swing.JLabel(); passwordLabel = new javax.swing.JLabel(); passwordTextField = new javax.swing.JTextField(); + javax.swing.JPanel spacer = new javax.swing.JPanel(); setMinimumSize(new java.awt.Dimension(0, 65)); setPreferredSize(new java.awt.Dimension(403, 65)); + setLayout(new java.awt.GridBagLayout()); org.openide.awt.Mnemonics.setLocalizedText(pathLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.pathLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.gridwidth = 3; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5); + add(pathLabel, gridBagConstraints); org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.browseButton.text")); // NOI18N browseButton.addActionListener(new java.awt.event.ActionListener() { @@ -187,136 +220,211 @@ public class ImageFilePanel extends JPanel implements DocumentListener { browseButtonActionPerformed(evt); } }); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 2; + gridBagConstraints.gridy = 1; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5); + add(browseButton, gridBagConstraints); pathTextField.setText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.pathTextField.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 1; + gridBagConstraints.gridwidth = 2; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5); + add(pathTextField, gridBagConstraints); org.openide.awt.Mnemonics.setLocalizedText(timeZoneLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.timeZoneLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 3; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5); + add(timeZoneLabel, gridBagConstraints); timeZoneComboBox.setMaximumRowCount(30); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 3; + gridBagConstraints.gridwidth = 2; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5); + add(timeZoneComboBox, gridBagConstraints); org.openide.awt.Mnemonics.setLocalizedText(noFatOrphansCheckbox, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.noFatOrphansCheckbox.text")); // NOI18N noFatOrphansCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.noFatOrphansCheckbox.toolTipText")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 2; + gridBagConstraints.gridwidth = 3; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5); + add(noFatOrphansCheckbox, gridBagConstraints); errorLabel.setForeground(new java.awt.Color(255, 0, 0)); org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.errorLabel.text")); // NOI18N + errorLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP); + errorLabel.setMaximumSize(new java.awt.Dimension(500, 60)); + errorLabel.setMinimumSize(new java.awt.Dimension(200, 20)); + errorLabel.setPreferredSize(new java.awt.Dimension(200, 60)); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 11; + gridBagConstraints.gridwidth = 3; + gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5); + add(errorLabel, gridBagConstraints); org.openide.awt.Mnemonics.setLocalizedText(sectorSizeLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.sectorSizeLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 4; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5); + add(sectorSizeLabel, gridBagConstraints); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 4; + gridBagConstraints.gridwidth = 2; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5); + add(sectorSizeComboBox, gridBagConstraints); org.openide.awt.Mnemonics.setLocalizedText(sha256HashLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.sha256HashLabel.text")); // NOI18N sha256HashLabel.setEnabled(false); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 9; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5); + add(sha256HashLabel, gridBagConstraints); sha256HashTextField.setText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.sha256HashTextField.text")); // NOI18N sha256HashTextField.setEnabled(false); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 9; + gridBagConstraints.gridwidth = 2; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5); + add(sha256HashTextField, gridBagConstraints); sha1HashTextField.setText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.sha1HashTextField.text")); // NOI18N sha1HashTextField.setEnabled(false); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 8; + gridBagConstraints.gridwidth = 2; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5); + add(sha1HashTextField, gridBagConstraints); md5HashTextField.setText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.md5HashTextField.text")); // NOI18N md5HashTextField.setEnabled(false); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 7; + gridBagConstraints.gridwidth = 2; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5); + add(md5HashTextField, gridBagConstraints); org.openide.awt.Mnemonics.setLocalizedText(sha1HashLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.sha1HashLabel.text")); // NOI18N sha1HashLabel.setEnabled(false); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 8; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5); + add(sha1HashLabel, gridBagConstraints); org.openide.awt.Mnemonics.setLocalizedText(md5HashLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.md5HashLabel.text")); // NOI18N md5HashLabel.setEnabled(false); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 7; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5); + add(md5HashLabel, gridBagConstraints); org.openide.awt.Mnemonics.setLocalizedText(hashValuesLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.hashValuesLabel.text")); // NOI18N hashValuesLabel.setEnabled(false); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 6; + gridBagConstraints.gridwidth = 3; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5); + add(hashValuesLabel, gridBagConstraints); org.openide.awt.Mnemonics.setLocalizedText(hashValuesNoteLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.hashValuesNoteLabel.text")); // NOI18N hashValuesNoteLabel.setEnabled(false); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 10; + gridBagConstraints.gridwidth = 3; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5); + add(hashValuesNoteLabel, gridBagConstraints); org.openide.awt.Mnemonics.setLocalizedText(passwordLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.passwordLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 5; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5); + add(passwordLabel, gridBagConstraints); passwordTextField.setText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.passwordTextField.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 5; + gridBagConstraints.gridwidth = 2; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5); + add(passwordTextField, gridBagConstraints); - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(pathTextField) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(browseButton) - .addGap(2, 2, 2)) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(pathLabel) - .addComponent(noFatOrphansCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 262, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(0, 368, Short.MAX_VALUE)) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(errorLabel) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(timeZoneLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 455, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(sectorSizeLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(sectorSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 455, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(md5HashLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(md5HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 455, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(sha1HashLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(sha1HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 455, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(sha256HashLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(sha256HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 455, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(hashValuesNoteLabel) - .addGroup(layout.createSequentialGroup() - .addComponent(passwordLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(passwordTextField)) - .addComponent(hashValuesLabel)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + javax.swing.GroupLayout spacerLayout = new javax.swing.GroupLayout(spacer); + spacer.setLayout(spacerLayout); + spacerLayout.setHorizontalGroup( + spacerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 0, Short.MAX_VALUE) ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(pathLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(browseButton) - .addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(noFatOrphansCheckbox) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(timeZoneLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(sectorSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(sectorSizeLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(passwordLabel) - .addComponent(passwordTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(hashValuesLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(md5HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(md5HashLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(sha1HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(sha1HashLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(sha256HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(sha256HashLabel)) - .addGap(18, 18, 18) - .addComponent(hashValuesNoteLabel) - .addGap(18, 18, 18) - .addComponent(errorLabel) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + spacerLayout.setVerticalGroup( + spacerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 0, Short.MAX_VALUE) ); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 12; + gridBagConstraints.weighty = 1.0; + add(spacer, gridBagConstraints); }// //GEN-END:initComponents @NbBundle.Messages({"ImageFilePanel.000.confirmationMessage=The selected file" @@ -478,7 +586,12 @@ public class ImageFilePanel extends JPanel implements DocumentListener { "ImageFilePanel.validatePanel.dataSourceOnCDriveError=Warning: Path to multi-user data source is on \"C:\" drive", "ImageFilePanel.validatePanel.invalidMD5=Invalid MD5 hash", "ImageFilePanel.validatePanel.invalidSHA1=Invalid SHA1 hash", - "ImageFilePanel.validatePanel.invalidSHA256=Invalid SHA256 hash",}) + "ImageFilePanel.validatePanel.invalidSHA256=Invalid SHA256 hash", + "# {0} - imageOpenError", + "ImageFilePanel_validatePanel_imageOpenError=

An error occurred while opening the image:{0}

", + "ImageFilePanel_validatePanel_unknownErrorMsg=", + "ImageFilePanel_validatePanel_unknownError=

An unknown error occurred while attempting to validate the image

" + }) public boolean validatePanel() { errorLabel.setVisible(false); @@ -488,31 +601,59 @@ public class ImageFilePanel extends JPanel implements DocumentListener { } if (!StringUtils.isBlank(getMd5()) && !HashUtility.isValidMd5Hash(getMd5())) { - errorLabel.setVisible(true); - errorLabel.setText(Bundle.ImageFilePanel_validatePanel_invalidMD5()); + showError(Bundle.ImageFilePanel_validatePanel_invalidMD5()); return false; } if (!StringUtils.isBlank(getSha1()) && !HashUtility.isValidSha1Hash(getSha1())) { - errorLabel.setVisible(true); - errorLabel.setText(Bundle.ImageFilePanel_validatePanel_invalidSHA1()); + showError(Bundle.ImageFilePanel_validatePanel_invalidSHA1()); return false; } if (!StringUtils.isBlank(getSha256()) && !HashUtility.isValidSha256Hash(getSha256())) { - errorLabel.setVisible(true); - errorLabel.setText(Bundle.ImageFilePanel_validatePanel_invalidSHA256()); + showError(Bundle.ImageFilePanel_validatePanel_invalidSHA256()); return false; } if (!PathValidator.isValidForCaseType(path, Case.getCurrentCase().getCaseType())) { - errorLabel.setVisible(true); - errorLabel.setText(Bundle.ImageFilePanel_validatePanel_dataSourceOnCDriveError()); + showError(Bundle.ImageFilePanel_validatePanel_dataSourceOnCDriveError()); + } + + try { + String password = this.getPassword(); + TestOpenImageResult testResult = SleuthkitJNI.testOpenImage(path, password); + if (!testResult.wasSuccessful()) { + showError(Bundle.ImageFilePanel_validatePanel_imageOpenError( + StringUtils.defaultIfBlank( + testResult.getMessage(), + Bundle.ImageFilePanel_validatePanel_unknownErrorMsg()))); + return false; + } + } catch (Throwable t) { + logger.log(Level.SEVERE, "An unknown error occurred test opening image: " + path, t); + showError(Bundle.ImageFilePanel_validatePanel_unknownError()); + return false; } return true; } + /** + * Show an error message if error message is non-empty. Otherwise, hide + * error message. + * + * @param errorMessage The error message to show. + */ + private void showError(String errorMessage) { + if (StringUtils.isNotBlank(errorMessage)) { + errorLabel.setVisible(true); + errorLabel.setText(errorMessage); + } else { + errorLabel.setVisible(false); + errorLabel.setText(""); + } + } + private boolean isImagePathValid() { String path = getContentPaths(); @@ -538,21 +679,6 @@ public class ImageFilePanel extends JPanel implements DocumentListener { } } - @Override - public void insertUpdate(DocumentEvent e) { - updateHelper(); - } - - @Override - public void removeUpdate(DocumentEvent e) { - updateHelper(); - } - - @Override - public void changedUpdate(DocumentEvent e) { - updateHelper(); - } - /** * Update functions are called by the pathTextField which has this set as * it's DocumentEventListener. Each update function fires a property change @@ -578,4 +704,40 @@ public class ImageFilePanel extends JPanel implements DocumentListener { public void select() { pathTextField.requestFocusInWindow(); } + + /** + * This class validates on a delay canceling any tasks previously scheduled + * so that password validation doesn't lock up the system. + */ + private class DelayedValidationDocListener implements DocumentListener { + + @Override + public void insertUpdate(DocumentEvent e) { + delayValidate(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + delayValidate(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + delayValidate(); + } + + private synchronized void delayValidate() { + if (ImageFilePanel.this.validateAction != null) { + ImageFilePanel.this.validateAction.cancel(true); + } + + ImageFilePanel.this.validateAction = ImageFilePanel.this.delayedValidationService.schedule( + () -> { + ImageFilePanel.this.updateHelper(); + return null; + }, + VALIDATE_TIMEOUT_MILLIS, + TimeUnit.MILLISECONDS); + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java index 5843220af4..e63943a456 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java @@ -173,7 +173,7 @@ public class LocalDiskDSProcessor implements DataSourceProcessor { try { image = SleuthkitJNI.addImageToDatabase(Case.getCurrentCase().getSleuthkitCase(), new String[]{drivePath}, sectorSize, - timeZone, null, null, null, deviceId, this.host, this.password); + timeZone, null, null, null, deviceId, this.host); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error adding local disk with path " + drivePath + " to database", ex); final List errors = new ArrayList<>(); diff --git a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/AddMultipleImagesTask.java b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/AddMultipleImagesTask.java index 4cf0503679..95484341c7 100644 --- a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/AddMultipleImagesTask.java +++ b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/AddMultipleImagesTask.java @@ -128,7 +128,7 @@ class AddMultipleImagesTask implements Runnable { for (String imageFilePath : imageFilePaths) { try { currentImage = SleuthkitJNI.addImageToDatabase(currentCase.getSleuthkitCase(), new String[]{imageFilePath}, - 0, timeZone, "", "", "", deviceId, host, null); + 0, timeZone, "", "", "", deviceId, host); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error adding image " + imageFilePath + " to database", ex); errorMessages.add(Bundle.AddMultipleImagesTask_imageError(imageFilePath)); diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java index 137850ee17..860739f91b 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java @@ -1230,7 +1230,7 @@ public class PortableCaseReportModule implements ReportModule { if (content instanceof Image) { Image image = (Image) content; newContent = portableSkCase.addImage(image.getType(), image.getSsize(), image.getSize(), image.getName(), - new ArrayList<>(), image.getTimeZone(), md5, sha1, sha256, image.getDeviceId(), newHost, null, trans); + new ArrayList<>(), image.getTimeZone(), md5, sha1, sha256, image.getDeviceId(), newHost, trans); } else if (content instanceof VolumeSystem) { VolumeSystem vs = (VolumeSystem) content; newContent = portableSkCase.addVolumeSystem(parentId, vs.getType(), vs.getOffset(), vs.getBlockSize(), trans); From 3689e89937a27f65723c316020b6fb7136a8de4d Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 19 Dec 2024 20:53:16 -0500 Subject: [PATCH 5/8] fix in DSP processor --- .../sleuthkit/autopsy/casemodule/ImageDSProcessor.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java index c1fef28484..e7e22b5763 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java @@ -207,7 +207,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour this.host = host; try { image = SleuthkitJNI.addImageToDatabase(Case.getCurrentCase().getSleuthkitCase(), - new String[]{imagePath}, sectorSize, timeZone, md5, sha1, sha256, deviceId, this.host); + new String[]{imagePath}, sectorSize, timeZone, md5, sha1, sha256, deviceId, this.password, this.host); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error adding data source with path " + imagePath + " to database", ex); final List errors = new ArrayList<>(); @@ -271,7 +271,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour // Set up the data source before creating the ingest stream try { image = SleuthkitJNI.addImageToDatabase(Case.getCurrentCase().getSleuthkitCase(), - new String[]{imagePath}, sectorSize, timeZone, md5, sha1, sha256, deviceId, this.host); + new String[]{imagePath}, sectorSize, timeZone, md5, sha1, sha256, deviceId, this.password, this.host); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error adding data source with path " + imagePath + " to database", ex); final List errors = new ArrayList<>(); @@ -357,7 +357,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour ingestStream = new DefaultIngestStream(); try { image = SleuthkitJNI.addImageToDatabase(Case.getCurrentCase().getSleuthkitCase(), - new String[]{imagePath}, sectorSize, timeZone, "", "", "", deviceId); + new String[]{imagePath}, sectorSize, timeZone, "", "", "", deviceId, this.password, null); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error adding data source with path " + imagePath + " to database", ex); final List errors = new ArrayList<>(); @@ -518,7 +518,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour ingestStream = new DefaultIngestStream(); try { image = SleuthkitJNI.addImageToDatabase(Case.getCurrentCase().getSleuthkitCase(), - new String[]{imagePath}, sectorSize, timeZone, "", "", "", deviceId, host); + new String[]{imagePath}, sectorSize, timeZone, "", "", "", deviceId, this.password, host); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error adding data source with path " + imagePath + " to database", ex); final List errors = new ArrayList<>(); @@ -548,7 +548,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour // Set up the data source before creating the ingest stream try { image = SleuthkitJNI.addImageToDatabase(Case.getCurrentCase().getSleuthkitCase(), - new String[]{imagePath}, sectorSize, timeZone, md5, sha1, sha256, deviceId, host); + new String[]{imagePath}, sectorSize, timeZone, md5, sha1, sha256, deviceId, this.password, host); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error adding data source with path " + imagePath + " to database", ex); final List errors = new ArrayList<>(); From 9101f481f882c57e78ffdd47c799b16a3369eeb3 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 19 Dec 2024 21:35:16 -0500 Subject: [PATCH 6/8] updates --- .../autopsy/casemodule/Bundle.properties | 1 + .../casemodule/Bundle.properties-MERGED | 1 + .../autopsy/casemodule/ImageFilePanel.form | 25 +++++++++++++ .../autopsy/casemodule/ImageFilePanel.java | 35 ++++++++++++++++--- 4 files changed, 57 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index c53c3085a9..9fc3d3315e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -272,3 +272,4 @@ LocalFilesPanel.timeStampToIncludeLabel.text=Timestamps To Include: LocalFilesPanel.timeStampNoteLabel.text=NOTE: Time stamps may have changed when the files were copied to the current location. ImageFilePanel.passwordLabel.text=Bitlocker Password (optional): ImageFilePanel.passwordTextField.text= +ImageFilePanel.loadingLabel.text=loading... diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED index 9e7e2d7e81..f711125611 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED @@ -510,3 +510,4 @@ LocalFilesPanel.timeStampToIncludeLabel.text=Timestamps To Include: LocalFilesPanel.timeStampNoteLabel.text=NOTE: Time stamps may have changed when the files were copied to the current location. ImageFilePanel.passwordLabel.text=Bitlocker Password (optional): ImageFilePanel.passwordTextField.text= +ImageFilePanel.loadingLabel.text=loading... diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form index c46749306b..6e3633641d 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form @@ -310,5 +310,30 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index 7cf1f85183..585a81a1d2 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java @@ -64,7 +64,7 @@ public class ImageFilePanel extends JPanel { private final String contextName; private final List fileChooserFilters; - private static int VALIDATE_TIMEOUT_MILLIS = 1500; + private static int VALIDATE_TIMEOUT_MILLIS = 1200; static ScheduledThreadPoolExecutor delayedValidationService = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("ImageFilePanel delayed validation").build()); private Future validateAction = null; @@ -91,6 +91,7 @@ public class ImageFilePanel extends JPanel { sectorSizeComboBox.setSelectedIndex(0); errorLabel.setVisible(false); + loadingLabel.setVisible(false); this.fileChooserFilters = fileChooserFilters; } @@ -198,6 +199,7 @@ public class ImageFilePanel extends JPanel { passwordLabel = new javax.swing.JLabel(); passwordTextField = new javax.swing.JTextField(); javax.swing.JPanel spacer = new javax.swing.JPanel(); + loadingLabel = new javax.swing.JLabel(); setMinimumSize(new java.awt.Dimension(0, 65)); setPreferredSize(new java.awt.Dimension(403, 65)); @@ -425,6 +427,22 @@ public class ImageFilePanel extends JPanel { gridBagConstraints.gridy = 12; gridBagConstraints.weighty = 1.0; add(spacer, gridBagConstraints); + + loadingLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/working_spinner.gif"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(loadingLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.loadingLabel.text")); // NOI18N + loadingLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP); + loadingLabel.setMaximumSize(new java.awt.Dimension(500, 60)); + loadingLabel.setMinimumSize(new java.awt.Dimension(200, 20)); + loadingLabel.setPreferredSize(new java.awt.Dimension(200, 60)); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 11; + gridBagConstraints.gridwidth = 3; + gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5); + add(loadingLabel, gridBagConstraints); }// //GEN-END:initComponents @NbBundle.Messages({"ImageFilePanel.000.confirmationMessage=The selected file" @@ -474,6 +492,7 @@ public class ImageFilePanel extends JPanel { private javax.swing.JLabel errorLabel; private javax.swing.JLabel hashValuesLabel; private javax.swing.JLabel hashValuesNoteLabel; + private javax.swing.JLabel loadingLabel; private javax.swing.JLabel md5HashLabel; private javax.swing.JTextField md5HashTextField; private javax.swing.JCheckBox noFatOrphansCheckbox; @@ -593,10 +612,9 @@ public class ImageFilePanel extends JPanel { "ImageFilePanel_validatePanel_unknownError=

An unknown error occurred while attempting to validate the image

" }) public boolean validatePanel() { - errorLabel.setVisible(false); - String path = getContentPaths(); if (!isImagePathValid()) { + showError(null); return false; } @@ -635,16 +653,18 @@ public class ImageFilePanel extends JPanel { return false; } + showError(null); return true; } /** * Show an error message if error message is non-empty. Otherwise, hide - * error message. + * error message. Either way, hide loading label. * - * @param errorMessage The error message to show. + * @param errorMessage The error message to show or null for no error. */ private void showError(String errorMessage) { + loadingLabel.setVisible(false); if (StringUtils.isNotBlank(errorMessage)) { errorLabel.setVisible(true); errorLabel.setText(errorMessage); @@ -730,6 +750,11 @@ public class ImageFilePanel extends JPanel { if (ImageFilePanel.this.validateAction != null) { ImageFilePanel.this.validateAction.cancel(true); } + + errorLabel.setVisible(false); + if (!ImageFilePanel.this.loadingLabel.isVisible()) { + ImageFilePanel.this.loadingLabel.setVisible(true); + } ImageFilePanel.this.validateAction = ImageFilePanel.this.delayedValidationService.schedule( () -> { From 44a98864e67f0495a2f55c2ad2817bc38441fb25 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 23 Dec 2024 13:49:48 -0500 Subject: [PATCH 7/8] jna update to 5.16.0 --- CoreLibs/ivy.xml | 2 +- CoreLibs/nbproject/project.properties | 4 ++-- CoreLibs/nbproject/project.xml | 8 ++++---- Tika/nbproject/project.properties | 2 +- Tika/nbproject/project.xml | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CoreLibs/ivy.xml b/CoreLibs/ivy.xml index 446106e111..26973e5cfe 100644 --- a/CoreLibs/ivy.xml +++ b/CoreLibs/ivy.xml @@ -62,7 +62,7 @@ - + diff --git a/CoreLibs/nbproject/project.properties b/CoreLibs/nbproject/project.properties index 3dcee33819..75b27a6162 100644 --- a/CoreLibs/nbproject/project.properties +++ b/CoreLibs/nbproject/project.properties @@ -118,8 +118,8 @@ file.reference.jericho-html-3.4.jar=release/modules/ext/jericho-html-3.4.jar file.reference.jfxtras-common-17-r1.jar=release/modules/ext/jfxtras-common-17-r1.jar file.reference.jfxtras-controls-17-r1.jar=release/modules/ext/jfxtras-controls-17-r1.jar file.reference.jfxtras-fxml-17-r1.jar=release/modules/ext/jfxtras-fxml-17-r1.jar -file.reference.jna-5.15.0.jar=release/modules/ext/jna-5.15.0.jar -file.reference.jna-platform-5.15.0.jar=release/modules/ext/jna-platform-5.15.0.jar +file.reference.jna-5.16.0.jar=release/modules/ext/jna-5.16.0.jar +file.reference.jna-platform-5.16.0.jar=release/modules/ext/jna-platform-5.16.0.jar file.reference.joda-time-2.10.14.jar=release/modules/ext/joda-time-2.10.14.jar file.reference.jsr305-3.0.2.jar=release/modules/ext/jsr305-3.0.2.jar file.reference.LGoodDatePicker-11.2.1.jar=release/modules/ext/LGoodDatePicker-11.2.1.jar diff --git a/CoreLibs/nbproject/project.xml b/CoreLibs/nbproject/project.xml index ba5941acfb..f0ad9874d0 100644 --- a/CoreLibs/nbproject/project.xml +++ b/CoreLibs/nbproject/project.xml @@ -1041,12 +1041,12 @@ release/modules/ext/jfxtras-fxml-17-r1.jar - ext/jna-5.15.0.jar - release/modules/ext/jna-5.15.0.jar + ext/jna-5.16.0.jar + release/modules/ext/jna-5.16.0.jar - ext/jna-platform-5.15.0.jar - release/modules/ext/jna-platform-5.15.0.jar + ext/jna-platform-5.16.0.jar + release/modules/ext/jna-platform-5.16.0.jar ext/joda-time-2.10.14.jar diff --git a/Tika/nbproject/project.properties b/Tika/nbproject/project.properties index 92b72c53ea..e3794f4203 100755 --- a/Tika/nbproject/project.properties +++ b/Tika/nbproject/project.properties @@ -64,7 +64,7 @@ file.reference.jdom2-2.0.6.1.jar=release/modules/ext/jdom2-2.0.6.1.jar file.reference.jempbox-1.8.16.jar=release/modules/ext/jempbox-1.8.16.jar file.reference.jhighlight-1.0.3.jar=release/modules/ext/jhighlight-1.0.3.jar file.reference.jmatio-1.5.jar=release/modules/ext/jmatio-1.5.jar -file.reference.jna-5.15.0.jar=release/modules/ext/jna-5.15.0.jar +file.reference.jna-5.16.0.jar=release/modules/ext/jna-5.16.0.jar file.reference.joda-time-2.2.jar=release/modules/ext/joda-time-2.2.jar file.reference.json-simple-1.1.1.jar=release/modules/ext/json-simple-1.1.1.jar file.reference.jsr305-3.0.2.jar=release/modules/ext/jsr305-3.0.2.jar diff --git a/Tika/nbproject/project.xml b/Tika/nbproject/project.xml index 244530be96..a653584351 100755 --- a/Tika/nbproject/project.xml +++ b/Tika/nbproject/project.xml @@ -620,8 +620,8 @@ release/modules/ext/jmatio-1.5.jar - ext/jna-5.15.0.jar - release/modules/ext/jna-5.15.0.jar + ext/jna-5.16.0.jar + release/modules/ext/jna-5.16.0.jar ext/joda-time-2.2.jar From 14cb87e4fb908648cd66055468cd7419743977b8 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 3 Jan 2025 14:35:29 -0500 Subject: [PATCH 8/8] update for loading --- ...ddImageWizardDataSourceSettingsVisual.java | 54 +++++++++--- .../autopsy/casemodule/ImageDSProcessor.java | 4 +- .../autopsy/casemodule/ImageFilePanel.java | 87 +++++++++++++++---- 3 files changed, 116 insertions(+), 29 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.java index 320a2200f7..52393fee8f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.java @@ -49,6 +49,8 @@ final class AddImageWizardDataSourceSettingsVisual extends JPanel { private JPanel currentPanel; private final Map datasourceProcessorsMap = new HashMap<>(); + + private final PanelUpdateListener panelUpdateListener; private String currentDsp; @@ -60,6 +62,7 @@ final class AddImageWizardDataSourceSettingsVisual extends JPanel { AddImageWizardDataSourceSettingsVisual(AddImageWizardDataSourceSettingsPanel wizPanel) { initComponents(); this.wizPanel = wizPanel; + this.panelUpdateListener = new PanelUpdateListener(); typePanel.setLayout(new BorderLayout()); discoverDataSourceProcessors(); currentDsp = ImageDSProcessor.getType(); //default value to the ImageDSProcessor @@ -107,24 +110,37 @@ final class AddImageWizardDataSourceSettingsVisual extends JPanel { */ @SuppressWarnings("deprecation") private void updateCurrentPanel(JPanel panel) { + cleanupUpdateListener(currentPanel); currentPanel = panel; typePanel.removeAll(); typePanel.add(currentPanel, BorderLayout.CENTER); typePanel.validate(); typePanel.repaint(); - currentPanel.addPropertyChangeListener(new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString())) { - wizPanel.enableNextButton(getCurrentDSProcessor().isPanelValid()); - } - if (evt.getPropertyName().equals(DataSourceProcessor.DSP_PANEL_EVENT.FOCUS_NEXT.toString())) { - wizPanel.moveFocusToNext(); - } - } - }); + cleanupUpdateListener(currentPanel); + currentPanel.addPropertyChangeListener(panelUpdateListener); this.wizPanel.enableNextButton(getCurrentDSProcessor().isPanelValid()); } + + /** + * Removes PanelUpdateListener from panel if found. + * @param panel The panel from which to remove the listener. + */ + private void cleanupUpdateListener(JPanel panel) { + if (panel == null) { + return; + } + + PropertyChangeListener[] listeners = panel.getPropertyChangeListeners(); + if (listeners == null) { + return; + } + + for (PropertyChangeListener listener: listeners) { + if (listener instanceof PanelUpdateListener) { + panel.removePropertyChangeListener(listener); + } + } + } /** * Returns the currently selected DS Processor @@ -221,4 +237,20 @@ final class AddImageWizardDataSourceSettingsVisual extends JPanel { protected abstract boolean addSeparatorAfter(JList list, Object value, int index); } + + /** + * A property change listener that responds to update events. + */ + private class PanelUpdateListener implements PropertyChangeListener { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString())) { + wizPanel.enableNextButton(getCurrentDSProcessor().isPanelValid()); + } + if (evt.getPropertyName().equals(DataSourceProcessor.DSP_PANEL_EVENT.FOCUS_NEXT.toString())) { + wizPanel.moveFocusToNext(); + } + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java index e7e22b5763..83bfb434f1 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java @@ -163,7 +163,9 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour */ @Override public boolean isPanelValid() { - return configPanel.validatePanel(); + // before attempting to validate the panel (a potentially long running operation), + // check if the validation is loading or on delay. + return !configPanel.isValidationLoading() && configPanel.validatePanel(); } /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index 585a81a1d2..166067478d 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java @@ -67,7 +67,9 @@ public class ImageFilePanel extends JPanel { private static int VALIDATE_TIMEOUT_MILLIS = 1200; static ScheduledThreadPoolExecutor delayedValidationService = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("ImageFilePanel delayed validation").build()); - private Future validateAction = null; + private final Object validateActionLock = new Object(); + private Runnable validateAction = null; + private Future validateFuture = null; /** * Creates new form ImageFilePanel @@ -632,10 +634,6 @@ public class ImageFilePanel extends JPanel { showError(Bundle.ImageFilePanel_validatePanel_invalidSHA256()); return false; } - - if (!PathValidator.isValidForCaseType(path, Case.getCurrentCase().getCaseType())) { - showError(Bundle.ImageFilePanel_validatePanel_dataSourceOnCDriveError()); - } try { String password = this.getPassword(); @@ -652,8 +650,12 @@ public class ImageFilePanel extends JPanel { showError(Bundle.ImageFilePanel_validatePanel_unknownError()); return false; } - - showError(null); + + if (!PathValidator.isValidForCaseType(path, Case.getCurrentCase().getCaseType())) { + showError(Bundle.ImageFilePanel_validatePanel_dataSourceOnCDriveError()); + } else { + showError(null); + } return true; } @@ -683,6 +685,16 @@ public class ImageFilePanel extends JPanel { return true; } + + /** + * @return True if the panel is on a delay for validating (i.e. typing a + * password for bitlocker). + */ + public boolean isValidationLoading() { + synchronized (this.validateActionLock) { + return this.validateAction != null; + } + } public void storeSettings() { String imagePathName = getContentPaths(); @@ -746,23 +758,64 @@ public class ImageFilePanel extends JPanel { delayValidate(); } - private synchronized void delayValidate() { - if (ImageFilePanel.this.validateAction != null) { - ImageFilePanel.this.validateAction.cancel(true); + /** + * Run validation on a delay to avoid password checking too many times + * while typing. + */ + private void delayValidate() { + boolean triggerUpdate = false; + synchronized (ImageFilePanel.this.validateActionLock) { + if (ImageFilePanel.this.validateFuture != null && + !ImageFilePanel.this.validateFuture.isCancelled() && + !ImageFilePanel.this.validateFuture.isDone()) { + ImageFilePanel.this.validateFuture.cancel(true); + triggerUpdate = true; + } + + ImageFilePanel.this.validateAction = new ValidationRunnable(); + + ImageFilePanel.this.validateFuture = ImageFilePanel.this.delayedValidationService.schedule( + ImageFilePanel.this.validateAction, + VALIDATE_TIMEOUT_MILLIS, + TimeUnit.MILLISECONDS); } + // trigger invalidation after setting up new runnable if not already triggered + if (triggerUpdate) { + firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true); + } + errorLabel.setVisible(false); if (!ImageFilePanel.this.loadingLabel.isVisible()) { ImageFilePanel.this.loadingLabel.setVisible(true); } + } + + /** + * Runnable to run the updateHelper if the validation action remains + * this runnable. + */ + private class ValidationRunnable implements Runnable { - ImageFilePanel.this.validateAction = ImageFilePanel.this.delayedValidationService.schedule( - () -> { - ImageFilePanel.this.updateHelper(); - return null; - }, - VALIDATE_TIMEOUT_MILLIS, - TimeUnit.MILLISECONDS); + @Override + public void run() { + if (Thread.interrupted()) { + return; + } + + synchronized (ImageFilePanel.this.validateActionLock) { + if (ImageFilePanel.this.validateAction != this) { + return; + } + + // set the validation action to null to indicate that this is done running and can be validated. + ImageFilePanel.this.validateAction = null; + ImageFilePanel.this.validateFuture = null; + } + + ImageFilePanel.this.updateHelper(); + } + } } }