diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java index cbcb06c936..ded1c3c26a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java @@ -47,6 +47,9 @@ class AddImageTask implements Runnable { private final String timeZone; private final ImageWriterSettings imageWriterSettings; private final boolean ignoreFatOrphanFiles; + private final String md5; + private final String sha1; + private final String sha256; private final DataSourceProcessorProgressMonitor progressMonitor; private final DataSourceProcessorCallback callback; private boolean criticalErrorOccurred; @@ -63,7 +66,7 @@ class AddImageTask implements Runnable { * TODO (AUT-2021): Merge SleuthkitJNI.AddImageProcess and AddImageTask */ private final Object tskAddImageProcessLock; - + @GuardedBy("tskAddImageProcessLock") private boolean tskAddImageProcessStopped; private SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess; @@ -82,6 +85,9 @@ class AddImageTask implements Runnable { * java.util.TimeZone.getID. * @param ignoreFatOrphanFiles Whether to parse orphans if the image has a * FAT filesystem. + * @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 imageWriterPath Path that a copy of the image should be * written to. Use empty string to disable image * writing @@ -89,13 +95,16 @@ class AddImageTask implements Runnable { * processing. * @param callback Callback to call when processing is done. */ - AddImageTask(String deviceId, String imagePath, int sectorSize, String timeZone, boolean ignoreFatOrphanFiles, ImageWriterSettings imageWriterSettings, + AddImageTask(String deviceId, String imagePath, int sectorSize, String timeZone, boolean ignoreFatOrphanFiles, String md5, String sha1, String sha256, ImageWriterSettings imageWriterSettings, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { this.deviceId = deviceId; this.imagePath = imagePath; this.sectorSize = sectorSize; this.timeZone = timeZone; this.ignoreFatOrphanFiles = ignoreFatOrphanFiles; + this.md5 = md5; + this.sha1 = sha1; + this.sha256 = sha256; this.imageWriterSettings = imageWriterSettings; this.callback = callback; this.progressMonitor = progressMonitor; @@ -111,7 +120,7 @@ class AddImageTask implements Runnable { try { currentCase = Case.getCurrentCaseThrows(); } catch (NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Exception while getting open case.", ex); + logger.log(Level.SEVERE, "Failed to add image data source, no current case", ex); return; } progressMonitor.setIndeterminate(true); @@ -125,11 +134,10 @@ class AddImageTask implements Runnable { try { currentCase.getSleuthkitCase().acquireSingleUserCaseWriteLock(); synchronized (tskAddImageProcessLock) { - if (!tskAddImageProcessStopped) { //if we have already cancelled don't bother making an addImageProcess - tskAddImageProcess = currentCase.getSleuthkitCase().makeAddImageProcess(timeZone, true, - ignoreFatOrphanFiles, imageWriterPath); + if (!tskAddImageProcessStopped) { + tskAddImageProcess = currentCase.getSleuthkitCase().makeAddImageProcess(timeZone, true, ignoreFatOrphanFiles, imageWriterPath); } else { - return; //we have already cancelled so we do not want to add the image, returning will execute the finally block + return; } } Thread progressUpdateThread = new Thread(new ProgressUpdater(progressMonitor, tskAddImageProcess)); @@ -139,7 +147,6 @@ class AddImageTask implements Runnable { commitOrRevertAddImageProcess(currentCase, errorMessages, newDataSources); progressMonitor.setProgress(100); } finally { - currentCase.getSleuthkitCase().releaseSingleUserCaseWriteLock(); DataSourceProcessorCallback.DataSourceProcessorResult result; if (criticalErrorOccurred) { result = DataSourceProcessorResult.CRITICAL_ERRORS; @@ -148,6 +155,7 @@ class AddImageTask implements Runnable { } else { result = DataSourceProcessorResult.NO_ERRORS; } + currentCase.getSleuthkitCase().releaseSingleUserCaseWriteLock(); callback.done(result, errorMessages, newDataSources); } } @@ -233,6 +241,39 @@ class AddImageTask implements Runnable { ImageWriterService.createImageWriter(imageId, imageWriterSettings); } newDataSources.add(newImage); + try { + newImage.setMD5(md5); + } catch (TskCoreException | TskDataException ex) { + /* + * Treat both exceptions as the same since this is a + * new image and the hash should not already be set. + */ + logger.log(Level.SEVERE, String.format("Failed to add MD5 hash for image data source %s (objId=%d)", newImage.getName(), newImage.getId()), ex); + errorMessages.add(ex.getMessage()); + criticalErrorOccurred = true; + } + try { + newImage.setSha1(sha1); + } catch (TskCoreException | TskDataException ex) { + /* + * Treat both exceptions as the same since this is a + * new image and the hash should not already be set. + */ + logger.log(Level.SEVERE, String.format("Failed to add SHA1 hash for image data source %s (objId=%d)", newImage.getName(), newImage.getId()), ex); + errorMessages.add(ex.getMessage()); + criticalErrorOccurred = true; + } + try { + newImage.setSha256(sha256); + } catch (TskCoreException | TskDataException ex) { + /* + * Treat both exceptions as the same since this is a + * new image and the hash should not already be set. + */ + logger.log(Level.SEVERE, String.format("Failed to add SHA256 for image data source %s (objId=%d)", newImage.getName(), newImage.getId()), ex); + errorMessages.add(ex.getMessage()); + criticalErrorOccurred = true; + } } else { String errorMessage = String.format("Error commiting adding image %s to the case database, no object id returned", imagePath); //NON-NLS logger.log(Level.SEVERE, errorMessage); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 42eb09af5f..a413abd846 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -24,7 +24,7 @@ AddImageErrorsDialog.copyButton.text=Copy AddImageErrorsDialog.closeButton.toolTipText=Close this window AddImageErrorsDialog.closeButton.text=Close OpenRecentCasePanel.openButton.text=Open -ImageFilePanel.pathLabel.text=Browse for an image file: +ImageFilePanel.pathLabel.text=Path: ImageFilePanel.browseButton.text=Browse ImageFilePanel.pathTextField.text= MissingImageDialog.selectButton.text=Select Image @@ -201,7 +201,6 @@ MultiUserCasesPanel.bnOpenSingleUserCase.text=Open Single-User Case... CueBannerPanel.newCaseButton.text= MultiUserCasesPanel.searchLabel.text=Select any case and start typing to search by case name MultiUserCasesPanel.cancelButton.text=Cancel -ImageFilePanel.pathErrorLabel.text=Error Label ImageFilePanel.sectorSizeLabel.text=Sector size: LocalDiskPanel.sectorSizeLabel.text=Sector Size: LocalFilesPanel.displayNameLabel.text=Logical File Set Display Name: Default @@ -239,3 +238,4 @@ ImageFilePanel.sha256HashLabel.text=SHA-256 hash: ImageFilePanel.sha256HashTextField.text= ImageFilePanel.sha1HashTextField.text= ImageFilePanel.md5HashTextField.text= +ImageFilePanel.errorLabel.text=Error Label diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties index 90849f4639..408ad24806 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties @@ -186,7 +186,6 @@ OpenMultiUserCasePanel.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb OpenMultiUserCasePanel.jLabel1.text=\u6700\u8fd1\u958b\u3044\u305f\u30d5\u30a1\u30a4\u30eb CueBannerPanel.newCaseLabel.text=\u65b0\u898f\u30b1\u30fc\u30b9\u3092\u4f5c\u6210 CueBannerPanel.openCaseLabel.text=\u65e2\u5b58\u30b1\u30fc\u30b9\u3092\u958b\u304f -ImageFilePanel.pathErrorLabel.text=\u30a8\u30e9\u30fc\u30e9\u30d9\u30eb ImageFilePanel.sectorSizeLabel.text=\u30a4\u30f3\u30d7\u30c3\u30c8\u30bf\u30a4\u30e0\u30be\u30fc\u30f3\u3092\u9078\u629e\u3057\u3066\u4e0b\u3055\u3044\uff1a LocalFilesPanel.errorLabel.text=\u30a8\u30e9\u30fc\u30e9\u30d9\u30eb LocalFilesPanel.clearButton.toolTipText=\u73fe\u5728\u9078\u629e\u3055\u308c\u3066\u3044\u308b\u30ed\u30fc\u30ab\u30eb\u30d5\u30a1\u30a4\u30eb\u30d1\u30b9\u304c\u30af\u30ea\u30a2\u3055\u308c\u307e\u3059 diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java index 0fb98ea8b8..722b16472c 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java @@ -41,9 +41,10 @@ import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; * wizard. It also provides a run method overload to allow it to be used * independently of the wizard. */ -@ServiceProviders(value={ - @ServiceProvider(service=DataSourceProcessor.class), - @ServiceProvider(service=AutoIngestDataSourceProcessor.class)} +@ServiceProviders(value = { + @ServiceProvider(service = DataSourceProcessor.class) + , + @ServiceProvider(service = AutoIngestDataSourceProcessor.class)} ) public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSourceProcessor { @@ -66,6 +67,9 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour private int sectorSize; private String timeZone; private boolean ignoreFatOrphanFiles; + private String md5; + private String sha1; + private String sha256; private boolean setDataSourceOptionsCalled; static { @@ -74,7 +78,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour filtersList.add(encaseFilter); allExt.addAll(GeneralFilter.RAW_IMAGE_EXTS); allExt.addAll(GeneralFilter.ENCASE_IMAGE_EXTS); - if(!System.getProperty("os.name").toLowerCase().contains("mac")){ + if (!System.getProperty("os.name").toLowerCase().contains("mac")) { filtersList.add(virtualMachineFilter); allExt.addAll(GeneralFilter.VIRTUAL_MACHINE_EXTS); } @@ -89,10 +93,10 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour public ImageDSProcessor() { configPanel = ImageFilePanel.createInstance(ImageDSProcessor.class.getName(), filtersList); } - + /** * Get the list of file filters supported by this DSP. - * + * * @return A list of all supported file filters. */ static List getFileFiltersList() { @@ -172,8 +176,20 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour sectorSize = configPanel.getSectorSize(); timeZone = configPanel.getTimeZone(); ignoreFatOrphanFiles = configPanel.getNoFatOrphans(); + md5 = configPanel.getMd5(); + if (md5.isEmpty()) { + md5 = null; + } + sha1 = configPanel.getSha1(); + if (sha1.isEmpty()) { + sha1 = null; + } + sha256 = configPanel.getSha256(); + if (sha256.isEmpty()) { + sha256 = null; + } } - run(deviceId, imagePath, sectorSize, timeZone, ignoreFatOrphanFiles, progressMonitor, callback); + run(deviceId, imagePath, sectorSize, timeZone, ignoreFatOrphanFiles, md5, sha1, sha256, progressMonitor, callback); } /** @@ -198,7 +214,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour * @param callback Callback to call when processing is done. */ public void run(String deviceId, String imagePath, String timeZone, boolean ignoreFatOrphanFiles, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { - run(deviceId, imagePath, 0, timeZone, ignoreFatOrphanFiles, progressMonitor, callback); + run(deviceId, imagePath, 0, timeZone, ignoreFatOrphanFiles, null, null, null, progressMonitor, callback); } /** @@ -219,12 +235,15 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour * java.util.TimeZone.getID. * @param ignoreFatOrphanFiles Whether to parse orphans if the image has a * FAT filesystem. + * @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 progressMonitor Progress monitor for reporting progress * during processing. * @param callback Callback to call when processing is done. */ - private void run(String deviceId, String imagePath, int sectorSize, String timeZone, boolean ignoreFatOrphanFiles, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { - addImageTask = new AddImageTask(deviceId, imagePath, sectorSize, timeZone, ignoreFatOrphanFiles, null, progressMonitor, callback); + private void run(String deviceId, String imagePath, int sectorSize, String timeZone, boolean ignoreFatOrphanFiles, String md5, String sha1, String sha256, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { + addImageTask = new AddImageTask(deviceId, imagePath, sectorSize, timeZone, ignoreFatOrphanFiles, md5, sha1, sha256, null, progressMonitor, callback); new Thread(addImageTask).start(); } @@ -267,12 +286,12 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour @Override public int canProcess(Path dataSourcePath) throws AutoIngestDataSourceProcessorException { - + // check file extension for supported types if (!isAcceptedByFiler(dataSourcePath.toFile(), filtersList)) { return 0; } - + try { // verify that the image has a file system that TSK can process Case currentCase = Case.getCurrentCaseThrows(); @@ -283,7 +302,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour } catch (Exception ex) { throw new AutoIngestDataSourceProcessorException("Exception inside canProcess() method", ex); } - + // able to process the data source return 100; } @@ -296,9 +315,9 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour this.timeZone = Calendar.getInstance().getTimeZone().getID(); this.ignoreFatOrphanFiles = false; setDataSourceOptionsCalled = true; - run(deviceId, dataSourcePath.toString(), sectorSize, timeZone, ignoreFatOrphanFiles, progressMonitor, callBack); + run(deviceId, dataSourcePath.toString(), sectorSize, timeZone, ignoreFatOrphanFiles, null, null, null, progressMonitor, callBack); } - + /** * Sets the configuration of the data source processor without using the * selection and configuration panel. @@ -321,5 +340,5 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour this.ignoreFatOrphanFiles = ignoreFatOrphanFiles; setDataSourceOptionsCalled = true; } - + } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form index 5c738b0c7d..6a1bd5465e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form @@ -33,7 +33,7 @@ - + @@ -54,7 +54,7 @@ - + @@ -67,8 +67,6 @@ - - @@ -96,7 +94,9 @@ - + + + @@ -154,13 +154,13 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index cf282311fa..61c0e84f9f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java @@ -21,23 +21,21 @@ package org.sleuthkit.autopsy.casemodule; import java.io.File; import java.util.Calendar; import java.util.List; -import java.util.logging.Level; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.JTextField; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.filechooser.FileFilter; import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle; -import static org.sleuthkit.autopsy.casemodule.Bundle.*; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.DriveUtils; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PathValidator; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; +import org.sleuthkit.datamodel.HashUtility; /** * Panel for adding an image file such as .img, .E0x, .00x, etc. Allows the user @@ -47,15 +45,10 @@ import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives public class ImageFilePanel extends JPanel implements DocumentListener { - private static final Logger logger = Logger.getLogger(ImageFilePanel.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"}; - private final JFileChooser fileChooser = new JFileChooser(); - - /** - * Externally supplied name is used to store settings - */ private final String contextName; /** @@ -79,7 +72,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { } sectorSizeComboBox.setSelectedIndex(0); - pathErrorLabel.setVisible(false); + errorLabel.setVisible(false); fileChooser.setDragEnabled(false); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); @@ -117,10 +110,29 @@ public class ImageFilePanel extends JPanel implements DocumentListener { public static synchronized ImageFilePanel createInstance(String context, List fileChooserFilters) { ImageFilePanel instance = new ImageFilePanel(context, fileChooserFilters); // post-constructor initialization of listener support without leaking references of uninitialized objects - instance.pathTextField.getDocument().addDocumentListener(instance); + instance.getPathTextField().getDocument().addDocumentListener(instance); + instance.getMd5TextFieldField().getDocument().addDocumentListener(instance); + instance.getSha1TextField().getDocument().addDocumentListener(instance); + instance.getSha256TextField().getDocument().addDocumentListener(instance); return instance; } + private JTextField getPathTextField() { + return pathTextField; + } + + private JTextField getMd5TextFieldField() { + return md5HashTextField; + } + + private JTextField getSha1TextField() { + return sha1HashTextField; + } + + private JTextField getSha256TextField() { + return sha256HashTextField; + } + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -135,7 +147,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { timeZoneLabel = new javax.swing.JLabel(); timeZoneComboBox = new javax.swing.JComboBox<>(); noFatOrphansCheckbox = new javax.swing.JCheckBox(); - pathErrorLabel = new javax.swing.JLabel(); + errorLabel = new javax.swing.JLabel(); sectorSizeLabel = new javax.swing.JLabel(); sectorSizeComboBox = new javax.swing.JComboBox<>(); sha256HashLabel = new javax.swing.JLabel(); @@ -166,8 +178,8 @@ public class ImageFilePanel extends JPanel implements DocumentListener { 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 - pathErrorLabel.setForeground(new java.awt.Color(255, 0, 0)); - org.openide.awt.Mnemonics.setLocalizedText(pathErrorLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.pathErrorLabel.text")); // NOI18N + 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 org.openide.awt.Mnemonics.setLocalizedText(sectorSizeLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.sectorSizeLabel.text")); // NOI18N @@ -195,7 +207,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(pathLabel) - .addComponent(pathErrorLabel) + .addComponent(errorLabel) .addComponent(noFatOrphansCheckbox)) .addGap(0, 0, Short.MAX_VALUE)) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() @@ -212,7 +224,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .addComponent(md5HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 231, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(sha1HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 287, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(sha256HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 455, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap(11, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -222,8 +234,6 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .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)) - .addGap(3, 3, 3) - .addComponent(pathErrorLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(noFatOrphansCheckbox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) @@ -246,7 +256,9 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .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)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGap(18, 18, 18) + .addComponent(errorLabel) + .addContainerGap(45, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -282,10 +294,10 @@ public class ImageFilePanel extends JPanel implements DocumentListener { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton browseButton; + private javax.swing.JLabel errorLabel; private javax.swing.JLabel md5HashLabel; private javax.swing.JTextField md5HashTextField; private javax.swing.JCheckBox noFatOrphansCheckbox; - private javax.swing.JLabel pathErrorLabel; private javax.swing.JLabel pathLabel; private javax.swing.JTextField pathTextField; private javax.swing.JComboBox sectorSizeComboBox; @@ -340,6 +352,18 @@ public class ImageFilePanel extends JPanel implements DocumentListener { return noFatOrphansCheckbox.isSelected(); } + String getMd5() { + return this.md5HashTextField.getText(); + } + + String getSha1() { + return this.sha1HashTextField.getText(); + } + + String getSha256() { + return this.sha256HashTextField.getText(); + } + public void reset() { //reset the UI elements to default pathTextField.setText(null); @@ -350,30 +374,43 @@ public class ImageFilePanel extends JPanel implements DocumentListener { * * @return true if a proper image has been selected, false otherwise */ - @NbBundle.Messages({"ImageFilePanel.pathValidation.dataSourceOnCDriveError=Warning: Path to multi-user data source is on \"C:\" drive", - "ImageFilePanel.pathValidation.getOpenCase.Error=Warning: Exception while getting open case." - }) + @NbBundle.Messages({ + "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",}) public boolean validatePanel() { - pathErrorLabel.setVisible(false); + errorLabel.setVisible(false); + String path = getContentPaths(); - if (StringUtils.isBlank(path)) { + if (StringUtils.isBlank(path) || (!(new File(path).isFile() || DriveUtils.isPhysicalDrive(path) || DriveUtils.isPartition(path)))) { return false; } - // Display warning if there is one (but don't disable "next" button) - try { - if (false == PathValidator.isValidForMultiUserCase(path, Case.getCurrentCaseThrows().getCaseType())) { - pathErrorLabel.setVisible(true); - pathErrorLabel.setText(Bundle.ImageFilePanel_pathValidation_dataSourceOnCDriveError()); - } - } catch (NoCurrentCaseException ex) { - pathErrorLabel.setVisible(true); - pathErrorLabel.setText(Bundle.ImageFilePanel_pathValidation_getOpenCase_Error()); + if (!StringUtils.isBlank(getMd5()) && !HashUtility.isValidMd5Hash(getMd5())) { + errorLabel.setVisible(true); + errorLabel.setText(Bundle.ImageFilePanel_validatePanel_invalidMD5()); + return false; } - return new File(path).isFile() - || DriveUtils.isPhysicalDrive(path) - || DriveUtils.isPartition(path); + if (!StringUtils.isBlank(getSha1()) && !HashUtility.isValidSha1Hash(getSha1())) { + errorLabel.setVisible(true); + errorLabel.setText(Bundle.ImageFilePanel_validatePanel_invalidSHA1()); + return false; + } + + if (!StringUtils.isBlank(getSha256()) && !HashUtility.isValidSha256Hash(getSha256())) { + errorLabel.setVisible(true); + errorLabel.setText(Bundle.ImageFilePanel_validatePanel_invalidSHA256()); + return false; + } + + if (!PathValidator.isValidForMultiUserCase(path, Case.getCurrentCase().getCaseType())) { + errorLabel.setVisible(true); + errorLabel.setText(Bundle.ImageFilePanel_validatePanel_dataSourceOnCDriveError()); + } + + return true; } public void storeSettings() { @@ -416,12 +453,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { "ImageFilePanel.moduleErr.msg=A module caused an error listening to ImageFilePanel updates." + " See log to determine which module. Some data could be incomplete.\n"}) private void updateHelper() { - try { - firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true); - } catch (Exception e) { - logger.log(Level.SEVERE, "ImageFilePanel listener threw exception", e); //NON-NLS - MessageNotifyUtil.Notify.error(ImageFilePanel_moduleErr(), ImageFilePanel_moduleErr_msg()); - } + firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true); } /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java index 38d422585f..60c0aed94b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java @@ -139,7 +139,7 @@ public class LocalDiskDSProcessor implements DataSourceProcessor { imageWriterSettings = null; } } - addDiskTask = new AddImageTask(deviceId, drivePath, sectorSize, timeZone, ignoreFatOrphanFiles, imageWriterSettings, progressMonitor, callback); + addDiskTask = new AddImageTask(deviceId, drivePath, sectorSize, timeZone, ignoreFatOrphanFiles, null, null, null, imageWriterSettings, progressMonitor, callback); new Thread(addDiskTask).start(); } @@ -191,7 +191,7 @@ public class LocalDiskDSProcessor implements DataSourceProcessor { * @param callback Callback to call when processing is done. */ private void run(String deviceId, String drivePath, int sectorSize, String timeZone, boolean ignoreFatOrphanFiles, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { - addDiskTask = new AddImageTask(deviceId, drivePath, sectorSize, timeZone, ignoreFatOrphanFiles, imageWriterSettings, progressMonitor, callback); + addDiskTask = new AddImageTask(deviceId, drivePath, sectorSize, timeZone, ignoreFatOrphanFiles, null, null, null, imageWriterSettings, progressMonitor, callback); new Thread(addDiskTask).start(); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/dataSourceIntegrity/DataSourceIntegrityIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/dataSourceIntegrity/DataSourceIntegrityIngestModule.java index a47e869fec..1971a83b2b 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/dataSourceIntegrity/DataSourceIntegrityIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/dataSourceIntegrity/DataSourceIntegrityIngestModule.java @@ -25,7 +25,6 @@ import java.util.List; import java.util.logging.Level; import javax.xml.bind.DatatypeConverter; import java.util.Arrays; -import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.DataSourceIngestModule; import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress; @@ -266,12 +265,12 @@ public class DataSourceIntegrityIngestModule implements DataSourceIngestModule { for (HashData hashData:hashDataList) { if (hashData.storedHash.equals(hashData.calculatedHash)) { - hashResults += Bundle.DataSourceIntegrityIngestModule_process_hashMatch(hashData.type.name); + hashResults += Bundle.DataSourceIntegrityIngestModule_process_hashMatch(hashData.type.name) + " "; } else { verified = false; - hashResults += Bundle.DataSourceIntegrityIngestModule_process_hashNonMatch(hashData.type.name); + hashResults += Bundle.DataSourceIntegrityIngestModule_process_hashNonMatch(hashData.type.name) + " "; artifactComment += Bundle.DataSourceIntegrityIngestModule_process_hashFailedForArtifact(hashData.type.name, - hashData.calculatedHash, hashData.storedHash); + hashData.calculatedHash, hashData.storedHash) + " "; } hashResults += Bundle.DataSourceIntegrityIngestModule_process_hashList(hashData.calculatedHash, hashData.storedHash); }