User can enter image data source hashes

This commit is contained in:
Richard Cordovano 2018-12-08 15:13:22 -05:00
parent 16eed89b82
commit e213eb04d3
8 changed files with 174 additions and 84 deletions

View File

@ -47,6 +47,9 @@ class AddImageTask implements Runnable {
private final String timeZone; private final String timeZone;
private final ImageWriterSettings imageWriterSettings; private final ImageWriterSettings imageWriterSettings;
private final boolean ignoreFatOrphanFiles; private final boolean ignoreFatOrphanFiles;
private final String md5;
private final String sha1;
private final String sha256;
private final DataSourceProcessorProgressMonitor progressMonitor; private final DataSourceProcessorProgressMonitor progressMonitor;
private final DataSourceProcessorCallback callback; private final DataSourceProcessorCallback callback;
private boolean criticalErrorOccurred; private boolean criticalErrorOccurred;
@ -63,7 +66,7 @@ class AddImageTask implements Runnable {
* TODO (AUT-2021): Merge SleuthkitJNI.AddImageProcess and AddImageTask * TODO (AUT-2021): Merge SleuthkitJNI.AddImageProcess and AddImageTask
*/ */
private final Object tskAddImageProcessLock; private final Object tskAddImageProcessLock;
@GuardedBy("tskAddImageProcessLock") @GuardedBy("tskAddImageProcessLock")
private boolean tskAddImageProcessStopped; private boolean tskAddImageProcessStopped;
private SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess; private SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess;
@ -82,6 +85,9 @@ class AddImageTask implements Runnable {
* java.util.TimeZone.getID. * java.util.TimeZone.getID.
* @param ignoreFatOrphanFiles Whether to parse orphans if the image has a * @param ignoreFatOrphanFiles Whether to parse orphans if the image has a
* FAT filesystem. * 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 * @param imageWriterPath Path that a copy of the image should be
* written to. Use empty string to disable image * written to. Use empty string to disable image
* writing * writing
@ -89,13 +95,16 @@ class AddImageTask implements Runnable {
* processing. * processing.
* @param callback Callback to call when processing is done. * @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) { DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
this.deviceId = deviceId; this.deviceId = deviceId;
this.imagePath = imagePath; this.imagePath = imagePath;
this.sectorSize = sectorSize; this.sectorSize = sectorSize;
this.timeZone = timeZone; this.timeZone = timeZone;
this.ignoreFatOrphanFiles = ignoreFatOrphanFiles; this.ignoreFatOrphanFiles = ignoreFatOrphanFiles;
this.md5 = md5;
this.sha1 = sha1;
this.sha256 = sha256;
this.imageWriterSettings = imageWriterSettings; this.imageWriterSettings = imageWriterSettings;
this.callback = callback; this.callback = callback;
this.progressMonitor = progressMonitor; this.progressMonitor = progressMonitor;
@ -111,7 +120,7 @@ class AddImageTask implements Runnable {
try { try {
currentCase = Case.getCurrentCaseThrows(); currentCase = Case.getCurrentCaseThrows();
} catch (NoCurrentCaseException ex) { } 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; return;
} }
progressMonitor.setIndeterminate(true); progressMonitor.setIndeterminate(true);
@ -125,11 +134,10 @@ class AddImageTask implements Runnable {
try { try {
currentCase.getSleuthkitCase().acquireSingleUserCaseWriteLock(); currentCase.getSleuthkitCase().acquireSingleUserCaseWriteLock();
synchronized (tskAddImageProcessLock) { synchronized (tskAddImageProcessLock) {
if (!tskAddImageProcessStopped) { //if we have already cancelled don't bother making an addImageProcess if (!tskAddImageProcessStopped) {
tskAddImageProcess = currentCase.getSleuthkitCase().makeAddImageProcess(timeZone, true, tskAddImageProcess = currentCase.getSleuthkitCase().makeAddImageProcess(timeZone, true, ignoreFatOrphanFiles, imageWriterPath);
ignoreFatOrphanFiles, imageWriterPath);
} else { } 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)); Thread progressUpdateThread = new Thread(new ProgressUpdater(progressMonitor, tskAddImageProcess));
@ -139,7 +147,6 @@ class AddImageTask implements Runnable {
commitOrRevertAddImageProcess(currentCase, errorMessages, newDataSources); commitOrRevertAddImageProcess(currentCase, errorMessages, newDataSources);
progressMonitor.setProgress(100); progressMonitor.setProgress(100);
} finally { } finally {
currentCase.getSleuthkitCase().releaseSingleUserCaseWriteLock();
DataSourceProcessorCallback.DataSourceProcessorResult result; DataSourceProcessorCallback.DataSourceProcessorResult result;
if (criticalErrorOccurred) { if (criticalErrorOccurred) {
result = DataSourceProcessorResult.CRITICAL_ERRORS; result = DataSourceProcessorResult.CRITICAL_ERRORS;
@ -148,6 +155,7 @@ class AddImageTask implements Runnable {
} else { } else {
result = DataSourceProcessorResult.NO_ERRORS; result = DataSourceProcessorResult.NO_ERRORS;
} }
currentCase.getSleuthkitCase().releaseSingleUserCaseWriteLock();
callback.done(result, errorMessages, newDataSources); callback.done(result, errorMessages, newDataSources);
} }
} }
@ -233,6 +241,39 @@ class AddImageTask implements Runnable {
ImageWriterService.createImageWriter(imageId, imageWriterSettings); ImageWriterService.createImageWriter(imageId, imageWriterSettings);
} }
newDataSources.add(newImage); 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 { } else {
String errorMessage = String.format("Error commiting adding image %s to the case database, no object id returned", imagePath); //NON-NLS 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); logger.log(Level.SEVERE, errorMessage);

View File

@ -24,7 +24,7 @@ AddImageErrorsDialog.copyButton.text=Copy
AddImageErrorsDialog.closeButton.toolTipText=Close this window AddImageErrorsDialog.closeButton.toolTipText=Close this window
AddImageErrorsDialog.closeButton.text=Close AddImageErrorsDialog.closeButton.text=Close
OpenRecentCasePanel.openButton.text=Open OpenRecentCasePanel.openButton.text=Open
ImageFilePanel.pathLabel.text=Browse for an image file: ImageFilePanel.pathLabel.text=Path:
ImageFilePanel.browseButton.text=Browse ImageFilePanel.browseButton.text=Browse
ImageFilePanel.pathTextField.text= ImageFilePanel.pathTextField.text=
MissingImageDialog.selectButton.text=Select Image MissingImageDialog.selectButton.text=Select Image
@ -201,7 +201,6 @@ MultiUserCasesPanel.bnOpenSingleUserCase.text=Open Single-User Case...
CueBannerPanel.newCaseButton.text= CueBannerPanel.newCaseButton.text=
MultiUserCasesPanel.searchLabel.text=Select any case and start typing to search by case name MultiUserCasesPanel.searchLabel.text=Select any case and start typing to search by case name
MultiUserCasesPanel.cancelButton.text=Cancel MultiUserCasesPanel.cancelButton.text=Cancel
ImageFilePanel.pathErrorLabel.text=Error Label
ImageFilePanel.sectorSizeLabel.text=Sector size: ImageFilePanel.sectorSizeLabel.text=Sector size:
LocalDiskPanel.sectorSizeLabel.text=Sector Size: LocalDiskPanel.sectorSizeLabel.text=Sector Size:
LocalFilesPanel.displayNameLabel.text=Logical File Set Display Name: Default LocalFilesPanel.displayNameLabel.text=Logical File Set Display Name: Default
@ -239,3 +238,4 @@ ImageFilePanel.sha256HashLabel.text=SHA-256 hash:
ImageFilePanel.sha256HashTextField.text= ImageFilePanel.sha256HashTextField.text=
ImageFilePanel.sha1HashTextField.text= ImageFilePanel.sha1HashTextField.text=
ImageFilePanel.md5HashTextField.text= ImageFilePanel.md5HashTextField.text=
ImageFilePanel.errorLabel.text=Error Label

View File

@ -186,7 +186,6 @@ OpenMultiUserCasePanel.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb
OpenMultiUserCasePanel.jLabel1.text=\u6700\u8fd1\u958b\u3044\u305f\u30d5\u30a1\u30a4\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.newCaseLabel.text=\u65b0\u898f\u30b1\u30fc\u30b9\u3092\u4f5c\u6210
CueBannerPanel.openCaseLabel.text=\u65e2\u5b58\u30b1\u30fc\u30b9\u3092\u958b\u304f 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 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.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 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

View File

@ -41,9 +41,10 @@ import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor;
* wizard. It also provides a run method overload to allow it to be used * wizard. It also provides a run method overload to allow it to be used
* independently of the wizard. * independently of the wizard.
*/ */
@ServiceProviders(value={ @ServiceProviders(value = {
@ServiceProvider(service=DataSourceProcessor.class), @ServiceProvider(service = DataSourceProcessor.class)
@ServiceProvider(service=AutoIngestDataSourceProcessor.class)} ,
@ServiceProvider(service = AutoIngestDataSourceProcessor.class)}
) )
public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSourceProcessor { public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSourceProcessor {
@ -66,6 +67,9 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour
private int sectorSize; private int sectorSize;
private String timeZone; private String timeZone;
private boolean ignoreFatOrphanFiles; private boolean ignoreFatOrphanFiles;
private String md5;
private String sha1;
private String sha256;
private boolean setDataSourceOptionsCalled; private boolean setDataSourceOptionsCalled;
static { static {
@ -74,7 +78,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour
filtersList.add(encaseFilter); filtersList.add(encaseFilter);
allExt.addAll(GeneralFilter.RAW_IMAGE_EXTS); allExt.addAll(GeneralFilter.RAW_IMAGE_EXTS);
allExt.addAll(GeneralFilter.ENCASE_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); filtersList.add(virtualMachineFilter);
allExt.addAll(GeneralFilter.VIRTUAL_MACHINE_EXTS); allExt.addAll(GeneralFilter.VIRTUAL_MACHINE_EXTS);
} }
@ -89,10 +93,10 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour
public ImageDSProcessor() { public ImageDSProcessor() {
configPanel = ImageFilePanel.createInstance(ImageDSProcessor.class.getName(), filtersList); configPanel = ImageFilePanel.createInstance(ImageDSProcessor.class.getName(), filtersList);
} }
/** /**
* Get the list of file filters supported by this DSP. * Get the list of file filters supported by this DSP.
* *
* @return A list of all supported file filters. * @return A list of all supported file filters.
*/ */
static List<FileFilter> getFileFiltersList() { static List<FileFilter> getFileFiltersList() {
@ -172,8 +176,20 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour
sectorSize = configPanel.getSectorSize(); sectorSize = configPanel.getSectorSize();
timeZone = configPanel.getTimeZone(); timeZone = configPanel.getTimeZone();
ignoreFatOrphanFiles = configPanel.getNoFatOrphans(); 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. * @param callback Callback to call when processing is done.
*/ */
public void run(String deviceId, String imagePath, String timeZone, boolean ignoreFatOrphanFiles, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { 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. * java.util.TimeZone.getID.
* @param ignoreFatOrphanFiles Whether to parse orphans if the image has a * @param ignoreFatOrphanFiles Whether to parse orphans if the image has a
* FAT filesystem. * 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 * @param progressMonitor Progress monitor for reporting progress
* during processing. * during processing.
* @param callback Callback to call when processing is done. * @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) { 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, null, progressMonitor, callback); addImageTask = new AddImageTask(deviceId, imagePath, sectorSize, timeZone, ignoreFatOrphanFiles, md5, sha1, sha256, null, progressMonitor, callback);
new Thread(addImageTask).start(); new Thread(addImageTask).start();
} }
@ -267,12 +286,12 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour
@Override @Override
public int canProcess(Path dataSourcePath) throws AutoIngestDataSourceProcessorException { public int canProcess(Path dataSourcePath) throws AutoIngestDataSourceProcessorException {
// check file extension for supported types // check file extension for supported types
if (!isAcceptedByFiler(dataSourcePath.toFile(), filtersList)) { if (!isAcceptedByFiler(dataSourcePath.toFile(), filtersList)) {
return 0; return 0;
} }
try { try {
// verify that the image has a file system that TSK can process // verify that the image has a file system that TSK can process
Case currentCase = Case.getCurrentCaseThrows(); Case currentCase = Case.getCurrentCaseThrows();
@ -283,7 +302,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour
} catch (Exception ex) { } catch (Exception ex) {
throw new AutoIngestDataSourceProcessorException("Exception inside canProcess() method", ex); throw new AutoIngestDataSourceProcessorException("Exception inside canProcess() method", ex);
} }
// able to process the data source // able to process the data source
return 100; return 100;
} }
@ -296,9 +315,9 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour
this.timeZone = Calendar.getInstance().getTimeZone().getID(); this.timeZone = Calendar.getInstance().getTimeZone().getID();
this.ignoreFatOrphanFiles = false; this.ignoreFatOrphanFiles = false;
setDataSourceOptionsCalled = true; 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 * Sets the configuration of the data source processor without using the
* selection and configuration panel. * selection and configuration panel.
@ -321,5 +340,5 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour
this.ignoreFatOrphanFiles = ignoreFatOrphanFiles; this.ignoreFatOrphanFiles = ignoreFatOrphanFiles;
setDataSourceOptionsCalled = true; setDataSourceOptionsCalled = true;
} }
} }

View File

@ -33,7 +33,7 @@
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="pathLabel" min="-2" max="-2" attributes="0"/> <Component id="pathLabel" min="-2" max="-2" attributes="0"/>
<Component id="pathErrorLabel" alignment="0" min="-2" max="-2" attributes="0"/> <Component id="errorLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="noFatOrphansCheckbox" alignment="0" min="-2" max="-2" attributes="0"/> <Component id="noFatOrphansCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/> <EmptySpace min="0" pref="0" max="32767" attributes="0"/>
@ -54,7 +54,7 @@
<Component id="sha1HashTextField" min="-2" pref="287" max="-2" attributes="0"/> <Component id="sha1HashTextField" min="-2" pref="287" max="-2" attributes="0"/>
<Component id="sha256HashTextField" min="-2" pref="455" max="-2" attributes="0"/> <Component id="sha256HashTextField" min="-2" pref="455" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace pref="-237" max="32767" attributes="0"/> <EmptySpace pref="11" max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -67,8 +67,6 @@
<Component id="browseButton" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="browseButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="pathTextField" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="pathTextField" alignment="3" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
<Component id="pathErrorLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/> <EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="noFatOrphansCheckbox" min="-2" max="-2" attributes="0"/> <Component id="noFatOrphansCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/> <EmptySpace type="unrelated" max="-2" attributes="0"/>
@ -96,7 +94,9 @@
<Component id="sha256HashTextField" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="sha256HashTextField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="sha256HashLabel" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="sha256HashLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace max="32767" attributes="0"/> <EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="errorLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="45" max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -154,13 +154,13 @@
</Property> </Property>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JLabel" name="pathErrorLabel"> <Component class="javax.swing.JLabel" name="errorLabel">
<Properties> <Properties>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor"> <Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="ff" type="rgb"/> <Color blue="0" green="0" red="ff" type="rgb"/>
</Property> </Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="ImageFilePanel.pathErrorLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="ImageFilePanel.errorLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
</Properties> </Properties>
</Component> </Component>

View File

@ -21,23 +21,21 @@ package org.sleuthkit.autopsy.casemodule;
import java.io.File; import java.io.File;
import java.util.Calendar; import java.util.Calendar;
import java.util.List; import java.util.List;
import java.util.logging.Level;
import javax.swing.JFileChooser; import javax.swing.JFileChooser;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener; import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileFilter;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import static org.sleuthkit.autopsy.casemodule.Bundle.*;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.coreutils.DriveUtils; 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.ModuleSettings;
import org.sleuthkit.autopsy.coreutils.PathValidator; import org.sleuthkit.autopsy.coreutils.PathValidator;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; 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 * 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 @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class ImageFilePanel extends JPanel implements DocumentListener { 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 PROP_LASTIMAGE_PATH = "LBL_LastImage_PATH"; //NON-NLS
private static final String[] SECTOR_SIZE_CHOICES = {"Auto Detect", "512", "1024", "2048", "4096"}; private static final String[] SECTOR_SIZE_CHOICES = {"Auto Detect", "512", "1024", "2048", "4096"};
private final JFileChooser fileChooser = new JFileChooser(); private final JFileChooser fileChooser = new JFileChooser();
/**
* Externally supplied name is used to store settings
*/
private final String contextName; private final String contextName;
/** /**
@ -79,7 +72,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
} }
sectorSizeComboBox.setSelectedIndex(0); sectorSizeComboBox.setSelectedIndex(0);
pathErrorLabel.setVisible(false); errorLabel.setVisible(false);
fileChooser.setDragEnabled(false); fileChooser.setDragEnabled(false);
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
@ -117,10 +110,29 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
public static synchronized ImageFilePanel createInstance(String context, List<FileFilter> fileChooserFilters) { public static synchronized ImageFilePanel createInstance(String context, List<FileFilter> fileChooserFilters) {
ImageFilePanel instance = new ImageFilePanel(context, fileChooserFilters); ImageFilePanel instance = new ImageFilePanel(context, fileChooserFilters);
// post-constructor initialization of listener support without leaking references of uninitialized objects // 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; 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. * This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always * WARNING: Do NOT modify this code. The content of this method is always
@ -135,7 +147,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
timeZoneLabel = new javax.swing.JLabel(); timeZoneLabel = new javax.swing.JLabel();
timeZoneComboBox = new javax.swing.JComboBox<>(); timeZoneComboBox = new javax.swing.JComboBox<>();
noFatOrphansCheckbox = new javax.swing.JCheckBox(); noFatOrphansCheckbox = new javax.swing.JCheckBox();
pathErrorLabel = new javax.swing.JLabel(); errorLabel = new javax.swing.JLabel();
sectorSizeLabel = new javax.swing.JLabel(); sectorSizeLabel = new javax.swing.JLabel();
sectorSizeComboBox = new javax.swing.JComboBox<>(); sectorSizeComboBox = new javax.swing.JComboBox<>();
sha256HashLabel = new javax.swing.JLabel(); 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 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 noFatOrphansCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.noFatOrphansCheckbox.toolTipText")); // NOI18N
pathErrorLabel.setForeground(new java.awt.Color(255, 0, 0)); errorLabel.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 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 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.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(pathLabel) .addComponent(pathLabel)
.addComponent(pathErrorLabel) .addComponent(errorLabel)
.addComponent(noFatOrphansCheckbox)) .addComponent(noFatOrphansCheckbox))
.addGap(0, 0, Short.MAX_VALUE)) .addGap(0, 0, Short.MAX_VALUE))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .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(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(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)) .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.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 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) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(browseButton) .addComponent(browseButton)
.addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .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) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(noFatOrphansCheckbox) .addComponent(noFatOrphansCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .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) .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(sha256HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(sha256HashLabel)) .addComponent(sha256HashLabel))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addGap(18, 18, 18)
.addComponent(errorLabel)
.addContainerGap(45, Short.MAX_VALUE))
); );
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
@ -282,10 +294,10 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton browseButton; private javax.swing.JButton browseButton;
private javax.swing.JLabel errorLabel;
private javax.swing.JLabel md5HashLabel; private javax.swing.JLabel md5HashLabel;
private javax.swing.JTextField md5HashTextField; private javax.swing.JTextField md5HashTextField;
private javax.swing.JCheckBox noFatOrphansCheckbox; private javax.swing.JCheckBox noFatOrphansCheckbox;
private javax.swing.JLabel pathErrorLabel;
private javax.swing.JLabel pathLabel; private javax.swing.JLabel pathLabel;
private javax.swing.JTextField pathTextField; private javax.swing.JTextField pathTextField;
private javax.swing.JComboBox<String> sectorSizeComboBox; private javax.swing.JComboBox<String> sectorSizeComboBox;
@ -340,6 +352,18 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
return noFatOrphansCheckbox.isSelected(); return noFatOrphansCheckbox.isSelected();
} }
String getMd5() {
return this.md5HashTextField.getText();
}
String getSha1() {
return this.sha1HashTextField.getText();
}
String getSha256() {
return this.sha256HashTextField.getText();
}
public void reset() { public void reset() {
//reset the UI elements to default //reset the UI elements to default
pathTextField.setText(null); 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 * @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", @NbBundle.Messages({
"ImageFilePanel.pathValidation.getOpenCase.Error=Warning: Exception while getting open case." "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() { public boolean validatePanel() {
pathErrorLabel.setVisible(false); errorLabel.setVisible(false);
String path = getContentPaths(); String path = getContentPaths();
if (StringUtils.isBlank(path)) { if (StringUtils.isBlank(path) || (!(new File(path).isFile() || DriveUtils.isPhysicalDrive(path) || DriveUtils.isPartition(path)))) {
return false; return false;
} }
// Display warning if there is one (but don't disable "next" button) if (!StringUtils.isBlank(getMd5()) && !HashUtility.isValidMd5Hash(getMd5())) {
try { errorLabel.setVisible(true);
if (false == PathValidator.isValidForMultiUserCase(path, Case.getCurrentCaseThrows().getCaseType())) { errorLabel.setText(Bundle.ImageFilePanel_validatePanel_invalidMD5());
pathErrorLabel.setVisible(true); return false;
pathErrorLabel.setText(Bundle.ImageFilePanel_pathValidation_dataSourceOnCDriveError());
}
} catch (NoCurrentCaseException ex) {
pathErrorLabel.setVisible(true);
pathErrorLabel.setText(Bundle.ImageFilePanel_pathValidation_getOpenCase_Error());
} }
return new File(path).isFile() if (!StringUtils.isBlank(getSha1()) && !HashUtility.isValidSha1Hash(getSha1())) {
|| DriveUtils.isPhysicalDrive(path) errorLabel.setVisible(true);
|| DriveUtils.isPartition(path); 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() { 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." "ImageFilePanel.moduleErr.msg=A module caused an error listening to ImageFilePanel updates."
+ " See log to determine which module. Some data could be incomplete.\n"}) + " See log to determine which module. Some data could be incomplete.\n"})
private void updateHelper() { private void updateHelper() {
try { firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
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());
}
} }
/** /**

View File

@ -139,7 +139,7 @@ public class LocalDiskDSProcessor implements DataSourceProcessor {
imageWriterSettings = null; 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(); new Thread(addDiskTask).start();
} }
@ -191,7 +191,7 @@ public class LocalDiskDSProcessor implements DataSourceProcessor {
* @param callback Callback to call when processing is done. * @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) { 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(); new Thread(addDiskTask).start();
} }

View File

@ -25,7 +25,6 @@ import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import javax.xml.bind.DatatypeConverter; import javax.xml.bind.DatatypeConverter;
import java.util.Arrays; import java.util.Arrays;
import org.openide.util.Exceptions;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModule; import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress; import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
@ -266,12 +265,12 @@ public class DataSourceIntegrityIngestModule implements DataSourceIngestModule {
for (HashData hashData:hashDataList) { for (HashData hashData:hashDataList) {
if (hashData.storedHash.equals(hashData.calculatedHash)) { if (hashData.storedHash.equals(hashData.calculatedHash)) {
hashResults += Bundle.DataSourceIntegrityIngestModule_process_hashMatch(hashData.type.name); hashResults += Bundle.DataSourceIntegrityIngestModule_process_hashMatch(hashData.type.name) + " ";
} else { } else {
verified = false; 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, 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); hashResults += Bundle.DataSourceIntegrityIngestModule_process_hashList(hashData.calculatedHash, hashData.storedHash);
} }