Merge pull request #4910 from sleuthkit/release-4.12.0

Merge release 4.12.0 branch into develop branch
This commit is contained in:
Richard Cordovano 2019-06-18 10:23:19 -04:00 committed by GitHub
commit 3bec1a3aec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 5955 additions and 70 deletions

View File

@ -30,7 +30,6 @@ import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.imagewriter.ImageWriterSettings;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
@ -40,7 +39,7 @@ import org.sleuthkit.datamodel.TskCoreException;
* - add alert.txt and users.txt files to report * - add alert.txt and users.txt files to report
* - add an image data source to the case database. * - add an image data source to the case database.
*/ */
public class AddLogicalImageTask extends AddImageTask { public class AddLogicalImageTask extends AddMultipleImageTask {
private final static Logger logger = Logger.getLogger(AddLogicalImageTask.class.getName()); private final static Logger logger = Logger.getLogger(AddLogicalImageTask.class.getName());
private final static String ALERT_TXT = "alert.txt"; //NON-NLS private final static String ALERT_TXT = "alert.txt"; //NON-NLS
@ -50,16 +49,14 @@ public class AddLogicalImageTask extends AddImageTask {
private final DataSourceProcessorCallback callback; private final DataSourceProcessorCallback callback;
private final DataSourceProcessorProgressMonitor progressMonitor; private final DataSourceProcessorProgressMonitor progressMonitor;
public AddLogicalImageTask(String deviceId, String imagePath, int sectorSize, public AddLogicalImageTask(String deviceId,
String timeZone, boolean ignoreFatOrphanFiles, List<String> imagePaths,
String md5, String sha1, String sha256, String timeZone,
ImageWriterSettings imageWriterSettings,
File src, File dest, File src, File dest,
DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorProgressMonitor progressMonitor,
DataSourceProcessorCallback callback DataSourceProcessorCallback callback
) { ) throws NoCurrentCaseException {
super(deviceId, imagePath, sectorSize, timeZone, ignoreFatOrphanFiles, super(deviceId, imagePaths, timeZone, progressMonitor, callback);
md5, sha1, sha256, imageWriterSettings, progressMonitor, callback);
this.src = src; this.src = src;
this.dest = dest; this.dest = dest;
this.progressMonitor = progressMonitor; this.progressMonitor = progressMonitor;

View File

@ -0,0 +1,252 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.services.FileManager;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback.DataSourceProcessorResult;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.LocalFilesDataSource;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.SleuthkitJNI;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskDataException;
/**
*
* A runnable that adds multiple images to the case database
*
*/
@Messages({
"AddMultipleImageTask.fsTypeUnknownErr=Cannot determine file system type"
})
class AddMultipleImageTask implements Runnable {
private static final Logger LOGGER = Logger.getLogger(AddMultipleImageTask.class.getName());
public static final String TSK_FS_TYPE_UNKNOWN_ERR_MSG = Bundle.AddMultipleImageTask_fsTypeUnknownErr();
private final String deviceId;
private final List<String> imageFilePaths;
private final String timeZone;
private final DataSourceProcessorProgressMonitor progressMonitor;
private final DataSourceProcessorCallback callback;
private final Case currentCase;
private boolean criticalErrorOccurred;
private volatile boolean cancelled;
/**
* Constructs a runnable that adds multiple image files
* to a case database. If Sleuth Kit fails to find a filesystem
* in any of input image files, the file is added to the case as a
* local/logical file instead.
*
* @param deviceId An ASCII-printable identifier for the device
* associated with the data source that is intended
* to be unique across multiple cases (e.g., a UUID).
* @param imageFilePaths The paths of the multiple output files.
* @param timeZone The time zone to use when processing dates and
* times for the image, obtained from
* java.util.TimeZone.getID.
* @param progressMonitor Progress monitor for reporting progress during
* processing.
* @param callback Callback to call when processing is done.
* @throws NoCurrentCaseException The exception if there is no open case.
*/
@Messages({
"# {0} - file", "AddMultipleImageTask.addingFileAsLogicalFile=Adding: {0} as logical file",
"# {0} - deviceId", "# {1} - exceptionMessage",
"AddMultipleImageTask.errorAddingImgWithoutFileSystem=Error adding images without file systems for device %s: %s",
})
AddMultipleImageTask(String deviceId, List<String> imageFilePaths, String timeZone,
DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) throws NoCurrentCaseException {
this.deviceId = deviceId;
this.imageFilePaths = imageFilePaths;
this.timeZone = timeZone;
this.callback = callback;
this.progressMonitor = progressMonitor;
currentCase = Case.getCurrentCaseThrows();
}
@Override
public void run() {
/*
* Try to add the input image files as images.
*/
List<Content> newDataSources = new ArrayList<>();
List<String> localFileDataSourcePaths = new ArrayList<>();
List<String> errorMessages = new ArrayList<>();
currentCase.getSleuthkitCase().acquireSingleUserCaseWriteLock();
try {
progressMonitor.setIndeterminate(true);
for (String imageFilePath : imageFilePaths) {
if (!cancelled) {
addImageToCase(imageFilePath, newDataSources, localFileDataSourcePaths, errorMessages);
}
}
} finally {
currentCase.getSleuthkitCase().releaseSingleUserCaseWriteLock();
}
/*
* Try to add any input image files that did not have file systems as a
* single local/logical files set with the device id as the root virtual
* directory name.
*/
if (!cancelled && !localFileDataSourcePaths.isEmpty()) {
FileManager fileManager = currentCase.getServices().getFileManager();
FileManager.FileAddProgressUpdater progressUpdater = (final AbstractFile newFile) -> {
progressMonitor.setProgressText(Bundle.AddMultipleImageTask_addingFileAsLogicalFile(Paths.get(newFile.getParentPath(), newFile.getName())));
};
try {
LocalFilesDataSource localFilesDataSource = fileManager.addLocalFilesDataSource(deviceId, "", timeZone, localFileDataSourcePaths, progressUpdater);
newDataSources.add(localFilesDataSource);
} catch (TskCoreException | TskDataException ex) {
errorMessages.add(Bundle.AddMultipleImageTask_errorAddingImgWithoutFileSystem(deviceId, ex.getLocalizedMessage()));
criticalErrorOccurred = true;
}
}
/*
* This appears to be the best that can be done to indicate completion
* with the DataSourceProcessorProgressMonitor in its current form.
*/
progressMonitor.setProgress(0);
progressMonitor.setProgress(100);
/*
* Pass the results back via the callback.
*/
DataSourceProcessorResult result;
if (criticalErrorOccurred) {
result = DataSourceProcessorResult.CRITICAL_ERRORS;
} else if (!errorMessages.isEmpty()) {
result = DataSourceProcessorResult.NONCRITICAL_ERRORS;
} else {
result = DataSourceProcessorResult.NO_ERRORS;
}
callback.done(result, errorMessages, newDataSources);
criticalErrorOccurred = false;
}
/**
* Attempts to cancel the processing of the input image files. May result in
* partial processing of the input.
*/
public void cancelTask() {
LOGGER.log(Level.WARNING, "AddMultipleImageTask cancelled, processing may be incomplete"); // NON-NLS
cancelled = true;
}
/**
* Attempts to add an input image to the case.
*
* @param imageFilePath The image file path.
* @param newDataSources If the image is added, a data source is
* added to this list for eventual return to
* the caller via the callback.
* @param localFileDataSourcePaths If the image cannot be added because
* Sleuth Kit cannot detect a filesystem, the
* image file path is added to this list for
* later addition as a part of a
* local/logical files data source.
* @param errorMessages If there are any error messages, the
* error messages are added to this list for
* eventual return to the caller via the
* callback.
*/
@Messages({
"# {0} - imageFilePath", "AddMultipleImageTask.adding=Adding: {0}",
"# {0} - imageFilePath", "# {1} - deviceId", "# {2} - exceptionMessage", "AddMultipleImageTask.criticalErrorAdding=Critical error adding {0} for device {1}: {2}",
"# {0} - imageFilePath", "# {1} - deviceId", "# {2} - exceptionMessage", "AddMultipleImageTask.criticalErrorReverting=Critical error reverting add image process for {0} for device {1}: {2}",
"# {0} - imageFilePath", "# {1} - deviceId", "# {2} - exceptionMessage", "AddMultipleImageTask.nonCriticalErrorAdding=Non-critical error adding {0} for device {1}: {2}",
})
private void addImageToCase(String imageFilePath, List<Content> newDataSources, List<String> localFileDataSourcePaths, List<String> errorMessages) {
/*
* Try to add the image to the case database as a data source.
*/
progressMonitor.setProgressText(Bundle.AddMultipleImageTask_adding(imageFilePath));
SleuthkitCase caseDatabase = currentCase.getSleuthkitCase();
SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess = caseDatabase.makeAddImageProcess(timeZone, false, false, "");
try {
addImageProcess.run(deviceId, new String[]{imageFilePath});
} catch (TskCoreException ex) {
if (ex.getMessage().contains(TSK_FS_TYPE_UNKNOWN_ERR_MSG)) {
/*
* If Sleuth Kit failed to add the image because it did not find
* a file system, save the image path so it can be added to the
* case as part of a local/logical files data source. All other
* errors are critical.
*/
localFileDataSourcePaths.add(imageFilePath);
} else {
errorMessages.add(Bundle.AddMultipleImageTask_criticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
criticalErrorOccurred = true;
}
/*
* Either way, the add image process needs to be reverted.
*/
try {
addImageProcess.revert();
} catch (TskCoreException e) {
errorMessages.add(Bundle.AddMultipleImageTask_criticalErrorReverting(imageFilePath, deviceId, e.getLocalizedMessage()));
criticalErrorOccurred = true;
}
return;
} catch (TskDataException ex) {
errorMessages.add(Bundle.AddMultipleImageTask_nonCriticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
}
/*
* Try to commit the results of the add image process, retrieve the new
* image from the case database, and add it to the list of new data
* sources to be returned via the callback.
*/
try {
long imageId = addImageProcess.commit();
Image dataSource = caseDatabase.getImageById(imageId);
newDataSources.add(dataSource);
/*
* Verify the size of the new image. Note that it may not be what is
* expected, but at least part of it was added to the case.
*/
String verificationError = dataSource.verifyImageSize();
if (!verificationError.isEmpty()) {
errorMessages.add(Bundle.AddMultipleImageTask_nonCriticalErrorAdding(imageFilePath, deviceId, verificationError));
}
} catch (TskCoreException ex) {
/*
* The add image process commit failed or querying the case database
* for the newly added image failed. Either way, this is a critical
* error.
*/
errorMessages.add(Bundle.AddMultipleImageTask_criticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
criticalErrorOccurred = true;
}
}
}

View File

@ -14,6 +14,26 @@ AddLogicalImageTask.failedToAddReport=Failed to add report {0}. Reason= {1}
# {0} - src # {0} - src
# {1} - dest # {1} - dest
AddLogicalImageTask.failedToCopyDirectory=Failed to copy directory {0} to {1} AddLogicalImageTask.failedToCopyDirectory=Failed to copy directory {0} to {1}
# {0} - imageFilePath
AddMultipleImageTask.adding=Adding: {0}
# {0} - file
AddMultipleImageTask.addingFileAsLogicalFile=Adding: {0} as logical file
# {0} - imageFilePath
# {1} - deviceId
# {2} - exceptionMessage
AddMultipleImageTask.criticalErrorAdding=Critical error adding {0} for device {1}: {2}
# {0} - imageFilePath
# {1} - deviceId
# {2} - exceptionMessage
AddMultipleImageTask.criticalErrorReverting=Critical error reverting add image process for {0} for device {1}: {2}
# {0} - deviceId
# {1} - exceptionMessage
AddMultipleImageTask.errorAddingImgWithoutFileSystem=Error adding images without file systems for device %s: %s
AddMultipleImageTask.fsTypeUnknownErr=Cannot determine file system type
# {0} - imageFilePath
# {1} - deviceId
# {2} - exceptionMessage
AddMultipleImageTask.nonCriticalErrorAdding=Non-critical error adding {0} for device {1}: {2}
# {0} - exception message # {0} - exception message
Case.closeException.couldNotCloseCase=Error closing case: {0} Case.closeException.couldNotCloseCase=Error closing case: {0}
Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directory Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directory
@ -187,19 +207,21 @@ LogicalImagerDSProcessor.dataSourceType=Autopsy Imager
LogicalImagerDSProcessor.directoryAlreadyExists=Directory {0} already exists LogicalImagerDSProcessor.directoryAlreadyExists=Directory {0} already exists
# {0} - directory # {0} - directory
LogicalImagerDSProcessor.failToCreateDirectory=Failed to create directory {0} LogicalImagerDSProcessor.failToCreateDirectory=Failed to create directory {0}
# {0} - file
LogicalImagerDSProcessor.failToGetCanonicalPath=Fail to get canonical path for {0}
# {0} - imageDirPath # {0} - imageDirPath
LogicalImagerDSProcessor.imageDirPathNotFound={0} not found.\nUSB drive has been ejected. LogicalImagerDSProcessor.imageDirPathNotFound={0} not found.\nUSB drive has been ejected.
LogicalImagerDSProcessor.noCurrentCase=No current case
LogicalImagerPanel.imageTable.columnModel.title0=Hostname LogicalImagerPanel.imageTable.columnModel.title0=Hostname
LogicalImagerPanel.imageTable.columnModel.title1=Extracted Date LogicalImagerPanel.imageTable.columnModel.title1=Extracted Date
# {0} - sparseImageDirectory # {0} - sparseImageDirectory
# {1} - image LogicalImagerPanel.messageLabel.directoryDoesNotContainSparseImage=Directory {0} does not contain any images
LogicalImagerPanel.messageLabel.directoryDoesNotContainSparseImage=Directory {0} does not contain {1}
# {0} - invalidFormatDirectory # {0} - invalidFormatDirectory
LogicalImagerPanel.messageLabel.directoryFormatInvalid=Directory {0} does not match format Logical_Imager_HOSTNAME_yyyymmdd_HH_MM_SS LogicalImagerPanel.messageLabel.directoryFormatInvalid=Directory {0} does not match format Logical_Imager_HOSTNAME_yyyymmdd_HH_MM_SS
LogicalImagerPanel.messageLabel.driveHasNoImages=Drive has no images LogicalImagerPanel.messageLabel.driveHasNoImages=Drive has no images
LogicalImagerPanel.messageLabel.noExternalDriveFound=No drive found LogicalImagerPanel.messageLabel.noExternalDriveFound=No drive found
LogicalImagerPanel.messageLabel.noImageSelected=No image selected LogicalImagerPanel.messageLabel.noImageSelected=No image selected
LogicalImagerPanel.messageLabel.scanningExternalDrives=Scanning external drives for sparse_image.vhd ... LogicalImagerPanel.messageLabel.scanningExternalDrives=Scanning external drives for images ...
LogicalImagerPanel.selectAcquisitionFromDriveLabel.text=Select acquisition from Drive LogicalImagerPanel.selectAcquisitionFromDriveLabel.text=Select acquisition from Drive
Menu/Case/OpenRecentCase=Open Recent Case Menu/Case/OpenRecentCase=Open Recent Case
CTL_CaseDeleteAction=Delete Case CTL_CaseDeleteAction=Delete Case

View File

@ -19,6 +19,7 @@
package org.sleuthkit.autopsy.casemodule; package org.sleuthkit.autopsy.casemodule;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
@ -46,7 +47,6 @@ import org.sleuthkit.datamodel.Content;
public class LogicalImagerDSProcessor implements DataSourceProcessor { public class LogicalImagerDSProcessor implements DataSourceProcessor {
private static final String LOGICAL_IMAGER_DIR = "LogicalImager"; //NON-NLS private static final String LOGICAL_IMAGER_DIR = "LogicalImager"; //NON-NLS
private static final String SPARSE_IMAGE_VHD = "sparse_image.vhd"; //NON-NLS
private final LogicalImagerPanel configPanel; private final LogicalImagerPanel configPanel;
private AddLogicalImageTask addLogicalImageTask; private AddLogicalImageTask addLogicalImageTask;
@ -128,6 +128,8 @@ public class LogicalImagerDSProcessor implements DataSourceProcessor {
"# {0} - imageDirPath", "LogicalImagerDSProcessor.imageDirPathNotFound={0} not found.\nUSB drive has been ejected.", "# {0} - imageDirPath", "LogicalImagerDSProcessor.imageDirPathNotFound={0} not found.\nUSB drive has been ejected.",
"# {0} - directory", "LogicalImagerDSProcessor.failToCreateDirectory=Failed to create directory {0}", "# {0} - directory", "LogicalImagerDSProcessor.failToCreateDirectory=Failed to create directory {0}",
"# {0} - directory", "LogicalImagerDSProcessor.directoryAlreadyExists=Directory {0} already exists", "# {0} - directory", "LogicalImagerDSProcessor.directoryAlreadyExists=Directory {0} already exists",
"# {0} - file", "LogicalImagerDSProcessor.failToGetCanonicalPath=Fail to get canonical path for {0}",
"LogicalImagerDSProcessor.noCurrentCase=No current case",
}) })
@Override @Override
public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
@ -170,9 +172,31 @@ public class LogicalImagerDSProcessor implements DataSourceProcessor {
String deviceId = UUID.randomUUID().toString(); String deviceId = UUID.randomUUID().toString();
String timeZone = Calendar.getInstance().getTimeZone().getID(); String timeZone = Calendar.getInstance().getTimeZone().getID();
boolean ignoreFatOrphanFiles = false; boolean ignoreFatOrphanFiles = false;
run(deviceId, Paths.get(src.toString(), SPARSE_IMAGE_VHD).toString(), 0,
timeZone, ignoreFatOrphanFiles, null, null, null, src, dest, // Get all VHD files in the src directory
List<String> imagePaths = new ArrayList<>();
for (File f : src.listFiles()) {
if (f.getName().endsWith(".vhd")) {
try {
imagePaths.add(f.getCanonicalPath());
} catch (IOException ex) {
String msg = Bundle.LogicalImagerDSProcessor_failToGetCanonicalPath(f.getName());
errorList.add(msg);
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
return;
}
}
}
try {
run(deviceId, imagePaths,
timeZone, src, dest,
progressMonitor, callback); progressMonitor, callback);
} catch (NoCurrentCaseException ex) {
String msg = Bundle.LogicalImagerDSProcessor_noCurrentCase();
errorList.add(msg);
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
return;
}
} }
/** /**
@ -186,29 +210,21 @@ public class LogicalImagerDSProcessor implements DataSourceProcessor {
* associated with the data source that is * associated with the data source that is
* intended to be unique across multiple cases * intended to be unique across multiple cases
* (e.g., a UUID). * (e.g., a UUID).
* @param imagePath Path to the image file. * @param imagePaths Paths to the image files.
* @param sectorSize The sector size (use '0' for autodetect).
* @param timeZone The time zone to use when processing dates * @param timeZone The time zone to use when processing dates
* and times for the image, obtained from * and times for the image, obtained from
* java.util.TimeZone.getID. * 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 src The source directory of image. * @param src The source directory of image.
* @param dest The destination directory to copy the source. * @param dest The destination directory to copy the source.
* @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, private void run(String deviceId, List<String> imagePaths, String timeZone,
boolean ignoreFatOrphanFiles, String md5, String sha1, String sha256,
File src, File dest, File src, File dest,
DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback
) { ) throws NoCurrentCaseException {
addLogicalImageTask = new AddLogicalImageTask(deviceId, imagePath, sectorSize, addLogicalImageTask = new AddLogicalImageTask(deviceId, imagePaths, timeZone, src, dest,
timeZone, ignoreFatOrphanFiles, md5, sha1, sha256, null, src, dest,
progressMonitor, callback); progressMonitor, callback);
new Thread(addLogicalImageTask).start(); new Thread(addLogicalImageTask).start();
} }

View File

@ -72,7 +72,7 @@
<Component id="jScrollPane1" min="-2" pref="568" max="-2" attributes="0"/> <Component id="jScrollPane1" min="-2" pref="568" max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
<EmptySpace pref="14" max="32767" attributes="0"/> <EmptySpace pref="338" max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -89,7 +89,7 @@
<EmptySpace min="-2" max="-2" attributes="0"/> <EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="imageScrollPane" pref="0" max="32767" attributes="0"/> <Component id="imageScrollPane" pref="0" max="32767" attributes="0"/>
<Component id="driveListScrollPane" pref="186" max="32767" attributes="0"/> <Component id="driveListScrollPane" pref="461" max="32767" attributes="0"/>
</Group> </Group>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/> <EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Component id="refreshButton" min="-2" max="-2" attributes="0"/> <Component id="refreshButton" min="-2" max="-2" attributes="0"/>
@ -294,9 +294,6 @@
<Insets value="[0, 0, 0, 0]"/> <Insets value="[0, 0, 0, 0]"/>
</Property> </Property>
</Properties> </Properties>
<BindingProperties>
<BindingProperty name="editable" source="messageTextArea" sourcePath="false" target="messageTextArea" targetPath="editable" updateStrategy="0" immediately="false"/>
</BindingProperties>
</Component> </Component>
</SubComponents> </SubComponents>
</Container> </Container>

View File

@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.casemodule;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.io.File; import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException; import java.io.IOException;
import java.nio.file.FileStore; import java.nio.file.FileStore;
import java.nio.file.Files; import java.nio.file.Files;
@ -54,7 +55,6 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
public class LogicalImagerPanel extends JPanel implements DocumentListener { public class LogicalImagerPanel extends JPanel implements DocumentListener {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final String SPARSE_IMAGE_VHD = "sparse_image.vhd"; //NON-NLS
private static final String NO_IMAGE_SELECTED = Bundle.LogicalImagerPanel_messageLabel_noImageSelected(); private static final String NO_IMAGE_SELECTED = Bundle.LogicalImagerPanel_messageLabel_noImageSelected();
private static final String DRIVE_HAS_NO_IMAGES = Bundle.LogicalImagerPanel_messageLabel_driveHasNoImages(); private static final String DRIVE_HAS_NO_IMAGES = Bundle.LogicalImagerPanel_messageLabel_driveHasNoImages();
private static final String[] EMPTY_LIST_DATA = {}; private static final String[] EMPTY_LIST_DATA = {};
@ -100,7 +100,6 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener {
*/ */
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() { private void initComponents() {
bindingGroup = new org.jdesktop.beansbinding.BindingGroup();
buttonGroup1 = new javax.swing.ButtonGroup(); buttonGroup1 = new javax.swing.ButtonGroup();
browseButton = new javax.swing.JButton(); browseButton = new javax.swing.JButton();
@ -219,10 +218,6 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener {
messageTextArea.setDisabledTextColor(java.awt.Color.red); messageTextArea.setDisabledTextColor(java.awt.Color.red);
messageTextArea.setEnabled(false); messageTextArea.setEnabled(false);
messageTextArea.setMargin(new java.awt.Insets(0, 0, 0, 0)); messageTextArea.setMargin(new java.awt.Insets(0, 0, 0, 0));
org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, messageTextArea, org.jdesktop.beansbinding.ELProperty.create("false"), messageTextArea, org.jdesktop.beansbinding.BeanProperty.create("editable"));
bindingGroup.addBinding(binding);
jScrollPane1.setViewportView(messageTextArea); jScrollPane1.setViewportView(messageTextArea);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
@ -262,7 +257,7 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener {
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addContainerGap() .addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 568, javax.swing.GroupLayout.PREFERRED_SIZE))) .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 568, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addContainerGap(14, Short.MAX_VALUE)) .addContainerGap(338, Short.MAX_VALUE))
); );
layout.setVerticalGroup( layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -276,7 +271,7 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener {
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(imageScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) .addComponent(imageScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
.addComponent(driveListScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 186, Short.MAX_VALUE)) .addComponent(driveListScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 461, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(refreshButton) .addComponent(refreshButton)
.addGap(18, 18, 18) .addGap(18, 18, 18)
@ -293,8 +288,6 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener {
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 61, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 61, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(6, 6, 6)) .addGap(6, 6, 6))
); );
bindingGroup.bind();
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
public static String humanReadableByteCount(long bytes, boolean si) { public static String humanReadableByteCount(long bytes, boolean si) {
@ -309,8 +302,7 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener {
@Messages({ @Messages({
"# {0} - sparseImageDirectory", "# {0} - sparseImageDirectory",
"# {1} - image", "LogicalImagerPanel.messageLabel.directoryDoesNotContainSparseImage=Directory {0} does not contain any images",
"LogicalImagerPanel.messageLabel.directoryDoesNotContainSparseImage=Directory {0} does not contain {1}",
"# {0} - invalidFormatDirectory", "# {0} - invalidFormatDirectory",
"LogicalImagerPanel.messageLabel.directoryFormatInvalid=Directory {0} does not match format Logical_Imager_HOSTNAME_yyyymmdd_HH_MM_SS" "LogicalImagerPanel.messageLabel.directoryFormatInvalid=Directory {0} does not match format Logical_Imager_HOSTNAME_yyyymmdd_HH_MM_SS"
}) })
@ -324,9 +316,15 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener {
String path = fileChooser.getSelectedFile().getPath(); String path = fileChooser.getSelectedFile().getPath();
Matcher m = regex.matcher(path); Matcher m = regex.matcher(path);
if (m.find()) { if (m.find()) {
Path vhdPath = Paths.get(path, SPARSE_IMAGE_VHD); File dir = Paths.get(path).toFile();
if (!vhdPath.toFile().exists()) { String[] vhdFiles = dir.list(new FilenameFilter() {
setErrorMessage(Bundle.LogicalImagerPanel_messageLabel_directoryDoesNotContainSparseImage(path, SPARSE_IMAGE_VHD)); @Override
public boolean accept(File dir, String name) {
return name.endsWith(".vhd");
}
});
if (vhdFiles.length == 0) {
setErrorMessage(Bundle.LogicalImagerPanel_messageLabel_directoryDoesNotContainSparseImage(path));
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false); firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false);
return; return;
} }
@ -355,6 +353,16 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener {
} }
} }
private boolean dirHasVhdFiles(File dir) {
File[] fList = dir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".vhd");
}
});
return (fList != null && fList.length != 0);
}
private void driveListSelect() { private void driveListSelect() {
String selectedStr = driveList.getSelectedValue(); String selectedStr = driveList.getSelectedValue();
if (selectedStr == null) { if (selectedStr == null) {
@ -368,10 +376,9 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener {
imageTableModel = new ImageTableModel(); imageTableModel = new ImageTableModel();
int row = 0; int row = 0;
// Find all directories with name like Logical_Imager_HOSTNAME_yyyymmdd_HH_MM_SS // Find all directories with name like Logical_Imager_HOSTNAME_yyyymmdd_HH_MM_SS
// and has a sparse_image.vhd file in it // and has vhd files in it
for (File file : fList) { for (File file : fList) {
if (file.isDirectory() if (file.isDirectory() && dirHasVhdFiles(file)) {
&& Paths.get(driveLetter, file.getName(), SPARSE_IMAGE_VHD).toFile().exists()) {
String dir = file.getName(); String dir = file.getName();
Matcher m = regex.matcher(dir); Matcher m = regex.matcher(dir);
if (m.find()) { if (m.find()) {
@ -471,11 +478,11 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener {
}//GEN-LAST:event_importRadioButtonActionPerformed }//GEN-LAST:event_importRadioButtonActionPerformed
@Messages({ @Messages({
"LogicalImagerPanel.messageLabel.scanningExternalDrives=Scanning external drives for sparse_image.vhd ...", "LogicalImagerPanel.messageLabel.scanningExternalDrives=Scanning external drives for images ...",
"LogicalImagerPanel.messageLabel.noExternalDriveFound=No drive found" "LogicalImagerPanel.messageLabel.noExternalDriveFound=No drive found"
}) })
private void refreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshButtonActionPerformed private void refreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshButtonActionPerformed
// Scan external drives for sparse_image.vhd // Scan external drives for vhd images
clearImageTable(); clearImageTable();
setNormalMessage(Bundle.LogicalImagerPanel_messageLabel_scanningExternalDrives()); setNormalMessage(Bundle.LogicalImagerPanel_messageLabel_scanningExternalDrives());
List<String> listData = new ArrayList<>(); List<String> listData = new ArrayList<>();
@ -555,7 +562,6 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener {
private javax.swing.JLabel selectDriveLabel; private javax.swing.JLabel selectDriveLabel;
private javax.swing.JLabel selectFolderLabel; private javax.swing.JLabel selectFolderLabel;
private javax.swing.JLabel selectFromDriveLabel; private javax.swing.JLabel selectFromDriveLabel;
private org.jdesktop.beansbinding.BindingGroup bindingGroup;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
public void reset() { public void reset() {

View File

@ -0,0 +1,129 @@
ConfigureLogicalImagerDialog.loadButton.text=Load
ConfigureLogicalImagerDialog.newButton.text=New
ConfigureLogicalImagerDialog.title=Configure Logical Imager
ConfigureLogicalImagerDialog.saveButton.text=Save
ConfigureLogicalImagerDialog.configFile.text=
ConfigureLogicalImagerDialog.configFile.toolTipText=
ConfigureLogicalImagerDialog.jLabel1.text=Rule Set:
ConfigureLogicalImagerDialog.finalizeImageWriter.text=Finalize Image Writer
ConfigureLogicalImagerDialog.newRuleButton.text=New Rule
ConfigureLogicalImagerDialog.editRuleButton.text=Edit Rule
ConfigureLogicalImagerDialog.deleteRuleButton.text=Delete Rule
ConfigureLogicalImagerDialog.jLabel2.text=Rule Details
ConfigureLogicalImagerDialog.shouldSaveCheckBox.text=Should Save
ConfigureLogicalImagerDialog.shouldAlertCheckBox.text=Should Alert
ConfigureLogicalImagerDialog.jLabel3.text=Extensions:
ConfigureLogicalImagerDialog.extensionsTextField.text=
ConfigureLogicalImagerDialog.filenamesLabel.text=File names:
ConfigureLogicalImagerDialog.folderNamesLabel.text=Folder names:
ConfigureLogicalImagerDialog.jLabel4.text=File size:
ConfigureLogicalImagerDialog.daysIncludedLabel.text=day(s)
ConfigureLogicalImagerDialog.daysIncludedTextField.text=
ConfigureLogicalImagerDialog.modifiedDateLabel.text=Modified Within:
ConfigureLogicalImagerDialog.fullPathsLabel.text=Full paths:
ConfigureLogicalImagerDialog.flagEncryptionProgramsCheckBox.text=Flag encryption programs
EditRulePanel.shouldAlertCheckBox.text=Alert in imager console if rule matches
EditRulePanel.shouldSaveCheckBox.text=Extract file if it matches a rule
EditRulePanel.fullPathsLabel.text=Full paths:
EditRulePanel.daysIncludedLabel.text=day(s)
EditRulePanel.daysIncludedTextField.text=
EditRulePanel.modifiedDateLabel.text=Modified Within:
EditRulePanel.folderNamesLabel.text=Folder names:
EditRulePanel.filenamesLabel.text=File names:
EditRulePanel.extensionsTextField.text=
ConfigureLogicalImagerDialog.jLabel5.text=Rule Name:
ConfigureLogicalImagerDialog.jLabel6.text=Description:
ConfigureLogicalImagerDialog.ruleNameEditTextField.text=
ConfigureLogicalImagerDialog.descriptionEditTextField.text=
ConfigureLogicalImagerDialog.fullPathsTable.columnModel.title0=
ConfigVisualPanel1.jTextField1.text=
ConfigVisualPanel1.jLabel1.text=Configuration file
ConfigVisualPanel2.jCheckBox1.text=jCheckBox1
ConfigVisualPanel2.jCheckBox2.text=jCheckBox2
ConfigVisualPanel2.jTextField1.text=jTextField1
ConfigVisualPanel1.jRadioButton1.text=Create new configuration
ConfigVisualPanel1.jRadioButton2.text=Open existing configuration
ConfigVisualPanel1.jLabel1.text_1=Configuration file:
ConfigVisualPanel1.configFileTextField.text_1=
ConfigVisualPanel2.modifiedDateLabel.text=Modified Within:
ConfigVisualPanel2.folderNamesLabel.text=Folder names:
ConfigVisualPanel2.finalizeImageWriter.text=Continue imaging after searches are performed
ConfigVisualPanel2.filenamesLabel.text=File names:
ConfigVisualPanel2.extensionsTextField.text=
ConfigVisualPanel2.shouldAlertCheckBox.text=Alert in imager console if rule matches
ConfigVisualPanel2.shouldSaveCheckBox.text=Extract file if it matches a rule
ConfigVisualPanel2.deleteRuleButton.text=Delete Rule
ConfigVisualPanel2.descriptionEditTextField.text=
ConfigVisualPanel2.editRuleButton.text=Edit Rule
ConfigVisualPanel2.newRuleButton.text=New Rule
ConfigVisualPanel2.ruleNameEditTextField.text=
ConfigVisualPanel2.flagEncryptionProgramsCheckBox.text=Alert if encryption programs are found
ConfigVisualPanel2.fullPathsLabel.text=Full paths:
ConfigVisualPanel2.daysIncludedLabel.text=day(s)
ConfigVisualPanel2.daysIncludedTextField.text=
ConfigVisualPanel2.configFileTextField.toolTipText=
ConfigVisualPanel2.configFileTextField.text=
ConfigVisualPanel2.filenamesTable.columnModel.title0=
ConfigVisualPanel2.fileSizeLabel.text=File size in bytes:
ConfigVisualPanel2.extensionsLabel.text=Extensions:
ConfigVisualPanel2.descriptionLabel.text=Description:
ConfigVisualPanel2.ruleNameLabel.text=Rule Name:
ConfigVisualPanel2.ruleSetFileLabel.text=Configuration rule file:
EditRulePanel.ruleNameLabel.text=Rule Set:
EditRulePanel.descriptionTextField.text=
EditRulePanel.extensionsLabel.text=Extensions:
EditRulePanel.ruleNameTextField.text=
EditRulePanel.extensionsCheckBox.text=
EditRulePanel.filenamesCheckBox.text=
EditRulePanel.folderNamesCheckBox.text=
EditRulePanel.fullPathsCheckBox.text=
EditRulePanel.fileSizeCheckBox.text=
EditRulePanel.minDaysCheckBox.text=
EditRulePanel.fileSizeLabel.text=File size:
EditRulePanel.descriptionLabel.text=Description:
EditRulePanel.jTable1.columnModel.title3=Title 4
EditRulePanel.jTable1.columnModel.title2=Title 3
EditRulePanel.jTable1.columnModel.title1=Title 2
EditRulePanel.shouldAlertCheckBox.actionCommand=
EditFullPathsRulePanel.ruleNameLabel.text=Rule Name:
EditFullPathsRulePanel.descriptionLabel.text=Description:
EditFullPathsRulePanel.descriptionTextField.text=
EditFullPathsRulePanel.shouldAlertCheckBox.actionCommand=
EditFullPathsRulePanel.shouldAlertCheckBox.text=Alert in imager console if rule matches
EditFullPathsRulePanel.shouldSaveCheckBox.text=Extract file if it matches a rule
EditFullPathsRulePanel.ruleNameTextField.text=
EditFullPathsRulePanel.fullPathsLabel.text=Full paths:
EditFullPathsRulePanel.fullPathsLabel.toolTipText=
EditNonFullPathsRulePanel.ruleNameTextField.text=
EditNonFullPathsRulePanel.ruleNameLabel.text=Rule Name:
EditNonFullPathsRulePanel.descriptionLabel.text=Description:
EditNonFullPathsRulePanel.descriptionTextField.text=
EditNonFullPathsRulePanel.shouldSaveCheckBox.text=Extract file if it matches a rule
EditNonFullPathsRulePanel.daysIncludedLabel.text=day(s)
EditNonFullPathsRulePanel.modifiedDateLabel.text=Modified Within:
EditNonFullPathsRulePanel.fileSizeLabel.text=File size (bytes):
EditNonFullPathsRulePanel.folderNamesLabel.text=Folder names:
EditNonFullPathsRulePanel.filenamesLabel.text=File names:
EditNonFullPathsRulePanel.extensionsTextField.text=
EditNonFullPathsRulePanel.extensionsLabel.text=Extensions:
EditNonFullPathsRulePanel.shouldAlertCheckBox.actionCommand=
EditNonFullPathsRulePanel.shouldAlertCheckBox.text=Alert in imager console if rule matches
ConfigVisualPanel1.browseButton.text=Browse
ConfigVisualPanel2.fullPathsTable.columnModel.title0=
ConfigVisualPanel2.folderNamesTable.columnModel.title0=
ConfigVisualPanel2.shouldSaveCheckBox.toolTipText=
NewRuleSetPanel.chooseLabel.text=Choose the type of rule
EditNonFullPathsRulePanel.minSizeLabel.text=Minimum:
EditNonFullPathsRulePanel.maxSizeLabel.text=Maximum:
EditNonFullPathsRulePanel.minSizeTextField.text=
EditNonFullPathsRulePanel.maxSizeTextField.text=
ConfigVisualPanel2.maxSizeTextField.text=
ConfigVisualPanel2.maxSizeLabel.text=Maximum:
ConfigVisualPanel2.minSizeTextField.text=
ConfigVisualPanel2.minSizeLabel.text=Minimum:
EditNonFullPathsRulePanel.minDaysTextField.text=jFormattedTextField1
ConfigVisualPanel1.browseButton.toolTipText=
EditNonFullPathsRulePanel.extensionsRadioButton.text=
EditNonFullPathsRulePanel.filenamesRadioButton.text=
EditNonFullPathsRulePanel.extensionsRadioButton.toolTipText=Extensions and File names are mutually exclusive
EditNonFullPathsRulePanel.filenamesRadioButton.toolTipText=Extensions and File names are mutually exclusive

View File

@ -0,0 +1,180 @@
ConfigureLogicalImager.title=Configure Logical Imager
ConfigureLogicalImagerDialog.loadButton.text=Load
ConfigureLogicalImagerDialog.newButton.text=New
ConfigureLogicalImagerDialog.title=Configure Logical Imager
ConfigureLogicalImagerDialog.saveButton.text=Save
ConfigureLogicalImagerDialog.configFile.text=
ConfigureLogicalImagerDialog.configFile.toolTipText=
ConfigureLogicalImagerDialog.jLabel1.text=Rule Set:
ConfigureLogicalImagerDialog.finalizeImageWriter.text=Finalize Image Writer
ConfigureLogicalImagerDialog.newRuleButton.text=New Rule
ConfigureLogicalImagerDialog.editRuleButton.text=Edit Rule
ConfigureLogicalImagerDialog.deleteRuleButton.text=Delete Rule
ConfigureLogicalImagerDialog.jLabel2.text=Rule Details
ConfigureLogicalImagerDialog.shouldSaveCheckBox.text=Should Save
ConfigureLogicalImagerDialog.shouldAlertCheckBox.text=Should Alert
ConfigureLogicalImagerDialog.jLabel3.text=Extensions:
ConfigureLogicalImagerDialog.extensionsTextField.text=
ConfigureLogicalImagerDialog.filenamesLabel.text=File names:
ConfigureLogicalImagerDialog.folderNamesLabel.text=Folder names:
ConfigureLogicalImagerDialog.jLabel4.text=File size:
ConfigureLogicalImagerDialog.daysIncludedLabel.text=day(s)
ConfigureLogicalImagerDialog.daysIncludedTextField.text=
ConfigureLogicalImagerDialog.modifiedDateLabel.text=Modified Within:
ConfigureLogicalImagerDialog.fullPathsLabel.text=Full paths:
ConfigureLogicalImagerDialog.flagEncryptionProgramsCheckBox.text=Flag encryption programs
ConfigVisualPanel1.chooseFileTitle=Select a Logical Imager configuration
# {0} - filename
ConfigVisualPanel1.configFileIsEmpty=Configuration file {0} is empty
ConfigVisualPanel1.configurationError=Configuration error
ConfigVisualPanel1.fileNameExtensionFilter=Configuration JSON File
ConfigVisualPanel1.invalidConfigJson=Invalid config JSON:
ConfigVisualPanel1.selectConfigurationFile=Select configuration file
ConfigVisualPanel2.cancel=Cancel
ConfigVisualPanel2.deleteRuleSet=Delete rule
ConfigVisualPanel2.deleteRuleSetConfirmation=Delete rule confirmation
ConfigVisualPanel2.editConfiguration=Edit configuration
ConfigVisualPanel2.editRuleError=Edit rule error
ConfigVisualPanel2.editRuleSet=Edit rule
ConfigVisualPanel2.ok=OK
ConfigVisualPanel2.rulesTable.columnModel.title0=Rule Name
ConfigVisualPanel2.rulesTable.columnModel.title1=Description
# {0} - configFilename
ConfigWizardPanel2.failedToSaveConfigMsg=Failed to save configuration file: {0}
ConfigWizardPanel2.failedToSaveExeMsg=Failed to save tsk_logical_imager.exe file
# {0} - reason
ConfigWizardPanel2.reason=\nReason:
CTL_ConfigureLogicalImager=Configure Logical Imager
EditFullPathsRulePanel.example=Example:
EditFullPathsRulePanel.fullPaths=Full paths
EditNonFullPathsRulePanel.emptyExtensionException=Extensions cannot have an empty entry
EditNonFullPathsRulePanel.example=Example:
EditNonFullPathsRulePanel.fileNames=File names
EditNonFullPathsRulePanel.folderNames=Folder names
# {0} - message
EditNonFullPathsRulePanel.maxFileSizeMustBeNumberException=Maximum file size must be a number: {0}
EditNonFullPathsRulePanel.maxFileSizeNotPositiveException=Maximum file size must be a positive
# {0} - maxFileSize
# {1} - minFileSize
EditNonFullPathsRulePanel.maxFileSizeSmallerThanMinException=Maximum file size: {0} must be bigger than minimum file size: {1}
# {0} - message
EditNonFullPathsRulePanel.minFileSizeMustBeNumberException=Minimum file size must be a number: {0}
EditNonFullPathsRulePanel.minFileSizeNotPositiveException=Minimum file size must be a positive
# {0} - message
EditNonFullPathsRulePanel.modifiedDaysMustBeNumberException=Modified days must be a number: {0}
EditNonFullPathsRulePanel.modifiedDaysNotPositiveException=Modified days must be a positive
EditNonFullPathsRulePanel.note=NOTE: A special [USER_FOLDER] token at the the start of a folder name to allow matches of all user folders in the file system.
# {0} - fieldName
EditRulePanel.blankLineException={0} cannot have a blank line
EditRulePanel.shouldAlertCheckBox.text=Alert in imager console if rule matches
EditRulePanel.shouldSaveCheckBox.text=Extract file if it matches a rule
EditRulePanel.fullPathsLabel.text=Full paths:
EditRulePanel.daysIncludedLabel.text=day(s)
EditRulePanel.daysIncludedTextField.text=
EditRulePanel.modifiedDateLabel.text=Modified Within:
EditRulePanel.folderNamesLabel.text=Folder names:
EditRulePanel.filenamesLabel.text=File names:
EditRulePanel.extensionsTextField.text=
ConfigureLogicalImagerDialog.jLabel5.text=Rule Name:
ConfigureLogicalImagerDialog.jLabel6.text=Description:
ConfigureLogicalImagerDialog.ruleNameEditTextField.text=
ConfigureLogicalImagerDialog.descriptionEditTextField.text=
ConfigureLogicalImagerDialog.fullPathsTable.columnModel.title0=
ConfigVisualPanel1.jTextField1.text=
ConfigVisualPanel1.jLabel1.text=Configuration file
ConfigVisualPanel2.jCheckBox1.text=jCheckBox1
ConfigVisualPanel2.jCheckBox2.text=jCheckBox2
ConfigVisualPanel2.jTextField1.text=jTextField1
ConfigVisualPanel1.jRadioButton1.text=Create new configuration
ConfigVisualPanel1.jRadioButton2.text=Open existing configuration
ConfigVisualPanel1.jLabel1.text_1=Configuration file:
ConfigVisualPanel1.configFileTextField.text_1=
ConfigVisualPanel2.modifiedDateLabel.text=Modified Within:
ConfigVisualPanel2.folderNamesLabel.text=Folder names:
ConfigVisualPanel2.finalizeImageWriter.text=Continue imaging after searches are performed
ConfigVisualPanel2.filenamesLabel.text=File names:
ConfigVisualPanel2.extensionsTextField.text=
ConfigVisualPanel2.shouldAlertCheckBox.text=Alert in imager console if rule matches
ConfigVisualPanel2.shouldSaveCheckBox.text=Extract file if it matches a rule
ConfigVisualPanel2.deleteRuleButton.text=Delete Rule
ConfigVisualPanel2.descriptionEditTextField.text=
ConfigVisualPanel2.editRuleButton.text=Edit Rule
ConfigVisualPanel2.newRuleButton.text=New Rule
ConfigVisualPanel2.ruleNameEditTextField.text=
ConfigVisualPanel2.flagEncryptionProgramsCheckBox.text=Alert if encryption programs are found
ConfigVisualPanel2.fullPathsLabel.text=Full paths:
ConfigVisualPanel2.daysIncludedLabel.text=day(s)
ConfigVisualPanel2.daysIncludedTextField.text=
ConfigVisualPanel2.configFileTextField.toolTipText=
ConfigVisualPanel2.configFileTextField.text=
ConfigVisualPanel2.filenamesTable.columnModel.title0=
ConfigVisualPanel2.fileSizeLabel.text=File size in bytes:
ConfigVisualPanel2.extensionsLabel.text=Extensions:
ConfigVisualPanel2.descriptionLabel.text=Description:
ConfigVisualPanel2.ruleNameLabel.text=Rule Name:
ConfigVisualPanel2.ruleSetFileLabel.text=Configuration rule file:
EditRulePanel.ruleNameLabel.text=Rule Set:
EditRulePanel.descriptionTextField.text=
EditRulePanel.extensionsLabel.text=Extensions:
EditRulePanel.ruleNameTextField.text=
EditRulePanel.extensionsCheckBox.text=
EditRulePanel.filenamesCheckBox.text=
EditRulePanel.folderNamesCheckBox.text=
EditRulePanel.fullPathsCheckBox.text=
EditRulePanel.fileSizeCheckBox.text=
EditRulePanel.minDaysCheckBox.text=
EditRulePanel.fileSizeLabel.text=File size:
EditRulePanel.descriptionLabel.text=Description:
EditRulePanel.jTable1.columnModel.title3=Title 4
EditRulePanel.jTable1.columnModel.title2=Title 3
EditRulePanel.jTable1.columnModel.title1=Title 2
EditRulePanel.shouldAlertCheckBox.actionCommand=
EditFullPathsRulePanel.ruleNameLabel.text=Rule Name:
EditFullPathsRulePanel.descriptionLabel.text=Description:
EditFullPathsRulePanel.descriptionTextField.text=
EditFullPathsRulePanel.shouldAlertCheckBox.actionCommand=
EditFullPathsRulePanel.shouldAlertCheckBox.text=Alert in imager console if rule matches
EditFullPathsRulePanel.shouldSaveCheckBox.text=Extract file if it matches a rule
EditFullPathsRulePanel.ruleNameTextField.text=
EditFullPathsRulePanel.fullPathsLabel.text=Full paths:
EditFullPathsRulePanel.fullPathsLabel.toolTipText=
EditNonFullPathsRulePanel.ruleNameTextField.text=
EditNonFullPathsRulePanel.ruleNameLabel.text=Rule Name:
EditNonFullPathsRulePanel.descriptionLabel.text=Description:
EditNonFullPathsRulePanel.descriptionTextField.text=
EditNonFullPathsRulePanel.shouldSaveCheckBox.text=Extract file if it matches a rule
EditNonFullPathsRulePanel.daysIncludedLabel.text=day(s)
EditNonFullPathsRulePanel.modifiedDateLabel.text=Modified Within:
EditNonFullPathsRulePanel.fileSizeLabel.text=File size (bytes):
EditNonFullPathsRulePanel.folderNamesLabel.text=Folder names:
EditNonFullPathsRulePanel.filenamesLabel.text=File names:
EditNonFullPathsRulePanel.extensionsTextField.text=
EditNonFullPathsRulePanel.extensionsLabel.text=Extensions:
EditNonFullPathsRulePanel.shouldAlertCheckBox.actionCommand=
EditNonFullPathsRulePanel.shouldAlertCheckBox.text=Alert in imager console if rule matches
ConfigVisualPanel1.browseButton.text=Browse
ConfigVisualPanel2.fullPathsTable.columnModel.title0=
ConfigVisualPanel2.folderNamesTable.columnModel.title0=
ConfigVisualPanel2.shouldSaveCheckBox.toolTipText=
EditRulePanel.validateRuleNameExceptionMsg=Rule name cannot be empty
EncryptionProgramsRule.encryptionProgramsRuleDescription=Find encryption programs
EncryptionProgramsRule.encryptionProgramsRuleName=Encryption Programs
LogicalImagerConfigDeserializer.fullPathsException=A rule with full-paths cannot have other rule definitions
LogicalImagerConfigDeserializer.missingRuleSetException=Missing rule-set
# {0} - key
LogicalImagerConfigDeserializer.unsupportedKeyException=Unsupported key: {0}
NewRuleSetPanel.chooseLabel.text=Choose the type of rule
EditNonFullPathsRulePanel.minSizeLabel.text=Minimum:
EditNonFullPathsRulePanel.maxSizeLabel.text=Maximum:
EditNonFullPathsRulePanel.minSizeTextField.text=
EditNonFullPathsRulePanel.maxSizeTextField.text=
ConfigVisualPanel2.maxSizeTextField.text=
ConfigVisualPanel2.maxSizeLabel.text=Maximum:
ConfigVisualPanel2.minSizeTextField.text=
ConfigVisualPanel2.minSizeLabel.text=Minimum:
EditNonFullPathsRulePanel.minDaysTextField.text=jFormattedTextField1
ConfigVisualPanel1.browseButton.toolTipText=
EditNonFullPathsRulePanel.extensionsRadioButton.text=
EditNonFullPathsRulePanel.filenamesRadioButton.text=
EditNonFullPathsRulePanel.extensionsRadioButton.toolTipText=Extensions and File names are mutually exclusive
EditNonFullPathsRulePanel.filenamesRadioButton.toolTipText=Extensions and File names are mutually exclusive

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<NonVisualComponents>
<Component class="javax.swing.ButtonGroup" name="buttonGroup1">
</Component>
</NonVisualComponents>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="38" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
<Component id="configFileTextField" pref="279" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="browseButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="116" max="-2" attributes="0"/>
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="configFileTextField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="browseButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="141" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="jLabel1">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel1.jLabel1.text_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="configFileTextField">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel1.configFileTextField.text_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="browseButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel1.browseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel1.browseButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="browseButtonActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,242 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.configurelogicalimager;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonIOException;
import com.google.gson.JsonSyntaxException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
import org.openide.util.NbBundle;
/**
* Configuration Visual Panel 1
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public final class ConfigVisualPanel1 extends JPanel {
private LogicalImagerConfig config;
private String configFilename;
private boolean newFile = true;
/**
* Creates new form ConfigVisualPanel1
*/
public ConfigVisualPanel1() {
initComponents();
configFileTextField.getDocument().addDocumentListener(new MyDocumentListener(this));
}
@NbBundle.Messages({
"ConfigVisualPanel1.selectConfigurationFile=Select configuration file"
})
@Override
public String getName() {
return Bundle.ConfigVisualPanel1_selectConfigurationFile();
}
/**
* 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
* regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
buttonGroup1 = new javax.swing.ButtonGroup();
jLabel1 = new javax.swing.JLabel();
configFileTextField = new javax.swing.JTextField();
browseButton = new javax.swing.JButton();
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(ConfigVisualPanel1.class, "ConfigVisualPanel1.jLabel1.text_1")); // NOI18N
configFileTextField.setEditable(false);
configFileTextField.setText(org.openide.util.NbBundle.getMessage(ConfigVisualPanel1.class, "ConfigVisualPanel1.configFileTextField.text_1")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(ConfigVisualPanel1.class, "ConfigVisualPanel1.browseButton.text")); // NOI18N
browseButton.setToolTipText(org.openide.util.NbBundle.getMessage(ConfigVisualPanel1.class, "ConfigVisualPanel1.browseButton.toolTipText")); // NOI18N
browseButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
browseButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(38, 38, 38)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel1)
.addComponent(configFileTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 279, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(browseButton)
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(116, 116, 116)
.addComponent(jLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(configFileTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(browseButton))
.addContainerGap(141, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
@NbBundle.Messages({
"ConfigVisualPanel1.chooseFileTitle=Select a Logical Imager configuration"
})
private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
chooseFile(Bundle.ConfigVisualPanel1_chooseFileTitle());
}//GEN-LAST:event_browseButtonActionPerformed
@NbBundle.Messages({
"ConfigVisualPanel1.fileNameExtensionFilter=Configuration JSON File",
"ConfigVisualPanel1.invalidConfigJson=Invalid config JSON: ",
"ConfigVisualPanel1.configurationError=Configuration error",
})
private void chooseFile(String title) {
final String jsonExt = ".json"; // NON-NLS
JFileChooser fileChooser = new JFileChooser();
fileChooser.setDialogTitle(title);
fileChooser.setDragEnabled(false);
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
FileFilter filter = new FileNameExtensionFilter(Bundle.ConfigVisualPanel1_fileNameExtensionFilter(), new String[] {"json"}); // NON-NLS
fileChooser.setFileFilter(filter);
fileChooser.setSelectedFile(new File("config.json")); // default
fileChooser.setMultiSelectionEnabled(false);
if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
String path = fileChooser.getSelectedFile().getPath();
if (new File(path).exists()) {
try {
loadConfigFile(path);
configFilename = path;
configFileTextField.setText(path);
newFile = false;
} catch (JsonIOException | JsonSyntaxException | IOException ex) {
JOptionPane.showMessageDialog(this,
Bundle.ConfigVisualPanel1_invalidConfigJson() + ex.getMessage() ,
Bundle.ConfigVisualPanel1_configurationError(),
JOptionPane.ERROR_MESSAGE);
}
} else {
if (!path.endsWith(jsonExt)) {
path += jsonExt;
}
configFilename = path;
configFileTextField.setText(path);
config = new LogicalImagerConfig();
newFile = true;
}
}
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton browseButton;
private javax.swing.ButtonGroup buttonGroup1;
private javax.swing.JTextField configFileTextField;
private javax.swing.JLabel jLabel1;
// End of variables declaration//GEN-END:variables
@NbBundle.Messages({
"# {0} - filename",
"ConfigVisualPanel1.configFileIsEmpty=Configuration file {0} is empty",
})
private void loadConfigFile(String path) throws FileNotFoundException, JsonIOException, JsonSyntaxException, IOException {
try (FileInputStream is = new FileInputStream(path)) {
InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8);
GsonBuilder gsonBuilder = new GsonBuilder().setPrettyPrinting();
gsonBuilder.registerTypeAdapter(LogicalImagerConfig.class, new LogicalImagerConfigDeserializer());
Gson gson = gsonBuilder.create();
config = gson.fromJson(reader, LogicalImagerConfig.class);
if (config == null) {
// This happens if the file is empty. Gson doesn't call the deserializer and doesn't throw any exception.
throw new IOException(Bundle.ConfigVisualPanel1_configFileIsEmpty(path));
}
}
}
public LogicalImagerConfig getConfig() {
return config;
}
public String getConfigFilename() {
return configFilename;
}
public boolean isNewFile() {
return newFile;
}
void setConfigFilename(String filename) {
configFileTextField.setText(filename);
}
public boolean isPanelValid() {
return (newFile || !configFileTextField.getText().isEmpty());
}
/**
* Document Listener for textfield
*/
private static class MyDocumentListener implements DocumentListener {
private final ConfigVisualPanel1 panel;
public MyDocumentListener(ConfigVisualPanel1 aThis) {
this.panel = aThis;
}
@Override
public void insertUpdate(DocumentEvent e) {
fireChange();
}
@Override
public void removeUpdate(DocumentEvent e) {
fireChange();
}
@Override
public void changedUpdate(DocumentEvent e) {
fireChange();
}
private void fireChange() {
panel.firePropertyChange("UPDATE_UI", false, true); // NON-NLS
}
}
}

View File

@ -0,0 +1,604 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.6" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="480" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="daysIncludedTextField" min="-2" pref="54" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="daysIncludedLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Component id="ruleNameEditTextField" alignment="0" max="32767" attributes="0"/>
<Component id="descriptionEditTextField" alignment="0" max="32767" attributes="0"/>
<Component id="extensionsTextField" alignment="0" max="32767" attributes="0"/>
<Component id="jScrollPane5" alignment="0" max="32767" attributes="0"/>
<Component id="jScrollPane6" alignment="0" max="32767" attributes="0"/>
<Component id="jScrollPane7" alignment="0" max="32767" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="jScrollPane1" min="-2" pref="377" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="newRuleButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="editRuleButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="37" max="-2" attributes="0"/>
<Component id="deleteRuleButton" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="flagEncryptionProgramsCheckBox" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="finalizeImageWriter" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="393" pref="393" max="-2" attributes="0"/>
<Component id="shouldSaveCheckBox" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="397" pref="397" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="extensionsLabel" min="-2" max="-2" attributes="0"/>
<Component id="filenamesLabel" min="-2" max="-2" attributes="0"/>
<Component id="descriptionLabel" min="-2" max="-2" attributes="0"/>
<Component id="ruleNameLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Group type="102" attributes="0">
<EmptySpace min="397" pref="397" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="modifiedDateLabel" alignment="0" min="-2" pref="79" max="-2" attributes="0"/>
<Component id="fileSizeLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="fullPathsLabel" min="-2" max="-2" attributes="0"/>
<Component id="folderNamesLabel" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="4" max="-2" attributes="0"/>
<Component id="minSizeLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="minSizeTextField" min="-2" pref="63" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="maxSizeLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="maxSizeTextField" min="-2" pref="63" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="393" pref="393" max="-2" attributes="0"/>
<Component id="shouldAlertCheckBox" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="17" max="-2" attributes="0"/>
<Component id="ruleSetFileLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="configFileTextField" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<EmptySpace min="397" pref="397" max="-2" attributes="0"/>
<Component id="jSeparator1" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="configFileTextField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="ruleSetFileLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="jScrollPane1" pref="527" max="32767" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="newRuleButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="editRuleButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="deleteRuleButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="30" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="descriptionEditTextField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="descriptionLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="9" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="extensionsTextField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="extensionsLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Group type="103" alignment="0" groupAlignment="3" attributes="0">
<Component id="ruleNameEditTextField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="ruleNameLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane6" pref="0" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="filenamesLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane7" pref="0" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="folderNamesLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="fullPathsLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<Component id="jScrollPane5" pref="0" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="11" max="-2" attributes="0"/>
</Group>
</Group>
<Group type="103" groupAlignment="2" attributes="0">
<Component id="minSizeLabel" alignment="2" min="-2" max="-2" attributes="0"/>
<Component id="minSizeTextField" alignment="2" min="-2" max="-2" attributes="0"/>
<Component id="maxSizeLabel" alignment="2" min="-2" max="-2" attributes="0"/>
<Component id="maxSizeTextField" alignment="2" min="-2" max="-2" attributes="0"/>
<Component id="fileSizeLabel" alignment="2" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="2" attributes="0">
<Component id="modifiedDateLabel" alignment="2" min="-2" max="-2" attributes="0"/>
<Component id="daysIncludedTextField" alignment="2" min="-2" max="-2" attributes="0"/>
<Component id="daysIncludedLabel" alignment="2" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
<Component id="shouldAlertCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="shouldSaveCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="jSeparator1" min="-2" pref="2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="flagEncryptionProgramsCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="finalizeImageWriter" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="modifiedDateLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.modifiedDateLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="daysIncludedTextField">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="horizontalAlignment" type="int" value="11"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.daysIncludedTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[60, 20]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[60, 20]"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="daysIncludedLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.daysIncludedLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="fullPathsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.fullPathsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="flagEncryptionProgramsCheckBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.flagEncryptionProgramsCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="flagEncryptionProgramsCheckBoxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="ruleNameLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.ruleNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="ruleNameEditTextField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.ruleNameEditTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="newRuleButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/add16.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.newRuleButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="newRuleButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="descriptionLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.descriptionLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="editRuleButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/edit16.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.editRuleButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="editRuleButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JTextField" name="descriptionEditTextField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.descriptionEditTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="deleteRuleButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/delete16.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.deleteRuleButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="deleteRuleButtonActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane5">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTable" name="fullPathsTable">
<Properties>
<Property name="columnModel" type="javax.swing.table.TableColumnModel" editor="org.netbeans.modules.form.editors2.TableColumnModelEditor">
<TableColumnModel selectionModel="2">
<Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true">
<Title editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.fullPathsTable.columnModel.title0" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Title>
<Editor/>
<Renderer/>
</Column>
</TableColumnModel>
</Property>
<Property name="columnSelectionAllowed" type="boolean" value="true"/>
<Property name="enabled" type="boolean" value="false"/>
<Property name="selectionModel" type="javax.swing.ListSelectionModel" editor="org.netbeans.modules.form.editors2.JTableSelectionModelEditor">
<JTableSelectionModel selectionMode="0"/>
</Property>
<Property name="showHorizontalLines" type="boolean" value="false"/>
<Property name="showVerticalLines" type="boolean" value="false"/>
<Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor">
<TableHeader reorderingAllowed="false" resizingAllowed="true"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JScrollPane" name="jScrollPane6">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTable" name="filenamesTable">
<Properties>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<SerializedValue value="-84,-19,0,5,115,114,0,64,111,114,103,46,110,101,116,98,101,97,110,115,46,109,111,100,117,108,101,115,46,102,111,114,109,46,101,100,105,116,111,114,115,50,46,84,97,98,108,101,77,111,100,101,108,69,100,105,116,111,114,36,78,98,84,97,98,108,101,77,111,100,101,108,-95,8,-65,-35,21,111,108,-106,12,0,0,120,114,0,36,106,97,118,97,120,46,115,119,105,110,103,46,116,97,98,108,101,46,65,98,115,116,114,97,99,116,84,97,98,108,101,77,111,100,101,108,114,-53,-21,56,-82,1,-1,-66,2,0,1,76,0,12,108,105,115,116,101,110,101,114,76,105,115,116,116,0,37,76,106,97,118,97,120,47,115,119,105,110,103,47,101,118,101,110,116,47,69,118,101,110,116,76,105,115,116,101,110,101,114,76,105,115,116,59,120,112,119,8,0,0,0,0,0,0,0,1,117,114,0,19,91,76,106,97,118,97,46,108,97,110,103,46,83,116,114,105,110,103,59,-83,-46,86,-25,-23,29,123,71,2,0,0,120,112,0,0,0,1,116,0,0,117,114,0,2,91,90,87,-113,32,57,20,-72,93,-30,2,0,0,120,112,0,0,0,1,0,116,0,16,106,97,118,97,46,108,97,110,103,46,83,116,114,105,110,103,120"/>
</Property>
<Property name="columnModel" type="javax.swing.table.TableColumnModel" editor="org.netbeans.modules.form.editors2.TableColumnModelEditor">
<TableColumnModel selectionModel="0">
<Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true">
<Title editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.filenamesTable.columnModel.title0" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Title>
<Editor/>
<Renderer/>
</Column>
</TableColumnModel>
</Property>
<Property name="enabled" type="boolean" value="false"/>
<Property name="selectionModel" type="javax.swing.ListSelectionModel" editor="org.netbeans.modules.form.editors2.JTableSelectionModelEditor">
<JTableSelectionModel selectionMode="0"/>
</Property>
<Property name="showHorizontalLines" type="boolean" value="false"/>
<Property name="showVerticalLines" type="boolean" value="false"/>
<Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor">
<TableHeader reorderingAllowed="false" resizingAllowed="true"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JCheckBox" name="shouldSaveCheckBox">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.shouldSaveCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.shouldSaveCheckBox.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="shouldAlertCheckBox">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.shouldAlertCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane7">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTable" name="folderNamesTable">
<Properties>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<SerializedValue value="-84,-19,0,5,115,114,0,64,111,114,103,46,110,101,116,98,101,97,110,115,46,109,111,100,117,108,101,115,46,102,111,114,109,46,101,100,105,116,111,114,115,50,46,84,97,98,108,101,77,111,100,101,108,69,100,105,116,111,114,36,78,98,84,97,98,108,101,77,111,100,101,108,-95,8,-65,-35,21,111,108,-106,12,0,0,120,114,0,36,106,97,118,97,120,46,115,119,105,110,103,46,116,97,98,108,101,46,65,98,115,116,114,97,99,116,84,97,98,108,101,77,111,100,101,108,114,-53,-21,56,-82,1,-1,-66,2,0,1,76,0,12,108,105,115,116,101,110,101,114,76,105,115,116,116,0,37,76,106,97,118,97,120,47,115,119,105,110,103,47,101,118,101,110,116,47,69,118,101,110,116,76,105,115,116,101,110,101,114,76,105,115,116,59,120,112,119,8,0,0,0,0,0,0,0,0,117,114,0,19,91,76,106,97,118,97,46,108,97,110,103,46,83,116,114,105,110,103,59,-83,-46,86,-25,-23,29,123,71,2,0,0,120,112,0,0,0,0,117,114,0,2,91,90,87,-113,32,57,20,-72,93,-30,2,0,0,120,112,0,0,0,0,120"/>
</Property>
<Property name="columnModel" type="javax.swing.table.TableColumnModel" editor="org.netbeans.modules.form.editors2.TableColumnModelEditor">
<TableColumnModel selectionModel="0">
<Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true">
<Title editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.folderNamesTable.columnModel.title0" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Title>
<Editor/>
<Renderer/>
</Column>
</TableColumnModel>
</Property>
<Property name="enabled" type="boolean" value="false"/>
<Property name="selectionModel" type="javax.swing.ListSelectionModel" editor="org.netbeans.modules.form.editors2.JTableSelectionModelEditor">
<JTableSelectionModel selectionMode="0"/>
</Property>
<Property name="showHorizontalLines" type="boolean" value="false"/>
<Property name="showVerticalLines" type="boolean" value="false"/>
<Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor">
<TableHeader reorderingAllowed="false" resizingAllowed="true"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="extensionsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.extensionsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="extensionsTextField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.extensionsTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="filenamesLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.filenamesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="configFileTextField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.configFileTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.configFileTextField.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="ruleSetFileLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.ruleSetFileLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="finalizeImageWriter">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.finalizeImageWriter.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="finalizeImageWriterActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTable" name="rulesTable">
<Properties>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<SerializedValue value="-84,-19,0,5,115,114,0,64,111,114,103,46,110,101,116,98,101,97,110,115,46,109,111,100,117,108,101,115,46,102,111,114,109,46,101,100,105,116,111,114,115,50,46,84,97,98,108,101,77,111,100,101,108,69,100,105,116,111,114,36,78,98,84,97,98,108,101,77,111,100,101,108,-95,8,-65,-35,21,111,108,-106,12,0,0,120,114,0,36,106,97,118,97,120,46,115,119,105,110,103,46,116,97,98,108,101,46,65,98,115,116,114,97,99,116,84,97,98,108,101,77,111,100,101,108,114,-53,-21,56,-82,1,-1,-66,2,0,1,76,0,12,108,105,115,116,101,110,101,114,76,105,115,116,116,0,37,76,106,97,118,97,120,47,115,119,105,110,103,47,101,118,101,110,116,47,69,118,101,110,116,76,105,115,116,101,110,101,114,76,105,115,116,59,120,112,119,8,0,0,0,0,0,0,0,2,117,114,0,19,91,76,106,97,118,97,46,108,97,110,103,46,83,116,114,105,110,103,59,-83,-46,86,-25,-23,29,123,71,2,0,0,120,112,0,0,0,2,116,0,9,82,117,108,101,32,78,97,109,101,116,0,11,68,101,115,99,114,105,112,116,105,111,110,117,114,0,2,91,90,87,-113,32,57,20,-72,93,-30,2,0,0,120,112,0,0,0,2,0,0,116,0,16,106,97,118,97,46,108,97,110,103,46,83,116,114,105,110,103,113,0,126,0,10,120"/>
</Property>
<Property name="autoResizeMode" type="int" value="4"/>
<Property name="columnModel" type="javax.swing.table.TableColumnModel" editor="org.netbeans.modules.form.editors2.TableColumnModelEditor">
<TableColumnModel selectionModel="0">
<Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true">
<Title editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.rulesTable.columnModel.title0" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Title>
<Editor/>
<Renderer/>
</Column>
<Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true">
<Title editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.rulesTable.columnModel.title1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Title>
<Editor/>
<Renderer/>
</Column>
</TableColumnModel>
</Property>
<Property name="selectionModel" type="javax.swing.ListSelectionModel" editor="org.netbeans.modules.form.editors2.JTableSelectionModelEditor">
<JTableSelectionModel selectionMode="0"/>
</Property>
<Property name="showHorizontalLines" type="boolean" value="false"/>
<Property name="showVerticalLines" type="boolean" value="false"/>
<Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor">
<TableHeader reorderingAllowed="false" resizingAllowed="true"/>
</Property>
</Properties>
<Events>
<EventHandler event="mouseReleased" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="rulesTableMouseReleased"/>
<EventHandler event="keyReleased" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="rulesTableKeyReleased"/>
</Events>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="folderNamesLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.folderNamesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="fileSizeLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.fileSizeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JSeparator" name="jSeparator1">
</Component>
<Component class="javax.swing.JLabel" name="minSizeLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.minSizeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JFormattedTextField" name="minSizeTextField">
<Properties>
<Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.editors.AbstractFormatterFactoryEditor">
<Format format="#,###; " subtype="-1" type="0"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.minSizeTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="maxSizeLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.maxSizeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JFormattedTextField" name="maxSizeTextField">
<Properties>
<Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.editors.AbstractFormatterFactoryEditor">
<Format format="#,###; " subtype="-1" type="0"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="ConfigVisualPanel2.maxSizeTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,900 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.configurelogicalimager;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.openide.util.NbBundle;
/**
* Configuration Visual Panel 2
*/
@NbBundle.Messages({
"ConfigVisualPanel2.ok=OK",
"ConfigVisualPanel2.cancel=Cancel"
})
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public final class ConfigVisualPanel2 extends JPanel {
private static final List<String> EMPTY_LIST = new ArrayList<>();
private String configFilename;
private LogicalImagerConfig config = null;
private final JButton okButton = new JButton(Bundle.ConfigVisualPanel2_ok());
private final JButton cancelButton = new JButton(Bundle.ConfigVisualPanel2_cancel());
private boolean flagEncryptionPrograms = false;
/**
* Creates new form ConfigVisualPanel2
*/
public ConfigVisualPanel2() {
initComponents();
if (config != null) {
updatePanel(configFilename, config);
}
}
@NbBundle.Messages({
"ConfigVisualPanel2.editConfiguration=Edit configuration"
})
@Override
public String getName() {
return Bundle.ConfigVisualPanel2_editConfiguration();
}
/**
* 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
* regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
modifiedDateLabel = new javax.swing.JLabel();
daysIncludedTextField = new javax.swing.JTextField();
daysIncludedLabel = new javax.swing.JLabel();
fullPathsLabel = new javax.swing.JLabel();
flagEncryptionProgramsCheckBox = new javax.swing.JCheckBox();
ruleNameLabel = new javax.swing.JLabel();
ruleNameEditTextField = new javax.swing.JTextField();
newRuleButton = new javax.swing.JButton();
descriptionLabel = new javax.swing.JLabel();
editRuleButton = new javax.swing.JButton();
descriptionEditTextField = new javax.swing.JTextField();
deleteRuleButton = new javax.swing.JButton();
jScrollPane5 = new javax.swing.JScrollPane();
fullPathsTable = new javax.swing.JTable();
jScrollPane6 = new javax.swing.JScrollPane();
filenamesTable = new javax.swing.JTable();
shouldSaveCheckBox = new javax.swing.JCheckBox();
shouldAlertCheckBox = new javax.swing.JCheckBox();
jScrollPane7 = new javax.swing.JScrollPane();
folderNamesTable = new javax.swing.JTable();
extensionsLabel = new javax.swing.JLabel();
extensionsTextField = new javax.swing.JTextField();
filenamesLabel = new javax.swing.JLabel();
configFileTextField = new javax.swing.JTextField();
ruleSetFileLabel = new javax.swing.JLabel();
finalizeImageWriter = new javax.swing.JCheckBox();
jScrollPane1 = new javax.swing.JScrollPane();
rulesTable = new javax.swing.JTable();
folderNamesLabel = new javax.swing.JLabel();
fileSizeLabel = new javax.swing.JLabel();
jSeparator1 = new javax.swing.JSeparator();
minSizeLabel = new javax.swing.JLabel();
minSizeTextField = new javax.swing.JFormattedTextField();
maxSizeLabel = new javax.swing.JLabel();
maxSizeTextField = new javax.swing.JFormattedTextField();
org.openide.awt.Mnemonics.setLocalizedText(modifiedDateLabel, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.modifiedDateLabel.text")); // NOI18N
daysIncludedTextField.setEditable(false);
daysIncludedTextField.setHorizontalAlignment(javax.swing.JTextField.TRAILING);
daysIncludedTextField.setText(org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.daysIncludedTextField.text")); // NOI18N
daysIncludedTextField.setEnabled(false);
daysIncludedTextField.setMinimumSize(new java.awt.Dimension(60, 20));
daysIncludedTextField.setPreferredSize(new java.awt.Dimension(60, 20));
org.openide.awt.Mnemonics.setLocalizedText(daysIncludedLabel, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.daysIncludedLabel.text")); // NOI18N
daysIncludedLabel.setEnabled(false);
org.openide.awt.Mnemonics.setLocalizedText(fullPathsLabel, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.fullPathsLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(flagEncryptionProgramsCheckBox, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.flagEncryptionProgramsCheckBox.text")); // NOI18N
flagEncryptionProgramsCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
flagEncryptionProgramsCheckBoxActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(ruleNameLabel, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.ruleNameLabel.text")); // NOI18N
ruleNameEditTextField.setText(org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.ruleNameEditTextField.text")); // NOI18N
ruleNameEditTextField.setEnabled(false);
newRuleButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add16.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(newRuleButton, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.newRuleButton.text")); // NOI18N
newRuleButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
newRuleButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.descriptionLabel.text")); // NOI18N
editRuleButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/edit16.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(editRuleButton, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.editRuleButton.text")); // NOI18N
editRuleButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
editRuleButtonActionPerformed(evt);
}
});
descriptionEditTextField.setText(org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.descriptionEditTextField.text")); // NOI18N
descriptionEditTextField.setEnabled(false);
deleteRuleButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/delete16.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(deleteRuleButton, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.deleteRuleButton.text")); // NOI18N
deleteRuleButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
deleteRuleButtonActionPerformed(evt);
}
});
fullPathsTable.setColumnSelectionAllowed(true);
fullPathsTable.setEnabled(false);
fullPathsTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
fullPathsTable.setShowHorizontalLines(false);
fullPathsTable.setShowVerticalLines(false);
fullPathsTable.getTableHeader().setReorderingAllowed(false);
jScrollPane5.setViewportView(fullPathsTable);
fullPathsTable.getColumnModel().getSelectionModel().setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION);
if (fullPathsTable.getColumnModel().getColumnCount() > 0) {
fullPathsTable.getColumnModel().getColumn(0).setHeaderValue(org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.fullPathsTable.columnModel.title0")); // NOI18N
}
filenamesTable.setEnabled(false);
filenamesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
filenamesTable.setShowHorizontalLines(false);
filenamesTable.setShowVerticalLines(false);
filenamesTable.getTableHeader().setReorderingAllowed(false);
jScrollPane6.setViewportView(filenamesTable);
if (filenamesTable.getColumnModel().getColumnCount() > 0) {
filenamesTable.getColumnModel().getColumn(0).setHeaderValue(org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.filenamesTable.columnModel.title0")); // NOI18N
}
shouldSaveCheckBox.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(shouldSaveCheckBox, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.shouldSaveCheckBox.text")); // NOI18N
shouldSaveCheckBox.setToolTipText(org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.shouldSaveCheckBox.toolTipText")); // NOI18N
shouldSaveCheckBox.setEnabled(false);
shouldAlertCheckBox.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(shouldAlertCheckBox, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.shouldAlertCheckBox.text")); // NOI18N
shouldAlertCheckBox.setEnabled(false);
folderNamesTable.setEnabled(false);
folderNamesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
folderNamesTable.setShowHorizontalLines(false);
folderNamesTable.setShowVerticalLines(false);
folderNamesTable.getTableHeader().setReorderingAllowed(false);
jScrollPane7.setViewportView(folderNamesTable);
if (folderNamesTable.getColumnModel().getColumnCount() > 0) {
folderNamesTable.getColumnModel().getColumn(0).setHeaderValue(org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.folderNamesTable.columnModel.title0")); // NOI18N
}
org.openide.awt.Mnemonics.setLocalizedText(extensionsLabel, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.extensionsLabel.text")); // NOI18N
extensionsTextField.setText(org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.extensionsTextField.text")); // NOI18N
extensionsTextField.setEnabled(false);
org.openide.awt.Mnemonics.setLocalizedText(filenamesLabel, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.filenamesLabel.text")); // NOI18N
configFileTextField.setText(org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.configFileTextField.text")); // NOI18N
configFileTextField.setToolTipText(org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.configFileTextField.toolTipText")); // NOI18N
configFileTextField.setEnabled(false);
org.openide.awt.Mnemonics.setLocalizedText(ruleSetFileLabel, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.ruleSetFileLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(finalizeImageWriter, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.finalizeImageWriter.text")); // NOI18N
finalizeImageWriter.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
finalizeImageWriterActionPerformed(evt);
}
});
rulesTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS);
rulesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
rulesTable.setShowHorizontalLines(false);
rulesTable.setShowVerticalLines(false);
rulesTable.getTableHeader().setReorderingAllowed(false);
rulesTable.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseReleased(java.awt.event.MouseEvent evt) {
rulesTableMouseReleased(evt);
}
});
rulesTable.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyReleased(java.awt.event.KeyEvent evt) {
rulesTableKeyReleased(evt);
}
});
jScrollPane1.setViewportView(rulesTable);
if (rulesTable.getColumnModel().getColumnCount() > 0) {
rulesTable.getColumnModel().getColumn(0).setHeaderValue(org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.rulesTable.columnModel.title0")); // NOI18N
rulesTable.getColumnModel().getColumn(1).setHeaderValue(org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.rulesTable.columnModel.title1")); // NOI18N
}
org.openide.awt.Mnemonics.setLocalizedText(folderNamesLabel, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.folderNamesLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(fileSizeLabel, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.fileSizeLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(minSizeLabel, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.minSizeLabel.text")); // NOI18N
minSizeTextField.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter(new java.text.DecimalFormat("#,###; "))));
minSizeTextField.setText(org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.minSizeTextField.text")); // NOI18N
minSizeTextField.setEnabled(false);
org.openide.awt.Mnemonics.setLocalizedText(maxSizeLabel, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.maxSizeLabel.text")); // NOI18N
maxSizeTextField.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter(new java.text.DecimalFormat("#,###; "))));
maxSizeTextField.setText(org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.maxSizeTextField.text")); // NOI18N
maxSizeTextField.setEnabled(false);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(480, 480, 480)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(daysIncludedTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(daysIncludedLabel))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(ruleNameEditTextField, javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(descriptionEditTextField, javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(extensionsTextField, javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane5, javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane6, javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane7, javax.swing.GroupLayout.Alignment.LEADING))
.addContainerGap())))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 377, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(layout.createSequentialGroup()
.addComponent(newRuleButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(editRuleButton)
.addGap(37, 37, 37)
.addComponent(deleteRuleButton)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(flagEncryptionProgramsCheckBox)
.addComponent(finalizeImageWriter)))
.addGroup(layout.createSequentialGroup()
.addGap(393, 393, 393)
.addComponent(shouldSaveCheckBox))
.addGroup(layout.createSequentialGroup()
.addGap(397, 397, 397)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(extensionsLabel)
.addComponent(filenamesLabel)
.addComponent(descriptionLabel)
.addComponent(ruleNameLabel)))
.addGroup(layout.createSequentialGroup()
.addGap(397, 397, 397)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(modifiedDateLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(fileSizeLabel)
.addComponent(fullPathsLabel)
.addComponent(folderNamesLabel))
.addGap(4, 4, 4)
.addComponent(minSizeLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(minSizeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 63, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(maxSizeLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(maxSizeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 63, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addGap(393, 393, 393)
.addComponent(shouldAlertCheckBox)))
.addContainerGap())
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(17, 17, 17)
.addComponent(ruleSetFileLabel)
.addGap(18, 18, 18)
.addComponent(configFileTextField))
.addGroup(layout.createSequentialGroup()
.addGap(397, 397, 397)
.addComponent(jSeparator1)))
.addGap(10, 10, 10))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(configFileTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(ruleSetFileLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 527, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(newRuleButton)
.addComponent(editRuleButton)
.addComponent(deleteRuleButton)))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(30, 30, 30)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(descriptionEditTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(descriptionLabel))
.addGap(9, 9, 9)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(extensionsTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(extensionsLabel)))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(ruleNameEditTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(ruleNameLabel)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane6, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(filenamesLabel)
.addGap(0, 0, Short.MAX_VALUE)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane7, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(folderNamesLabel)
.addGap(0, 0, Short.MAX_VALUE)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(fullPathsLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(jScrollPane5, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
.addGap(11, 11, 11)))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
.addComponent(minSizeLabel)
.addComponent(minSizeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(maxSizeLabel)
.addComponent(maxSizeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(fileSizeLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
.addComponent(modifiedDateLabel)
.addComponent(daysIncludedTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(daysIncludedLabel))
.addGap(3, 3, 3)
.addComponent(shouldAlertCheckBox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(shouldSaveCheckBox)
.addGap(18, 18, 18)
.addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(flagEncryptionProgramsCheckBox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(finalizeImageWriter)))
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents
private void finalizeImageWriterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_finalizeImageWriterActionPerformed
config.setFinalizeImageWriter(finalizeImageWriter.isSelected());
}//GEN-LAST:event_finalizeImageWriterActionPerformed
private void rulesTableKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_rulesTableKeyReleased
rulesTableSelect();
}//GEN-LAST:event_rulesTableKeyReleased
@NbBundle.Messages({
"ConfigVisualPanel2.editRuleSet=Edit rule",
"ConfigVisualPanel2.editRuleError=Edit rule error"
})
private void editRuleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editRuleButtonActionPerformed
int row = rulesTable.getSelectedRow();
if (row != -1) {
String ruleName = (String) rulesTable.getModel().getValueAt(row, 0);
LogicalImagerRule rule = getFirstRuleSet().getRules().get(row);
EditRulePanel editPanel = new EditRulePanel(okButton, cancelButton, ruleName, rule);
editPanel.setEnabled(true);
editPanel.setVisible(true);
while (true) {
int option = JOptionPane.showOptionDialog(this, editPanel.getPanel(), Bundle.ConfigVisualPanel2_editRuleSet(),
JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE,
null, new Object[]{okButton, cancelButton}, okButton);
if (option == JOptionPane.OK_OPTION) {
try {
ImmutablePair<String, LogicalImagerRule> ruleMap = editPanel.toRule();
updateRow(row, ruleMap);
break;
} catch (IOException | NumberFormatException ex) {
JOptionPane.showMessageDialog(this,
ex.getMessage(),
Bundle.ConfigVisualPanel2_editRuleError(),
JOptionPane.ERROR_MESSAGE);
// let user fix the error
}
} else {
break;
}
}
}
}//GEN-LAST:event_editRuleButtonActionPerformed
private void newRuleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newRuleButtonActionPerformed
NewRuleSetPanel panel;
panel = new NewRuleSetPanel(okButton, cancelButton);
panel.setEnabled(true);
panel.setVisible(true);
while (true) {
int option = JOptionPane.showOptionDialog(this, panel, "New rule",
JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE,
null, new Object[]{okButton, cancelButton}, okButton);
if (option == JOptionPane.OK_OPTION) {
try {
// Save the new rule
ImmutablePair<String, LogicalImagerRule> ruleMap = panel.toRule();
appendRow(ruleMap);
break;
} catch (IOException | NumberFormatException ex) {
JOptionPane.showMessageDialog(this,
ex.getMessage(),
"New rule error",
JOptionPane.ERROR_MESSAGE);
// let user fix the error
}
} else {
break;
}
}
}//GEN-LAST:event_newRuleButtonActionPerformed
@NbBundle.Messages({
"ConfigVisualPanel2.deleteRuleSet=Delete rule ",
"ConfigVisualPanel2.deleteRuleSetConfirmation=Delete rule confirmation",
})
private void deleteRuleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteRuleButtonActionPerformed
int index = rulesTable.getSelectedRow();
if (index != -1) {
String ruleName = (String) rulesTable.getModel().getValueAt(index, 0);
int option = JOptionPane.showOptionDialog(this,
Bundle.ConfigVisualPanel2_deleteRuleSet() + ruleName,
Bundle.ConfigVisualPanel2_deleteRuleSetConfirmation(),
JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null);
if (option == JOptionPane.NO_OPTION) {
return;
}
getFirstRuleSet().getRules().remove(index);
updatePanel(configFilename, config);
if (rulesTable.getRowCount() > 0) {
rulesTable.setRowSelectionInterval(0, 0);
rulesTableSelect();
}
}
}//GEN-LAST:event_deleteRuleButtonActionPerformed
private void flagEncryptionProgramsCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_flagEncryptionProgramsCheckBoxActionPerformed
flagEncryptionPrograms = flagEncryptionProgramsCheckBox.isSelected();
toggleEncryptionProgramsRule(flagEncryptionPrograms);
}//GEN-LAST:event_flagEncryptionProgramsCheckBoxActionPerformed
private void rulesTableMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rulesTableMouseReleased
rulesTableSelect();
}//GEN-LAST:event_rulesTableMouseReleased
private void toggleEncryptionProgramsRule(boolean flagEncryptionPrograms) {
if (flagEncryptionPrograms) {
// add the special rule
ImmutablePair<String, LogicalImagerRule> ruleMap = createEncryptionProgramsRule();
appendRow(ruleMap);
} else {
// remove it
int index = ((RulesTableModel) rulesTable.getModel()).findRow(EncryptionProgramsRule.getName());
if (index != -1) {
getFirstRuleSet().getRules().remove(index);
updatePanel(configFilename, config);
if (rulesTable.getRowCount() > 0) {
rulesTable.setRowSelectionInterval(0, 0);
rulesTableSelect();
}
}
}
}
/*
* Create an encryption programs rule
*/
private ImmutablePair<String, LogicalImagerRule> createEncryptionProgramsRule() {
LogicalImagerRule.Builder builder = new LogicalImagerRule.Builder();
builder.getName(EncryptionProgramsRule.getName())
.getDescription(EncryptionProgramsRule.getDescription())
.getShouldAlert(true)
.getShouldSave(true)
.getFilenames(EncryptionProgramsRule.getFilenames());
LogicalImagerRule rule = builder.build();
return new ImmutablePair<>(EncryptionProgramsRule.getName(), rule);
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JTextField configFileTextField;
private javax.swing.JLabel daysIncludedLabel;
private javax.swing.JTextField daysIncludedTextField;
private javax.swing.JButton deleteRuleButton;
private javax.swing.JTextField descriptionEditTextField;
private javax.swing.JLabel descriptionLabel;
private javax.swing.JButton editRuleButton;
private javax.swing.JLabel extensionsLabel;
private javax.swing.JTextField extensionsTextField;
private javax.swing.JLabel fileSizeLabel;
private javax.swing.JLabel filenamesLabel;
private javax.swing.JTable filenamesTable;
private javax.swing.JCheckBox finalizeImageWriter;
private javax.swing.JCheckBox flagEncryptionProgramsCheckBox;
private javax.swing.JLabel folderNamesLabel;
private javax.swing.JTable folderNamesTable;
private javax.swing.JLabel fullPathsLabel;
private javax.swing.JTable fullPathsTable;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JScrollPane jScrollPane5;
private javax.swing.JScrollPane jScrollPane6;
private javax.swing.JScrollPane jScrollPane7;
private javax.swing.JSeparator jSeparator1;
private javax.swing.JLabel maxSizeLabel;
private javax.swing.JFormattedTextField maxSizeTextField;
private javax.swing.JLabel minSizeLabel;
private javax.swing.JFormattedTextField minSizeTextField;
private javax.swing.JLabel modifiedDateLabel;
private javax.swing.JButton newRuleButton;
private javax.swing.JTextField ruleNameEditTextField;
private javax.swing.JLabel ruleNameLabel;
private javax.swing.JLabel ruleSetFileLabel;
private javax.swing.JTable rulesTable;
private javax.swing.JCheckBox shouldAlertCheckBox;
private javax.swing.JCheckBox shouldSaveCheckBox;
// End of variables declaration//GEN-END:variables
private LogicalImagerRuleSet getFirstRuleSet() {
if (config.getRuleSets().isEmpty()) {
List<LogicalImagerRuleSet> ruleSets = new ArrayList<>();
ruleSets.add(new LogicalImagerRuleSet("no-set-name", new ArrayList<>())); // NON-NLS
config.setRuleSet(ruleSets);
}
return config.getRuleSets().get(0);
}
private void updatePanel(String configFilePath, LogicalImagerConfig config, String rowSelectionkey) {
configFileTextField.setText(configFilePath);
finalizeImageWriter.setSelected(config.isFinalizeImageWriter());
LogicalImagerRuleSet ruleSet = getFirstRuleSet();
flagEncryptionProgramsCheckBox.setSelected(ruleSet.find(EncryptionProgramsRule.getName()) != null);
RulesTableModel rulesTableModel = new RulesTableModel();
int row = 0;
int selectThisRow = 0;
Collections.sort(ruleSet.getRules(), new SortRuleByName());
for (LogicalImagerRule rule : ruleSet.getRules()) {
rulesTableModel.setValueAt(rule.getName(), row, 0);
if (rowSelectionkey != null && rowSelectionkey.equals(rule.getName())) {
selectThisRow = row;
}
rulesTableModel.setValueAt(rule.getDescription(), row, 1);
rulesTableModel.setValueAt(rule, row, 2);
row++;
}
rulesTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
rulesTable.setModel(rulesTableModel);
// If there are any rules, select the first one
if (rulesTableModel.getRowCount() > 0) {
rulesTable.setRowSelectionInterval(selectThisRow, selectThisRow);
rulesTableSelect();
} else {
updateRuleSetButtons(false);
}
}
private void updatePanel(String configFilePath, LogicalImagerConfig config) {
updatePanel(configFilePath, config, null);
}
private void rulesTableSelect() {
int index = rulesTable.getSelectedRow();
if (index != -1) {
String ruleName = (String) rulesTable.getModel().getValueAt(index, 0);
String description = (String) rulesTable.getModel().getValueAt(index, 1);
updateRuleDetails(ruleName, description, config);
updateRuleSetButtons(ruleName.equals(EncryptionProgramsRule.getName()) ? false : true);
} else {
updateRuleSetButtons(false);
}
}
private void updateRuleDetails(String ruleName, String description, LogicalImagerConfig config) {
clearRuleDetails();
LogicalImagerRule rule = getFirstRuleSet().find(ruleName);
shouldAlertCheckBox.setSelected(rule.isShouldAlert());
shouldSaveCheckBox.setSelected(rule.isShouldSave());
ruleNameEditTextField.setText(ruleName);
descriptionEditTextField.setText(description);
updateExtensions(rule.getExtensions());
updateList(filenamesTable, rule.getFilenames());
updateList(folderNamesTable, rule.getPaths());
updateList(fullPathsTable, rule.getFullPaths());
if (rule.getMinFileSize() == null) {
minSizeTextField.setText("");
} else {
minSizeTextField.setText(rule.getMinFileSize().toString());
}
if (rule.getMaxFileSize() == null) {
maxSizeTextField.setText("");
} else {
maxSizeTextField.setText(rule.getMaxFileSize().toString());
}
if (rule.getMinDays() == null) {
daysIncludedTextField.setText("");
} else {
daysIncludedTextField.setText(Integer.toString(rule.getMinDays()));
}
}
private void clearRuleDetails() {
extensionsTextField.setText("");
shouldAlertCheckBox.setSelected(false);
shouldSaveCheckBox.setSelected(true);
}
private void updateExtensions(List<String> extensions) {
extensionsTextField.setText("");
if (extensions == null) {
return;
}
String content = "";
boolean first = true;
for (String ext : extensions) {
content += (first ? "" : ",") + ext;
first = false;
}
extensionsTextField.setText(content);
}
private void updateList(javax.swing.JTable jTable, List<String> set) {
SingleColumnTableModel tableModel = new SingleColumnTableModel();
jTable.setTableHeader(null);
if (set == null) {
jTable.setModel(tableModel);
return;
}
int row = 0;
for (String s : set) {
tableModel.setValueAt(s, row, 0);
row++;
}
jTable.setModel(tableModel);
}
void setConfiguration(String configFilename, LogicalImagerConfig config, boolean newFile) {
this.configFilename = configFilename;
this.config = config;
if (newFile) {
initPanel();
}
updatePanel(configFilename, config);
}
private void initPanel() {
configFileTextField.setText("");
rulesTable.setModel(new RulesTableModel());
shouldAlertCheckBox.setSelected(false);
shouldSaveCheckBox.setSelected(true);
ruleNameEditTextField.setText("");
descriptionEditTextField.setText("");
extensionsTextField.setText("");
updateList(filenamesTable, EMPTY_LIST);
updateList(folderNamesTable, EMPTY_LIST);
}
private void updateRow(int index, ImmutablePair<String, LogicalImagerRule> ruleMap) {
getFirstRuleSet().getRules().remove(index);
getFirstRuleSet().getRules().add(ruleMap.getValue());
updatePanel(configFilename, config, ruleMap.getKey());
}
private void appendRow(ImmutablePair<String, LogicalImagerRule> ruleMap) {
getFirstRuleSet().getRules().add(ruleMap.getValue());
updatePanel(configFilename, config, ruleMap.getKey());
}
private void updateRuleSetButtons(boolean isRowSelected) {
newRuleButton.setEnabled(true);
editRuleButton.setEnabled(isRowSelected);
deleteRuleButton.setEnabled(isRowSelected);
}
/**
* Sort rule by name
*/
private class SortRuleByName implements Comparator<LogicalImagerRule> {
public int compare(LogicalImagerRule a, LogicalImagerRule b) {
return a.getName().compareToIgnoreCase(b.getName());
}
}
/**
* RulesTableModel for rules table
*/
private class RulesTableModel extends AbstractTableModel {
private final List<String> ruleName = new ArrayList<>();
private final List<String> ruleDescription = new ArrayList<>();
private final List<LogicalImagerRule> rule = new ArrayList<>();
public int findRow(String name) {
return ruleName.indexOf(name);
}
@Override
public int getRowCount() {
return ruleName.size();
}
@Override
public int getColumnCount() {
return 2;
}
@NbBundle.Messages({
"ConfigVisualPanel2.rulesTable.columnModel.title0=Rule Name",
"ConfigVisualPanel2.rulesTable.columnModel.title1=Description"
})
@Override
public String getColumnName(int column) {
String colName = null;
switch (column) {
case 0:
colName = Bundle.ConfigVisualPanel2_rulesTable_columnModel_title0();
break;
case 1:
colName = Bundle.ConfigVisualPanel2_rulesTable_columnModel_title1();
break;
default:
break;
}
return colName;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Object ret = null;
switch (columnIndex) {
case 0:
ret = ruleName.get(rowIndex);
break;
case 1:
ret = ruleDescription.get(rowIndex);
break;
case 2:
ret = rule.get(rowIndex);
break;
default:
throw new UnsupportedOperationException("Invalid table column index: " + columnIndex); //NON-NLS
}
return ret;
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0:
ruleName.add((String) aValue);
break;
case 1:
ruleDescription.add((String) aValue);
break;
case 2:
rule.add((LogicalImagerRule) aValue);
break;
default:
throw new UnsupportedOperationException("Invalid table column index: " + columnIndex); //NON-NLS
}
// Only show the name and description column
if (columnIndex < 2) {
super.setValueAt(aValue, rowIndex, columnIndex);
}
}
}
/**
* Table model for single column list table.
*/
private class SingleColumnTableModel extends AbstractTableModel {
private final List<String> list = new ArrayList<>();
@Override
public int getRowCount() {
return list.size();
}
@Override
public int getColumnCount() {
return 1;
}
@Override
public String getColumnName(int column) {
return "";
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Object ret = null;
if (columnIndex == 0) {
ret = list.get(rowIndex);
} else {
throw new UnsupportedOperationException("Invalid table column index: " + columnIndex); //NON-NLS
}
return ret;
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (columnIndex == 0) {
list.add((String) aValue);
} else {
throw new UnsupportedOperationException("Invalid table column index: " + columnIndex); //NON-NLS
}
}
}
}

View File

@ -0,0 +1,143 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.configurelogicalimager;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.openide.WizardDescriptor;
import org.openide.WizardValidationException;
import org.openide.util.HelpCtx;
/**
* Configuration Wizard Panel 1
*/
public class ConfigWizardPanel1 implements WizardDescriptor.ValidatingPanel<WizardDescriptor> {
/**
* The visual component that displays this panel. If you need to access the
* component from this class, just use getComponent().
*/
private ConfigVisualPanel1 component;
private boolean valid = false;
// Get the visual component for the panel. In this template, the component
// is kept separate. This can be more efficient: if the wizard is created
// but never displayed, or not all panels are displayed, it is better to
// create only those which really need to be visible.
@Override
public ConfigVisualPanel1 getComponent() {
if (component == null) {
component = new ConfigVisualPanel1();
component.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("UPDATE_UI")) { // NON-NLS
valid = component.isPanelValid();
fireChangeEvent();
}
}
});
}
return component;
}
@Override
public HelpCtx getHelp() {
// Show no Help button for this panel:
return HelpCtx.DEFAULT_HELP;
// If you have context help:
// return new HelpCtx("help.key.here");
}
@Override
public boolean isValid() {
return valid;
// If it depends on some condition (form filled out...) and
// this condition changes (last form field filled in...) then
// use ChangeSupport to implement add/removeChangeListener below.
// WizardDescriptor.ERROR/WARNING/INFORMATION_MESSAGE will also be useful.
}
private final Set<ChangeListener> listeners = new HashSet<>(1); // or can use ChangeSupport in NB 6.0
/**
* Adds a listener to changes of the panel's validity.
*
* @param l the change listener to add
*/
@Override
public final void addChangeListener(ChangeListener l) {
synchronized (listeners) {
listeners.add(l);
}
}
/**
* Removes a listener to changes of the panel's validity.
*
* @param l the change listener to move
*/
@Override
public final void removeChangeListener(ChangeListener l) {
synchronized (listeners) {
listeners.remove(l);
}
}
/**
* This method is auto-generated. It seems that this method is used to
* listen to any change in this wizard panel.
*/
protected final void fireChangeEvent() {
Iterator<ChangeListener> it;
synchronized (listeners) {
it = new HashSet<>(listeners).iterator();
}
ChangeEvent ev = new ChangeEvent(this);
while (it.hasNext()) {
it.next().stateChanged(ev);
}
}
@Override
public void readSettings(WizardDescriptor wiz) {
// use wiz.getProperty to retrieve previous panel state
component.setConfigFilename((String) wiz.getProperty("configFilename")); // NON-NLS
}
@Override
public void storeSettings(WizardDescriptor wiz) {
// use wiz.putProperty to remember current panel state
wiz.putProperty("configFilename", component.getConfigFilename()); // NON-NLS
wiz.putProperty("config", component.getConfig()); // NON-NLS
wiz.putProperty("newFile", component.isNewFile()); // NON-NLS
}
@Override
public void validate() throws WizardValidationException {
valid = component.isPanelValid();
}
}

View File

@ -0,0 +1,149 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.configurelogicalimager;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonIOException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JOptionPane;
import javax.swing.event.ChangeListener;
import org.apache.commons.io.FileUtils;
import org.openide.WizardDescriptor;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Configuration Wizard Panel 2
*/
public class ConfigWizardPanel2 implements WizardDescriptor.Panel<WizardDescriptor> {
private static final Logger LOGGER = Logger.getLogger(ConfigWizardPanel2.class.getName());
/**
* The visual component that displays this panel. If you need to access the
* component from this class, just use getComponent().
*/
private ConfigVisualPanel2 component;
private String configFilename;
private LogicalImagerConfig config;
// Get the visual component for the panel. In this template, the component
// is kept separate. This can be more efficient: if the wizard is created
// but never displayed, or not all panels are displayed, it is better to
// create only those which really need to be visible.
@Override
public ConfigVisualPanel2 getComponent() {
if (component == null) {
component = new ConfigVisualPanel2();
}
return component;
}
@Override
public HelpCtx getHelp() {
// Show no Help button for this panel:
return HelpCtx.DEFAULT_HELP;
// If you have context help:
// return new HelpCtx("help.key.here");
}
@Override
public boolean isValid() {
// If it is always OK to press Next or Finish, then:
return true;
// If it depends on some condition (form filled out...) and
// this condition changes (last form field filled in...) then
// use ChangeSupport to implement add/removeChangeListener below.
// WizardDescriptor.ERROR/WARNING/INFORMATION_MESSAGE will also be useful.
}
@Override
public void readSettings(WizardDescriptor wiz) {
// use wiz.getProperty to retrieve previous panel state
configFilename = (String) wiz.getProperty("configFilename"); // NON-NLS
config = (LogicalImagerConfig) wiz.getProperty("config"); // NON-NLS
component.setConfiguration(configFilename, config, (boolean) wiz.getProperty("newFile"));
}
@Override
public void storeSettings(WizardDescriptor wiz) {
// use wiz.putProperty to remember current panel state
}
@NbBundle.Messages({
"# {0} - configFilename",
"ConfigWizardPanel2.failedToSaveConfigMsg=Failed to save configuration file: {0}",
"# {0} - reason",
"ConfigWizardPanel2.reason=\nReason: ",
"ConfigWizardPanel2.failedToSaveExeMsg=Failed to save tsk_logical_imager.exe file",
})
public void saveConfigFile() {
GsonBuilder gsonBuilder = new GsonBuilder()
.setPrettyPrinting()
.excludeFieldsWithoutExposeAnnotation()
.disableHtmlEscaping();
Gson gson = gsonBuilder.create();
String toJson = gson.toJson(config);
try {
List<String> lines = Arrays.asList(toJson.split("\\n"));
FileUtils.writeLines(new File(configFilename), "UTF-8", lines, System.getProperty("line.separator")); // NON-NLS
} catch (IOException ex) {
JOptionPane.showMessageDialog(component, Bundle.ConfigWizardPanel2_failedToSaveConfigMsg(configFilename)
+ Bundle.ConfigWizardPanel2_reason(ex.getMessage()));
} catch (JsonIOException jioe) {
LOGGER.log(Level.SEVERE, "Failed to save configuration file: " + configFilename, jioe); // NON-NLS
JOptionPane.showMessageDialog(component, Bundle.ConfigWizardPanel2_failedToSaveConfigMsg(configFilename)
+ Bundle.ConfigWizardPanel2_reason(jioe.getMessage()));
}
try {
writeTskLogicalImagerExe(Paths.get(configFilename).getParent());
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, "Failed to save tsk_logical_imager.exe file", ex); // NON-NLS
JOptionPane.showMessageDialog(component, Bundle.ConfigWizardPanel2_failedToSaveExeMsg()
+ Bundle.ConfigWizardPanel2_reason(ex.getMessage()));
}
}
private void writeTskLogicalImagerExe(Path destDir) throws IOException {
try (InputStream in = getClass().getResourceAsStream("tsk_logical_imager.exe")) { // NON-NLS
File destFile = Paths.get(destDir.toString(), "tsk_logical_imager.exe").toFile(); // NON-NLS
FileUtils.copyInputStreamToFile(in, destFile);
}
}
@Override
public void addChangeListener(ChangeListener cl) {
// Not used
}
@Override
public void removeChangeListener(ChangeListener cl) {
// Not used
}
}

View File

@ -0,0 +1,83 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.configurelogicalimager;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JComponent;
import org.openide.DialogDisplayer;
import org.openide.WizardDescriptor;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionRegistration;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
/**
* Configuration Logical Imager
*/
@ActionID(
category = "Tools",
id = "org.sleuthkit.autopsy.configurelogicalimager.ConfigureLogicalImager"
)
@ActionRegistration(
displayName = "#CTL_ConfigureLogicalImager"
)
@ActionReference(path = "Menu/Tools", position = 2000, separatorBefore = 1999)
@Messages("CTL_ConfigureLogicalImager=Configure Logical Imager")
public final class ConfigureLogicalImager implements ActionListener {
@NbBundle.Messages({
"ConfigureLogicalImager.title=Configure Logical Imager"
})
@Override
public void actionPerformed(ActionEvent e) {
List<WizardDescriptor.Panel<WizardDescriptor>> panels = new ArrayList<>();
panels.add(new ConfigWizardPanel1());
panels.add(new ConfigWizardPanel2());
String[] steps = new String[panels.size()];
for (int i = 0; i < panels.size(); i++) {
Component c = panels.get(i).getComponent();
// Default step name to component name of panel.
steps[i] = c.getName();
if (c instanceof JComponent) { // assume Swing components
JComponent jc = (JComponent) c;
jc.putClientProperty(WizardDescriptor.PROP_CONTENT_SELECTED_INDEX, i);
jc.putClientProperty(WizardDescriptor.PROP_CONTENT_DATA, steps);
jc.putClientProperty(WizardDescriptor.PROP_AUTO_WIZARD_STYLE, true);
jc.putClientProperty(WizardDescriptor.PROP_CONTENT_DISPLAYED, true);
jc.putClientProperty(WizardDescriptor.PROP_CONTENT_NUMBERED, true);
}
}
WizardDescriptor wiz = new WizardDescriptor(new WizardDescriptor.ArrayIterator<>(panels));
// {0} will be replaced by WizardDesriptor.Panel.getComponent().getName()
wiz.setTitleFormat(new MessageFormat("{0}")); // NON-NLS
wiz.setTitle(Bundle.ConfigureLogicalImager_title());
if ((DialogDisplayer.getDefault().notify(wiz) == WizardDescriptor.FINISH_OPTION) &&
(panels.get(1) instanceof ConfigWizardPanel2)) {
ConfigWizardPanel2 panel = (ConfigWizardPanel2) panels.get(1);
panel.saveConfigFile();
}
}
}

View File

@ -0,0 +1,134 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="shouldSaveCheckBox" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="shouldAlertCheckBox" min="-2" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="ruleNameLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="descriptionLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="fullPathsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="ruleNameTextField" alignment="0" pref="519" max="32767" attributes="0"/>
<Component id="descriptionTextField" alignment="0" max="32767" attributes="0"/>
<Component id="fullPathsScrollPane" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="ruleNameLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="ruleNameTextField" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="descriptionTextField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="descriptionLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="fullPathsLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="167" max="32767" attributes="0"/>
</Group>
<Component id="fullPathsScrollPane" max="32767" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="shouldAlertCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="shouldSaveCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JCheckBox" name="shouldSaveCheckBox">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditFullPathsRulePanel.shouldSaveCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="shouldAlertCheckBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditFullPathsRulePanel.shouldAlertCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="actionCommand" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditFullPathsRulePanel.shouldAlertCheckBox.actionCommand" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="fullPathsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditFullPathsRulePanel.fullPathsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditFullPathsRulePanel.fullPathsLabel.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="descriptionTextField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditFullPathsRulePanel.descriptionTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="descriptionLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditFullPathsRulePanel.descriptionLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="ruleNameLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditFullPathsRulePanel.ruleNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="ruleNameTextField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditFullPathsRulePanel.ruleNameTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JScrollPane" name="fullPathsScrollPane">
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,260 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.configurelogicalimager;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.openide.util.NbBundle;
/**
* Edit full paths rule panel
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class EditFullPathsRulePanel extends javax.swing.JPanel {
private JButton okButton;
private JButton cancelButton;
private final JTextArea fullPathsTextArea;
/**
* Creates new form EditFullPathsRulePanel
*/
@NbBundle.Messages({
"EditFullPathsRulePanel.example=Example: "
})
public EditFullPathsRulePanel(JButton okButton, JButton cancelButton, String ruleName, LogicalImagerRule rule, boolean editing) {
initComponents();
if (editing) {
ruleNameTextField.setEnabled(!editing);
}
this.setRule(ruleName, rule);
this.setButtons(okButton, cancelButton);
fullPathsTextArea = new JTextArea();
initTextArea(fullPathsScrollPane, fullPathsTextArea);
setTextArea(fullPathsTextArea, rule.getFullPaths());
EditRulePanel.setTextFieldPrompts(fullPathsTextArea,
"<html>" + Bundle.EditFullPathsRulePanel_example() + "<br>/Program Files/Common Files/system/wab32.dll<br>/Windows/System32/1033/VsGraphicsResources.dll</html>"); // NON-NLS
ruleNameTextField.requestFocus();
validate();
repaint();
}
private void initTextArea(JScrollPane pane, JTextArea textArea) {
textArea.setColumns(20);
textArea.setRows(5);
pane.setViewportView(textArea);
textArea.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_TAB) {
if (e.getModifiers() > 0) {
textArea.transferFocusBackward();
} else {
textArea.transferFocus();
}
e.consume();
}
}
});
}
/**
* 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
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
shouldSaveCheckBox = new javax.swing.JCheckBox();
shouldAlertCheckBox = new javax.swing.JCheckBox();
fullPathsLabel = new javax.swing.JLabel();
descriptionTextField = new javax.swing.JTextField();
descriptionLabel = new javax.swing.JLabel();
ruleNameLabel = new javax.swing.JLabel();
ruleNameTextField = new javax.swing.JTextField();
fullPathsScrollPane = new javax.swing.JScrollPane();
shouldSaveCheckBox.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(shouldSaveCheckBox, org.openide.util.NbBundle.getMessage(EditFullPathsRulePanel.class, "EditFullPathsRulePanel.shouldSaveCheckBox.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(shouldAlertCheckBox, org.openide.util.NbBundle.getMessage(EditFullPathsRulePanel.class, "EditFullPathsRulePanel.shouldAlertCheckBox.text")); // NOI18N
shouldAlertCheckBox.setActionCommand(org.openide.util.NbBundle.getMessage(EditFullPathsRulePanel.class, "EditFullPathsRulePanel.shouldAlertCheckBox.actionCommand")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(fullPathsLabel, org.openide.util.NbBundle.getMessage(EditFullPathsRulePanel.class, "EditFullPathsRulePanel.fullPathsLabel.text")); // NOI18N
fullPathsLabel.setToolTipText(org.openide.util.NbBundle.getMessage(EditFullPathsRulePanel.class, "EditFullPathsRulePanel.fullPathsLabel.toolTipText")); // NOI18N
descriptionTextField.setText(org.openide.util.NbBundle.getMessage(EditFullPathsRulePanel.class, "EditFullPathsRulePanel.descriptionTextField.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel, org.openide.util.NbBundle.getMessage(EditFullPathsRulePanel.class, "EditFullPathsRulePanel.descriptionLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(ruleNameLabel, org.openide.util.NbBundle.getMessage(EditFullPathsRulePanel.class, "EditFullPathsRulePanel.ruleNameLabel.text")); // NOI18N
ruleNameTextField.setText(org.openide.util.NbBundle.getMessage(EditFullPathsRulePanel.class, "EditFullPathsRulePanel.ruleNameTextField.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(shouldSaveCheckBox)
.addComponent(shouldAlertCheckBox)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(ruleNameLabel)
.addComponent(descriptionLabel)
.addComponent(fullPathsLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(ruleNameTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 519, Short.MAX_VALUE)
.addComponent(descriptionTextField)
.addComponent(fullPathsScrollPane))))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(ruleNameLabel)
.addComponent(ruleNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(descriptionTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(descriptionLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(fullPathsLabel)
.addGap(0, 167, Short.MAX_VALUE))
.addComponent(fullPathsScrollPane))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(shouldAlertCheckBox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(shouldSaveCheckBox)
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel descriptionLabel;
private javax.swing.JTextField descriptionTextField;
private javax.swing.JLabel fullPathsLabel;
private javax.swing.JScrollPane fullPathsScrollPane;
private javax.swing.JLabel ruleNameLabel;
private javax.swing.JTextField ruleNameTextField;
private javax.swing.JCheckBox shouldAlertCheckBox;
private javax.swing.JCheckBox shouldSaveCheckBox;
// End of variables declaration//GEN-END:variables
/**
* Sets whether or not the OK button should be enabled based upon other UI
* elements
*/
private void setOkButton() {
if (this.okButton != null) {
this.okButton.setEnabled(true);
}
}
/**
* Gets the JOptionPane that is used to contain this panel if there is one
*
* @param parent
*
* @return
*/
private JOptionPane getOptionPane(JComponent parent) {
JOptionPane pane;
if (!(parent instanceof JOptionPane)) {
pane = getOptionPane((JComponent) parent.getParent());
} else {
pane = (JOptionPane) parent;
}
return pane;
}
/**
* Sets the buttons for ending the panel
*
* @param ok The ok button
* @param cancel The cancel button
*/
private void setButtons(JButton ok, JButton cancel) {
this.okButton = ok;
this.cancelButton = cancel;
okButton.addActionListener((ActionEvent e) -> {
JOptionPane pane = getOptionPane(okButton);
pane.setValue(okButton);
});
cancelButton.addActionListener((ActionEvent e) -> {
JOptionPane pane = getOptionPane(cancelButton);
pane.setValue(cancelButton);
});
this.setOkButton();
}
private void setRule(String ruleName, LogicalImagerRule rule) {
ruleNameTextField.setText(ruleName);
descriptionTextField.setText(rule.getDescription());
shouldAlertCheckBox.setSelected(rule.isShouldAlert());
shouldSaveCheckBox.setSelected(rule.isShouldSave());
}
private void setTextArea(JTextArea textArea, List<String> set) {
String text = "";
for (String s : set) {
text += s + System.getProperty("line.separator"); // NON-NLS
}
textArea.setText(text);
}
@NbBundle.Messages({
"EditFullPathsRulePanel.fullPaths=Full paths",
})
public ImmutablePair<String, LogicalImagerRule> toRule() throws IOException {
List<String> fullPaths = EditRulePanel.validateTextList(fullPathsTextArea, Bundle.EditFullPathsRulePanel_fullPaths());
String ruleName = EditRulePanel.validRuleName(ruleNameTextField.getText());
LogicalImagerRule.Builder builder = new LogicalImagerRule.Builder();
builder.getShouldAlert(shouldAlertCheckBox.isSelected())
.getShouldSave(shouldSaveCheckBox.isSelected())
.getName(ruleName)
.getDescription(descriptionTextField.getText())
.getFullPaths(fullPaths);
LogicalImagerRule rule = builder.build();
return new ImmutablePair<>(ruleName, rule);
}
}

View File

@ -0,0 +1,322 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<NonVisualComponents>
<Component class="javax.swing.ButtonGroup" name="buttonGroup">
</Component>
</NonVisualComponents>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="extensionsRadioButton" min="-2" max="-2" attributes="0"/>
<Component id="filenamesRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="ruleNameLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="descriptionLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="extensionsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="filenamesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="folderNamesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="fileSizeLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="modifiedDateLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="folderNamesScrollPane" alignment="1" max="32767" attributes="0"/>
<Component id="filenamesScrollPane" alignment="1" max="32767" attributes="0"/>
<Component id="extensionsTextField" alignment="1" max="32767" attributes="0"/>
<Component id="descriptionTextField" alignment="1" max="32767" attributes="0"/>
<Component id="ruleNameTextField" alignment="1" max="32767" attributes="0"/>
</Group>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="23" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="shouldSaveCheckBox" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="shouldAlertCheckBox" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="108" pref="108" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="minDaysTextField" max="32767" attributes="0"/>
<Component id="minSizeLabel" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="minSizeTextField" min="-2" pref="63" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="maxSizeLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="maxSizeTextField" min="-2" pref="63" max="-2" attributes="0"/>
</Group>
<Component id="daysIncludedLabel" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<EmptySpace min="0" pref="236" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="2" attributes="0">
<Component id="ruleNameLabel" alignment="2" min="-2" max="-2" attributes="0"/>
<Component id="ruleNameTextField" alignment="2" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="2" attributes="0">
<Component id="descriptionLabel" alignment="2" min="-2" max="-2" attributes="0"/>
<Component id="descriptionTextField" alignment="2" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="2" attributes="0">
<Component id="extensionsTextField" alignment="2" min="-2" max="-2" attributes="0"/>
<Component id="extensionsLabel" alignment="2" min="-2" max="-2" attributes="0"/>
<Component id="extensionsRadioButton" alignment="2" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="filenamesScrollPane" alignment="0" pref="70" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="2" attributes="0">
<Component id="filenamesLabel" alignment="2" min="-2" max="-2" attributes="0"/>
<Component id="filenamesRadioButton" alignment="2" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="folderNamesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="folderNamesScrollPane" alignment="0" pref="71" max="32767" attributes="0"/>
</Group>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="2" attributes="0">
<Component id="fileSizeLabel" alignment="2" min="-2" max="-2" attributes="0"/>
<Component id="minSizeLabel" alignment="2" min="-2" max="-2" attributes="0"/>
<Component id="minSizeTextField" alignment="2" min="-2" max="-2" attributes="0"/>
<Component id="maxSizeLabel" alignment="2" min="-2" max="-2" attributes="0"/>
<Component id="maxSizeTextField" alignment="2" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Group type="103" groupAlignment="2" attributes="0">
<Component id="modifiedDateLabel" alignment="2" min="-2" max="-2" attributes="0"/>
<Component id="daysIncludedLabel" alignment="2" min="-2" max="-2" attributes="0"/>
<Component id="minDaysTextField" alignment="2" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="14" max="-2" attributes="0"/>
<Component id="shouldAlertCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Component id="shouldSaveCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="modifiedDateLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditNonFullPathsRulePanel.modifiedDateLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="daysIncludedLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditNonFullPathsRulePanel.daysIncludedLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="shouldSaveCheckBox">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditNonFullPathsRulePanel.shouldSaveCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="shouldAlertCheckBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditNonFullPathsRulePanel.shouldAlertCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="actionCommand" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditNonFullPathsRulePanel.shouldAlertCheckBox.actionCommand" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="extensionsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditNonFullPathsRulePanel.extensionsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="extensionsTextField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditNonFullPathsRulePanel.extensionsTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="filenamesLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditNonFullPathsRulePanel.filenamesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="folderNamesLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditNonFullPathsRulePanel.folderNamesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="fileSizeLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditNonFullPathsRulePanel.fileSizeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="descriptionTextField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditNonFullPathsRulePanel.descriptionTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="descriptionLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditNonFullPathsRulePanel.descriptionLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="ruleNameLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditNonFullPathsRulePanel.ruleNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="ruleNameTextField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditNonFullPathsRulePanel.ruleNameTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JScrollPane" name="filenamesScrollPane">
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
</Container>
<Container class="javax.swing.JScrollPane" name="folderNamesScrollPane">
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
</Container>
<Component class="javax.swing.JLabel" name="minSizeLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditNonFullPathsRulePanel.minSizeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JFormattedTextField" name="minSizeTextField">
<Properties>
<Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.editors.AbstractFormatterFactoryEditor">
<Format format="#,###; " subtype="-1" type="0"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditNonFullPathsRulePanel.minSizeTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="maxSizeLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditNonFullPathsRulePanel.maxSizeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JFormattedTextField" name="maxSizeTextField">
<Properties>
<Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.editors.AbstractFormatterFactoryEditor">
<Format format="#,###; " subtype="-1" type="0"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditNonFullPathsRulePanel.maxSizeTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JFormattedTextField" name="minDaysTextField">
<Properties>
<Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.editors.AbstractFormatterFactoryEditor">
<Format format="####; " subtype="-1" type="0"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JRadioButton" name="extensionsRadioButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="buttonGroup"/>
</Property>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditNonFullPathsRulePanel.extensionsRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditNonFullPathsRulePanel.extensionsRadioButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="extensionsRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="filenamesRadioButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="buttonGroup"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditNonFullPathsRulePanel.filenamesRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="EditNonFullPathsRulePanel.filenamesRadioButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="filenamesRadioButtonActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,546 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.configurelogicalimager;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import static org.apache.commons.lang.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.strip;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.openide.util.NbBundle;
/**
* Edit non-full paths rule panel
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class EditNonFullPathsRulePanel extends javax.swing.JPanel {
private JButton okButton;
private JButton cancelButton;
private final javax.swing.JTextArea filenamesTextArea;
private final javax.swing.JTextArea folderNamesTextArea;
/**
* Creates new form EditRulePanel
*/
@NbBundle.Messages({
"EditNonFullPathsRulePanel.example=Example: ",
"EditNonFullPathsRulePanel.note=NOTE: A special [USER_FOLDER] token at the the start of a folder name to allow matches of all user folders in the file system."
})
EditNonFullPathsRulePanel(JButton okButton, JButton cancelButton, String ruleName, LogicalImagerRule rule, boolean editing) {
initComponents();
if (editing) {
ruleNameTextField.setEnabled(!editing);
}
this.setRule(ruleName, rule);
this.setButtons(okButton, cancelButton);
setExtensions(rule.getExtensions());
filenamesTextArea = new JTextArea();
initTextArea(filenamesScrollPane, filenamesTextArea);
setTextArea(filenamesTextArea, rule.getFilenames());
if (rule.getExtensions() == null) {
extensionsRadioButton.setSelected(false);
filenamesRadioButton.setSelected(true);
} else {
extensionsRadioButton.setSelected(true);
filenamesRadioButton.setSelected(false);
}
folderNamesTextArea = new JTextArea();
initTextArea(folderNamesScrollPane, folderNamesTextArea);
setTextArea(folderNamesTextArea, rule.getPaths());
setMinDays(rule.getMinDays());
minSizeTextField.setText(rule.getMinFileSize() == null ? "" : rule.getMinFileSize().toString());
maxSizeTextField.setText(rule.getMaxFileSize() == null ? "" : rule.getMaxFileSize().toString());
ruleNameTextField.requestFocus();
EditRulePanel.setTextFieldPrompts(extensionsTextField, Bundle.EditNonFullPathsRulePanel_example() + "gif,jpg,png"); // NON-NLS
EditRulePanel.setTextFieldPrompts(filenamesTextArea, "<html>"
+ Bundle.EditNonFullPathsRulePanel_example()
+ "<br>filename.txt<br>readme.txt</html>"); // NON-NLS
EditRulePanel.setTextFieldPrompts(folderNamesTextArea, "<html>"
+ Bundle.EditNonFullPathsRulePanel_example()
+ "<br>[USER_FOLDER]/My Documents/Downloads"
+ "<br>/Program Files/Common Files"
+ "<br>"
+ Bundle.EditNonFullPathsRulePanel_note()
+ "</html>"); // NON-NLS
validate();
repaint();
}
private void initTextArea(JScrollPane pane, JTextArea textArea) {
textArea.setColumns(20);
textArea.setRows(5);
pane.setViewportView(textArea);
textArea.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_TAB) {
if (e.getModifiers() > 0) {
textArea.transferFocusBackward();
} else {
textArea.transferFocus();
}
e.consume();
}
}
});
}
private void setMinDays(Integer minDays) {
minDaysTextField.setText(minDays == null ? "" : minDays.toString());
}
private void setTextArea(JTextArea textArea, List<String> set) {
String text = "";
if (set != null) {
for (String s : set) {
text += s + System.getProperty("line.separator"); // NON-NLS
}
}
textArea.setText(text);
}
private void setExtensions(List<String> extensions) {
extensionsTextField.setText("");
String content = "";
if (extensions != null) {
boolean first = true;
for (String ext : extensions) {
content += (first ? "" : ",") + ext;
first = false;
}
}
extensionsTextField.setText(content);
}
/**
* 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
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
buttonGroup = new javax.swing.ButtonGroup();
modifiedDateLabel = new javax.swing.JLabel();
daysIncludedLabel = new javax.swing.JLabel();
shouldSaveCheckBox = new javax.swing.JCheckBox();
shouldAlertCheckBox = new javax.swing.JCheckBox();
extensionsLabel = new javax.swing.JLabel();
extensionsTextField = new javax.swing.JTextField();
filenamesLabel = new javax.swing.JLabel();
folderNamesLabel = new javax.swing.JLabel();
fileSizeLabel = new javax.swing.JLabel();
descriptionTextField = new javax.swing.JTextField();
descriptionLabel = new javax.swing.JLabel();
ruleNameLabel = new javax.swing.JLabel();
ruleNameTextField = new javax.swing.JTextField();
filenamesScrollPane = new javax.swing.JScrollPane();
folderNamesScrollPane = new javax.swing.JScrollPane();
minSizeLabel = new javax.swing.JLabel();
minSizeTextField = new javax.swing.JFormattedTextField();
maxSizeLabel = new javax.swing.JLabel();
maxSizeTextField = new javax.swing.JFormattedTextField();
minDaysTextField = new javax.swing.JFormattedTextField();
extensionsRadioButton = new javax.swing.JRadioButton();
filenamesRadioButton = new javax.swing.JRadioButton();
org.openide.awt.Mnemonics.setLocalizedText(modifiedDateLabel, org.openide.util.NbBundle.getMessage(EditNonFullPathsRulePanel.class, "EditNonFullPathsRulePanel.modifiedDateLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(daysIncludedLabel, org.openide.util.NbBundle.getMessage(EditNonFullPathsRulePanel.class, "EditNonFullPathsRulePanel.daysIncludedLabel.text")); // NOI18N
shouldSaveCheckBox.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(shouldSaveCheckBox, org.openide.util.NbBundle.getMessage(EditNonFullPathsRulePanel.class, "EditNonFullPathsRulePanel.shouldSaveCheckBox.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(shouldAlertCheckBox, org.openide.util.NbBundle.getMessage(EditNonFullPathsRulePanel.class, "EditNonFullPathsRulePanel.shouldAlertCheckBox.text")); // NOI18N
shouldAlertCheckBox.setActionCommand(org.openide.util.NbBundle.getMessage(EditNonFullPathsRulePanel.class, "EditNonFullPathsRulePanel.shouldAlertCheckBox.actionCommand")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(extensionsLabel, org.openide.util.NbBundle.getMessage(EditNonFullPathsRulePanel.class, "EditNonFullPathsRulePanel.extensionsLabel.text")); // NOI18N
extensionsTextField.setText(org.openide.util.NbBundle.getMessage(EditNonFullPathsRulePanel.class, "EditNonFullPathsRulePanel.extensionsTextField.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(filenamesLabel, org.openide.util.NbBundle.getMessage(EditNonFullPathsRulePanel.class, "EditNonFullPathsRulePanel.filenamesLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(folderNamesLabel, org.openide.util.NbBundle.getMessage(EditNonFullPathsRulePanel.class, "EditNonFullPathsRulePanel.folderNamesLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(fileSizeLabel, org.openide.util.NbBundle.getMessage(EditNonFullPathsRulePanel.class, "EditNonFullPathsRulePanel.fileSizeLabel.text")); // NOI18N
descriptionTextField.setText(org.openide.util.NbBundle.getMessage(EditNonFullPathsRulePanel.class, "EditNonFullPathsRulePanel.descriptionTextField.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel, org.openide.util.NbBundle.getMessage(EditNonFullPathsRulePanel.class, "EditNonFullPathsRulePanel.descriptionLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(ruleNameLabel, org.openide.util.NbBundle.getMessage(EditNonFullPathsRulePanel.class, "EditNonFullPathsRulePanel.ruleNameLabel.text")); // NOI18N
ruleNameTextField.setText(org.openide.util.NbBundle.getMessage(EditNonFullPathsRulePanel.class, "EditNonFullPathsRulePanel.ruleNameTextField.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(minSizeLabel, org.openide.util.NbBundle.getMessage(EditNonFullPathsRulePanel.class, "EditNonFullPathsRulePanel.minSizeLabel.text")); // NOI18N
minSizeTextField.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter(new java.text.DecimalFormat("#,###; "))));
minSizeTextField.setText(org.openide.util.NbBundle.getMessage(EditNonFullPathsRulePanel.class, "EditNonFullPathsRulePanel.minSizeTextField.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(maxSizeLabel, org.openide.util.NbBundle.getMessage(EditNonFullPathsRulePanel.class, "EditNonFullPathsRulePanel.maxSizeLabel.text")); // NOI18N
maxSizeTextField.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter(new java.text.DecimalFormat("#,###; "))));
maxSizeTextField.setText(org.openide.util.NbBundle.getMessage(EditNonFullPathsRulePanel.class, "EditNonFullPathsRulePanel.maxSizeTextField.text")); // NOI18N
minDaysTextField.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter(new java.text.DecimalFormat("####; "))));
buttonGroup.add(extensionsRadioButton);
extensionsRadioButton.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(extensionsRadioButton, org.openide.util.NbBundle.getMessage(EditNonFullPathsRulePanel.class, "EditNonFullPathsRulePanel.extensionsRadioButton.text")); // NOI18N
extensionsRadioButton.setToolTipText(org.openide.util.NbBundle.getMessage(EditNonFullPathsRulePanel.class, "EditNonFullPathsRulePanel.extensionsRadioButton.toolTipText")); // NOI18N
extensionsRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
extensionsRadioButtonActionPerformed(evt);
}
});
buttonGroup.add(filenamesRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(filenamesRadioButton, org.openide.util.NbBundle.getMessage(EditNonFullPathsRulePanel.class, "EditNonFullPathsRulePanel.filenamesRadioButton.text")); // NOI18N
filenamesRadioButton.setToolTipText(org.openide.util.NbBundle.getMessage(EditNonFullPathsRulePanel.class, "EditNonFullPathsRulePanel.filenamesRadioButton.toolTipText")); // NOI18N
filenamesRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
filenamesRadioButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(extensionsRadioButton)
.addComponent(filenamesRadioButton))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(ruleNameLabel)
.addComponent(descriptionLabel)
.addComponent(extensionsLabel)
.addComponent(filenamesLabel)
.addComponent(folderNamesLabel)
.addComponent(fileSizeLabel)
.addComponent(modifiedDateLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(folderNamesScrollPane, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(filenamesScrollPane, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(extensionsTextField, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(descriptionTextField, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(ruleNameTextField, javax.swing.GroupLayout.Alignment.TRAILING)))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(23, 23, 23)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(shouldSaveCheckBox)
.addComponent(shouldAlertCheckBox)))
.addGroup(layout.createSequentialGroup()
.addGap(108, 108, 108)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(minDaysTextField)
.addComponent(minSizeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(minSizeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 63, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(maxSizeLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(maxSizeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 63, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(daysIncludedLabel))))
.addGap(0, 236, Short.MAX_VALUE)))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
.addComponent(ruleNameLabel)
.addComponent(ruleNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
.addComponent(descriptionLabel)
.addComponent(descriptionTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
.addComponent(extensionsTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(extensionsLabel)
.addComponent(extensionsRadioButton))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(filenamesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 70, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
.addComponent(filenamesLabel)
.addComponent(filenamesRadioButton))
.addGap(0, 0, Short.MAX_VALUE)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(folderNamesLabel)
.addComponent(folderNamesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 71, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
.addComponent(fileSizeLabel)
.addComponent(minSizeLabel)
.addComponent(minSizeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(maxSizeLabel)
.addComponent(maxSizeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(6, 6, 6)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
.addComponent(modifiedDateLabel)
.addComponent(daysIncludedLabel)
.addComponent(minDaysTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(14, 14, 14)
.addComponent(shouldAlertCheckBox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(shouldSaveCheckBox)
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents
private void extensionsRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_extensionsRadioButtonActionPerformed
filenamesTextArea.setEnabled(false);
filenamesTextArea.setForeground(Color.LIGHT_GRAY);
extensionsTextField.setEnabled(true);
extensionsTextField.setForeground(Color.BLACK);
}//GEN-LAST:event_extensionsRadioButtonActionPerformed
private void filenamesRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_filenamesRadioButtonActionPerformed
filenamesTextArea.setEnabled(true);
filenamesTextArea.setForeground(Color.BLACK);
extensionsTextField.setEnabled(false);
extensionsTextField.setForeground(Color.LIGHT_GRAY);
}//GEN-LAST:event_filenamesRadioButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.ButtonGroup buttonGroup;
private javax.swing.JLabel daysIncludedLabel;
private javax.swing.JLabel descriptionLabel;
private javax.swing.JTextField descriptionTextField;
private javax.swing.JLabel extensionsLabel;
private javax.swing.JRadioButton extensionsRadioButton;
private javax.swing.JTextField extensionsTextField;
private javax.swing.JLabel fileSizeLabel;
private javax.swing.JLabel filenamesLabel;
private javax.swing.JRadioButton filenamesRadioButton;
private javax.swing.JScrollPane filenamesScrollPane;
private javax.swing.JLabel folderNamesLabel;
private javax.swing.JScrollPane folderNamesScrollPane;
private javax.swing.JLabel maxSizeLabel;
private javax.swing.JFormattedTextField maxSizeTextField;
private javax.swing.JFormattedTextField minDaysTextField;
private javax.swing.JLabel minSizeLabel;
private javax.swing.JFormattedTextField minSizeTextField;
private javax.swing.JLabel modifiedDateLabel;
private javax.swing.JLabel ruleNameLabel;
private javax.swing.JTextField ruleNameTextField;
private javax.swing.JCheckBox shouldAlertCheckBox;
private javax.swing.JCheckBox shouldSaveCheckBox;
// End of variables declaration//GEN-END:variables
private void setRule(String ruleName, LogicalImagerRule rule) {
ruleNameTextField.setText(ruleName);
descriptionTextField.setText(rule.getDescription());
shouldAlertCheckBox.setSelected(rule.isShouldAlert());
shouldSaveCheckBox.setSelected(rule.isShouldSave());
}
/**
* Sets whether or not the OK button should be enabled based upon other UI
* elements
*/
private void setOkButton() {
if (this.okButton != null) {
this.okButton.setEnabled(true);
}
}
/**
* Gets the JOptionPane that is used to contain this panel if there is one
*
* @param parent
*
* @return
*/
private JOptionPane getOptionPane(JComponent parent) {
JOptionPane pane;
if (!(parent instanceof JOptionPane)) {
pane = getOptionPane((JComponent) parent.getParent());
} else {
pane = (JOptionPane) parent;
}
return pane;
}
/**
* Sets the buttons for ending the panel
*
* @param ok The ok button
* @param cancel The cancel button
*/
private void setButtons(JButton ok, JButton cancel) {
this.okButton = ok;
this.cancelButton = cancel;
okButton.addActionListener((ActionEvent e) -> {
JOptionPane pane = getOptionPane(okButton);
pane.setValue(okButton);
});
cancelButton.addActionListener((ActionEvent e) -> {
JOptionPane pane = getOptionPane(cancelButton);
pane.setValue(cancelButton);
});
this.setOkButton();
}
@NbBundle.Messages({
"EditNonFullPathsRulePanel.modifiedDaysNotPositiveException=Modified days must be a positive",
"# {0} - message",
"EditNonFullPathsRulePanel.modifiedDaysMustBeNumberException=Modified days must be a number: {0}",
"EditNonFullPathsRulePanel.minFileSizeNotPositiveException=Minimum file size must be a positive",
"# {0} - message",
"EditNonFullPathsRulePanel.minFileSizeMustBeNumberException=Minimum file size must be a number: {0}",
"EditNonFullPathsRulePanel.maxFileSizeNotPositiveException=Maximum file size must be a positive",
"# {0} - message",
"EditNonFullPathsRulePanel.maxFileSizeMustBeNumberException=Maximum file size must be a number: {0}",
"# {0} - maxFileSize",
"# {1} - minFileSize",
"EditNonFullPathsRulePanel.maxFileSizeSmallerThanMinException=Maximum file size: {0} must be bigger than minimum file size: {1}",
"EditNonFullPathsRulePanel.fileNames=File names",
"EditNonFullPathsRulePanel.folderNames=Folder names",
})
ImmutablePair<String, LogicalImagerRule> toRule() throws IOException {
String ruleName = EditRulePanel.validRuleName(ruleNameTextField.getText());
List<String> extensions = validateExtensions(extensionsTextField);
List<String> filenames = EditRulePanel.validateTextList(filenamesTextArea, Bundle.EditNonFullPathsRulePanel_fileNames());
List<String> folderNames = EditRulePanel.validateTextList(folderNamesTextArea, Bundle.EditNonFullPathsRulePanel_folderNames());
LogicalImagerRule.Builder builder = new LogicalImagerRule.Builder();
builder.getName(ruleName)
.getDescription(descriptionTextField.getText())
.getShouldAlert(shouldAlertCheckBox.isSelected())
.getShouldSave(shouldSaveCheckBox.isSelected())
.getPaths(folderNames);
if (extensionsRadioButton.isSelected()) {
builder.getExtensions(extensions);
} else {
builder.getFilenames(filenames);
}
int minDays;
if (!isBlank(minDaysTextField.getText())) {
try {
minDaysTextField.commitEdit();
minDays = ((Number)minDaysTextField.getValue()).intValue();
if (minDays < 0) {
throw new IOException(Bundle.EditNonFullPathsRulePanel_modifiedDaysNotPositiveException());
}
builder.getMinDays(minDays);
} catch (NumberFormatException | ParseException ex) {
throw new IOException(Bundle.EditNonFullPathsRulePanel_modifiedDaysMustBeNumberException(ex.getMessage()), ex);
}
}
int minFileSize = 0;
if (!isBlank(minSizeTextField.getText())) {
try {
minSizeTextField.commitEdit();
minFileSize = ((Number)minSizeTextField.getValue()).intValue();
if (minFileSize < 0) {
throw new IOException(Bundle.EditNonFullPathsRulePanel_minFileSizeNotPositiveException());
}
} catch (NumberFormatException | ParseException ex) {
throw new IOException(Bundle.EditNonFullPathsRulePanel_minFileSizeMustBeNumberException(ex.getMessage()), ex);
}
}
int maxFileSize = 0;
if (!isBlank(maxSizeTextField.getText())) {
try {
maxSizeTextField.commitEdit();
maxFileSize = ((Number)maxSizeTextField.getValue()).intValue();
if (maxFileSize < 0) {
throw new IOException(Bundle.EditNonFullPathsRulePanel_maxFileSizeNotPositiveException());
}
} catch (NumberFormatException | ParseException ex) {
throw new IOException(Bundle.EditNonFullPathsRulePanel_maxFileSizeMustBeNumberException(ex.getMessage()), ex);
}
}
if (maxFileSize != 0 && (maxFileSize < minFileSize)) {
throw new IOException(Bundle.EditNonFullPathsRulePanel_maxFileSizeSmallerThanMinException(maxFileSize, minFileSize));
}
if (minFileSize != 0) {
builder.getMinFileSize(minFileSize);
}
if (maxFileSize != 0) {
builder.getMaxFileSize(maxFileSize);
}
LogicalImagerRule rule = builder.build();
return new ImmutablePair<>(ruleName, rule);
}
@NbBundle.Messages({
"EditNonFullPathsRulePanel.emptyExtensionException=Extensions cannot have an empty entry",
})
private List<String> validateExtensions(JTextField textField) throws IOException {
if (isBlank(textField.getText())) {
return null;
}
List<String> extensions = new ArrayList<>();
for (String extension : textField.getText().split(",")) {
extension = strip(extension);
if (extension.isEmpty()) {
throw new IOException(Bundle.EditNonFullPathsRulePanel_emptyExtensionException());
}
extensions.add(extension);
}
if (extensions.isEmpty()) {
return null;
}
return extensions;
}
}

View File

@ -0,0 +1,123 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.configurelogicalimager;
import java.awt.BorderLayout;
import java.awt.Color;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.text.JTextComponent;
import static org.apache.commons.lang.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.strip;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.corecomponents.TextPrompt;
/**
* Edit rule panel
*/
public class EditRulePanel extends JPanel {
private EditFullPathsRulePanel editFullPathsRulePanel = null;
private EditNonFullPathsRulePanel editNonFullPathsRulePanel = null;
/**
* Creates new form EditRulePanel
*/
public EditRulePanel(JButton okButton, JButton cancelButton, String ruleName, LogicalImagerRule rule) {
if (rule.getFullPaths() != null && rule.getFullPaths().size() > 0) {
editFullPathsRulePanel = new EditFullPathsRulePanel(okButton, cancelButton, ruleName, rule, true);
} else {
editNonFullPathsRulePanel = new EditNonFullPathsRulePanel(okButton, cancelButton, ruleName, rule, true);
}
}
JPanel getPanel() {
if (editFullPathsRulePanel != null) {
return editFullPathsRulePanel;
} else {
return editNonFullPathsRulePanel;
}
}
ImmutablePair<String, LogicalImagerRule> toRule() throws IOException, NumberFormatException {
ImmutablePair<String, LogicalImagerRule> ruleMap;
if (editFullPathsRulePanel != null) {
ruleMap = editFullPathsRulePanel.toRule();
} else {
ruleMap = editNonFullPathsRulePanel.toRule();
}
return ruleMap;
}
static void setTextFieldPrompts(JTextComponent textField, String text) {
/**
* Add text prompt to the text field.
*/
TextPrompt textPrompt;
if (textField instanceof JTextArea) {
textPrompt = new TextPrompt(text, textField, BorderLayout.NORTH);
} else {
textPrompt = new TextPrompt(text, textField);
}
/**
* Sets the foreground color and transparency of the text prompt.
*/
textPrompt.setForeground(Color.LIGHT_GRAY);
textPrompt.changeAlpha(0.9f); // Mostly opaque
}
@NbBundle.Messages({
"EditRulePanel.validateRuleNameExceptionMsg=Rule name cannot be empty"
})
static public String validRuleName(String name) throws IOException {
if (name.isEmpty()) {
throw new IOException(Bundle.EditRulePanel_validateRuleNameExceptionMsg());
}
return name;
}
@NbBundle.Messages({
"# {0} - fieldName",
"EditRulePanel.blankLineException={0} cannot have a blank line",
})
static public List<String> validateTextList(JTextArea textArea, String fieldName) throws IOException {
if (isBlank(textArea.getText())) {
return null;
}
List<String> list = new ArrayList<>();
for (String line : textArea.getText().split("\\n")) { // NON-NLS
line = strip(line);
if (line.isEmpty()) {
throw new IOException(Bundle.EditRulePanel_blankLineException(fieldName));
}
list.add(line);
}
if (list.isEmpty()) {
return null;
}
return list;
}
}

View File

@ -0,0 +1,94 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.configurelogicalimager;
import java.util.ArrayList;
import java.util.List;
import org.openide.util.NbBundle;
/**
* Encryption programs rule
*/
@NbBundle.Messages({
"EncryptionProgramsRule.encryptionProgramsRuleName=Encryption Programs",
"EncryptionProgramsRule.encryptionProgramsRuleDescription=Find encryption programs"
})
public final class EncryptionProgramsRule {
private static final String ENCRYPTION_PROGRAMS_RULE_NAME = Bundle.EncryptionProgramsRule_encryptionProgramsRuleName();
private static final String ENCRYPTION_PROGRAMS_RULE_DESCRIPTION = Bundle.EncryptionProgramsRule_encryptionProgramsRuleDescription();
private static final List<String> FILENAMES = new ArrayList<>();
private EncryptionProgramsRule() {}
// TODO: Add more files here
static {
// Truecrypt
FILENAMES.add("truecrypt.exe"); // NON-NLS
// AxCrypt
FILENAMES.add("AxCrypt.exe"); // NON-NLS
// VeraCrypt
FILENAMES.add("VeraCrypt.exe"); // NON-NLS
FILENAMES.add("VeraCrypt Format.exe"); // NON-NLS
FILENAMES.add("VeraCrypt Setup.exe"); // NON-NLS
FILENAMES.add("VeraCryptExpander.exe"); // NON-NLS
// GnuPG
FILENAMES.add("gpg-agent.exe"); // NON-NLS
FILENAMES.add("gpg-connect-agent.exe"); // NON-NLS
FILENAMES.add("gpg-preset-passphrase.exe"); // NON-NLS
FILENAMES.add("gpg-wks-client.exe"); // NON-NLS
FILENAMES.add("gpg.exe"); // NON-NLS
FILENAMES.add("gpgconf.exe"); // NON-NLS
FILENAMES.add("gpgme-w32spawn.exe"); // NON-NLS
FILENAMES.add("gpgsm.exe"); // NON-NLS
FILENAMES.add("gpgtar.exe"); // NON-NLS
FILENAMES.add("gpgv.exe"); // NON-NLS
// Symantec Encryption Desktop aka PGP
FILENAMES.add("PGP Viewer.exe"); // NON-NLS
FILENAMES.add("PGPcbt64.exe"); // NON-NLS
FILENAMES.add("PGPdesk.exe"); // NON-NLS
FILENAMES.add("PGPfsd.exe"); // NON-NLS
FILENAMES.add("PGPmnApp.exe"); // NON-NLS
FILENAMES.add("pgpnetshare.exe"); // NON-NLS
FILENAMES.add("pgpp.exe"); // NON-NLS
FILENAMES.add("PGPpdCreate.exe"); // NON-NLS
FILENAMES.add("pgppe.exe"); // NON-NLS
FILENAMES.add("pgpstart.exe"); // NON-NLS
FILENAMES.add("PGPtray.exe"); // NON-NLS
FILENAMES.add("PGPwde.exe"); // NON-NLS
FILENAMES.add("PGP Portable.exe"); // NON-NLS
}
public static String getName() {
return ENCRYPTION_PROGRAMS_RULE_NAME;
}
public static String getDescription() {
return ENCRYPTION_PROGRAMS_RULE_DESCRIPTION;
}
public static List<String> getFilenames() {
return FILENAMES;
}
}

View File

@ -0,0 +1,67 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.configurelogicalimager;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import java.util.ArrayList;
import java.util.List;
/**
* Logical Imager Configuration file JSON
*/
public class LogicalImagerConfig {
@SerializedName("finalize-image-writer")
@Expose(serialize = true)
private boolean finalizeImageWriter;
@SerializedName("rule-sets")
@Expose(serialize = true)
private List<LogicalImagerRuleSet> ruleSets;
public LogicalImagerConfig() {
this.finalizeImageWriter = false;
this.ruleSets = new ArrayList<>();
}
public LogicalImagerConfig(
boolean finalizeImageWriter,
List<LogicalImagerRuleSet> ruleSets
) {
this.finalizeImageWriter = finalizeImageWriter;
this.ruleSets = ruleSets;
}
public boolean isFinalizeImageWriter() {
return finalizeImageWriter;
}
public void setFinalizeImageWriter(boolean finalizeImageWriter) {
this.finalizeImageWriter = finalizeImageWriter;
}
public List<LogicalImagerRuleSet> getRuleSets() {
return ruleSets;
}
public void setRuleSet(List<LogicalImagerRuleSet> ruleSets) {
this.ruleSets = ruleSets;
}
}

View File

@ -0,0 +1,212 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.configurelogicalimager;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.openide.util.NbBundle;
/**
* Logical Imager Configuration JSON deserializer
*/
@NbBundle.Messages({
"LogicalImagerConfigDeserializer.missingRuleSetException=Missing rule-set",
"# {0} - key",
"LogicalImagerConfigDeserializer.unsupportedKeyException=Unsupported key: {0}",
"LogicalImagerConfigDeserializer.fullPathsException=A rule with full-paths cannot have other rule definitions",
})
public class LogicalImagerConfigDeserializer implements JsonDeserializer<LogicalImagerConfig> {
@Override
public LogicalImagerConfig deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) throws JsonParseException {
boolean finalizeImageWriter = false;
final JsonObject jsonObject = je.getAsJsonObject();
final JsonElement jsonFinalizeImageWriter = jsonObject.get("finalize-image-writer"); // NON-NLS
if (jsonFinalizeImageWriter != null) {
finalizeImageWriter = jsonFinalizeImageWriter.getAsBoolean();
}
JsonArray asJsonArray = jsonObject.get("rule-sets").getAsJsonArray(); // NON-NLS
if (asJsonArray == null) {
throw new JsonParseException(Bundle.LogicalImagerConfigDeserializer_missingRuleSetException());
}
List<LogicalImagerRuleSet> ruleSets = new ArrayList<>();
for (JsonElement element: asJsonArray) {
String setName = null;
List<LogicalImagerRule> rules = null;
JsonObject asJsonObject = element.getAsJsonObject();
JsonElement setNameElement = asJsonObject.get("set-name");
setName = setNameElement.getAsString();
JsonElement rulesElement = asJsonObject.get("rules");
rules = parseRules(rulesElement.getAsJsonArray());
LogicalImagerRuleSet ruleSet = new LogicalImagerRuleSet(setName, rules);
ruleSets.add(ruleSet);
}
return new LogicalImagerConfig(finalizeImageWriter, ruleSets);
}
private List<LogicalImagerRule> parseRules(JsonArray asJsonArray) {
List<LogicalImagerRule> rules = new ArrayList<>();
for (JsonElement element: asJsonArray) {
String key1;
Boolean shouldSave = false;
Boolean shouldAlert = true;
String name = null;
String description = null;
List<String> extensions = null;
List<String> paths = null;
List<String> fullPaths = null;
List<String> filenames = null;
Integer minFileSize = null;
Integer maxFileSize = null;
Integer minDays = null;
Integer minDate = null;
Integer maxDate = null;
Set<Map.Entry<String, JsonElement>> entrySet = element.getAsJsonObject().entrySet();
for (Map.Entry<String, JsonElement> entry1 : entrySet) {
key1 = entry1.getKey();
switch (key1) {
case "shouldAlert": // NON-NLS
shouldAlert = entry1.getValue().getAsBoolean();
break;
case "shouldSave": // NON-NLS
shouldSave = entry1.getValue().getAsBoolean();
break;
case "name": // NON-NLS
name = entry1.getValue().getAsString();
break;
case "description": // NON-NLS
description = entry1.getValue().getAsString();
break;
case "extensions": // NON-NLS
JsonArray extensionsArray = entry1.getValue().getAsJsonArray();
extensions = new ArrayList<>();
for (JsonElement e : extensionsArray) {
extensions.add(e.getAsString());
}
break;
case "folder-names": // NON-NLS
JsonArray pathsArray = entry1.getValue().getAsJsonArray();
paths = new ArrayList<>();
for (JsonElement e : pathsArray) {
paths.add(e.getAsString());
}
break;
case "file-names": // NON-NLS
JsonArray filenamesArray = entry1.getValue().getAsJsonArray();
filenames = new ArrayList<>();
for (JsonElement e : filenamesArray) {
filenames.add(e.getAsString());
}
break;
case "full-paths": // NON-NLS
JsonArray fullPathsArray = entry1.getValue().getAsJsonArray();
fullPaths = new ArrayList<>();
for (JsonElement e : fullPathsArray) {
fullPaths.add(e.getAsString());
}
break;
case "size-range": // NON-NLS
JsonObject sizeRangeObject = entry1.getValue().getAsJsonObject();
Set<Map.Entry<String, JsonElement>> entrySet1 = sizeRangeObject.entrySet();
for (Map.Entry<String, JsonElement> entry2 : entrySet1) {
String sizeKey = entry2.getKey();
switch (sizeKey) {
case "min": // NON-NLS
minFileSize = entry2.getValue().getAsInt();
break;
case "max": // NON-NLS
maxFileSize = entry2.getValue().getAsInt();
break;
default:
throw new JsonParseException(Bundle.LogicalImagerConfigDeserializer_unsupportedKeyException(sizeKey));
}
}
break;
case "date-range": // NON-NLS
JsonObject dateRangeObject = entry1.getValue().getAsJsonObject();
Set<Map.Entry<String, JsonElement>> entrySet2 = dateRangeObject.entrySet();
for (Map.Entry<String, JsonElement> entry2 : entrySet2) {
String dateKey = entry2.getKey();
switch (dateKey) {
case "min": // NON-NLS
minDate = entry2.getValue().getAsInt();
break;
case "max": // NON-NLS
maxDate = entry2.getValue().getAsInt();
break;
case "min-days": // NON-NLS
minDays = entry2.getValue().getAsInt();
break;
default:
throw new JsonParseException(Bundle.LogicalImagerConfigDeserializer_unsupportedKeyException(dateKey));
}
}
break;
default:
throw new JsonParseException(Bundle.LogicalImagerConfigDeserializer_unsupportedKeyException(key1));
}
}
// A rule with full-paths cannot have other rule definitions
if ((fullPaths != null && !fullPaths.isEmpty()) && ((extensions != null && !extensions.isEmpty())
|| (paths != null && !paths.isEmpty())
|| (filenames != null && !filenames.isEmpty()))) {
throw new JsonParseException(Bundle.LogicalImagerConfigDeserializer_fullPathsException());
}
LogicalImagerRule rule = new LogicalImagerRule.Builder()
.getShouldAlert(shouldAlert)
.getShouldSave(shouldSave)
.getName(name)
.getDescription(description)
.getExtensions(extensions)
.getPaths(paths)
.getFullPaths(fullPaths)
.getFilenames(filenames)
.getMinFileSize(minFileSize)
.getMaxFileSize(maxFileSize)
.getMinDays(minDays)
.getMinDate(minDate)
.getMaxDate(maxDate)
.build();
rules.add(rule);
} // for
return rules;
}
}

View File

@ -0,0 +1,254 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.configurelogicalimager;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* The class definition for the Logical Imager Rule.
*/
public class LogicalImagerRule {
@Expose(serialize = true)
private final Boolean shouldAlert;
@Expose(serialize = true)
private final Boolean shouldSave;
@Expose(serialize = true)
private final String name;
@Expose(serialize = true)
private final String description;
@Expose(serialize = true)
private List<String> extensions = new ArrayList<>();
@SerializedName("file-names")
@Expose(serialize = true)
private List<String> filenames = new ArrayList<>();
@SerializedName("folder-names")
@Expose(serialize = true)
private List<String> paths = new ArrayList<>();
@SerializedName("full-paths")
@Expose(serialize = true)
private List<String> fullPaths = new ArrayList<>();
@SerializedName("size-range")
@Expose(serialize = true)
final private Map<String, Integer> sizeRange = new HashMap<>();
@SerializedName("date-range")
@Expose(serialize = true)
final private Map<String, Integer> dateRange = new HashMap<>();
// The following fields should not be serialized, internal use only
@Expose(serialize = false)
private Integer minFileSize;
@Expose(serialize = false)
private Integer maxFileSize;
@Expose(serialize = false)
private Integer minDays;
@Expose(serialize = false)
private Integer minDate;
@Expose(serialize = false)
private Integer maxDate;
private LogicalImagerRule(Boolean shouldAlert, Boolean shouldSave, String name, String description,
List<String> extensions,
List<String> filenames,
List<String> paths,
List<String> fullPaths,
Integer minFileSize,
Integer maxFileSize,
Integer minDays,
Integer minDate,
Integer maxDate
) {
this.shouldAlert = shouldAlert;
this.shouldSave = shouldSave;
this.name = name;
this.description = description;
this.extensions = extensions;
this.filenames = filenames;
this.paths = paths;
this.fullPaths = fullPaths;
this.sizeRange.put("min", minFileSize); // NON-NLS
this.minFileSize = minFileSize;
this.sizeRange.put("max", maxFileSize); // NON-NLS
this.maxFileSize = maxFileSize;
this.dateRange.put("min-days", minDays); // NON-NLS
this.minDays = minDays;
this.dateRange.put("min-date", minDate); // NON-NLS
this.minDate = minDate;
this.dateRange.put("max-date", maxDate); // NON-NLS
this.maxDate = maxDate;
}
public LogicalImagerRule() {
this.shouldAlert = false; // default
this.shouldSave = true; // default
this.description = null;
this.name = null;
}
public Boolean isShouldAlert() {
return shouldAlert;
}
public Boolean isShouldSave() {
return shouldSave;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public List<String> getExtensions() {
return extensions;
}
public List<String> getFilenames() {
return filenames;
}
public List<String> getPaths() {
return paths;
}
public List<String> getFullPaths() {
return fullPaths;
}
public Integer getMinFileSize() {
return minFileSize;
}
public Integer getMaxFileSize() {
return maxFileSize;
}
public Integer getMinDays() {
return minDays;
}
public Integer getMinDate() {
return minDate;
}
public Integer getMaxDate() {
return maxDate;
}
/**
* Builder class
*/
public static class Builder {
private Boolean shouldAlert = null;
private Boolean shouldSave = null;
private String name = null;
private String description = null;
private List<String> extensions = null;
private List<String> filenames = null;
private List<String> paths = null;
private List<String> fullPaths = null;
private Integer minFileSize = null;
private Integer maxFileSize = null;
private Integer minDays = null;
private Integer minDate = null;
private Integer maxDate = null;
public Builder getShouldAlert(boolean shouldAlert) {
this.shouldAlert = shouldAlert;
return this;
}
public Builder getShouldSave(boolean shouldSave) {
this.shouldSave = shouldSave;
return this;
}
public Builder getName(String name) {
this.name = name;
return this;
}
public Builder getDescription(String description) {
this.description = description;
return this;
}
public Builder getExtensions(List<String> extensions) {
this.extensions = extensions;
return this;
}
public Builder getFilenames(List<String> filenames) {
this.filenames = filenames;
return this;
}
public Builder getPaths(List<String> paths) {
this.paths = paths;
return this;
}
public Builder getFullPaths(List<String> fullPaths) {
this.fullPaths = fullPaths;
return this;
}
public Builder getMinFileSize(Integer minFileSize) {
this.minFileSize = minFileSize;
return this;
}
public Builder getMaxFileSize(Integer maxFileSize) {
this.maxFileSize = maxFileSize;
return this;
}
public Builder getMinDays(Integer minDays) {
this.minDays = minDays;
return this;
}
public Builder getMinDate(Integer minDate) {
this.minDate = minDate;
return this;
}
public Builder getMaxDate(Integer maxDate) {
this.maxDate = maxDate;
return this;
}
public LogicalImagerRule build() {
return new LogicalImagerRule(shouldAlert, shouldSave, name, description,
extensions, filenames, paths, fullPaths,
minFileSize, maxFileSize,
minDays, minDate, maxDate
);
}
}
}

View File

@ -0,0 +1,63 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.configurelogicalimager;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import java.util.List;
/**
* Logical Imager Rule Set
*/
public class LogicalImagerRuleSet {
@SerializedName("set-name")
@Expose(serialize = true)
final private String setName;
@SerializedName("rules")
@Expose(serialize = true)
private final List<LogicalImagerRule> rules;
public LogicalImagerRuleSet(String setName, List<LogicalImagerRule> rules) {
this.setName = setName;
this.rules = rules;
}
public String getSetName() {
return setName;
}
public List<LogicalImagerRule> getRules() {
return rules;
}
/*
* Find a rule with the given name. Return null if not found.
*/
LogicalImagerRule find(String name) {
for (LogicalImagerRule rule : rules) {
if (rule.getName().equals(name)) {
return rule;
}
}
return null;
}
}

View File

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.9" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="chooseLabel" max="32767" attributes="0"/>
<Component id="chooseComboBox" max="32767" attributes="0"/>
</Group>
<EmptySpace pref="716" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="sharedLayeredPane" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="chooseLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="chooseComboBox" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="sharedLayeredPane" max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="chooseLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/configurelogicalimager/Bundle.properties" key="NewRuleSetPanel.chooseLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="chooseComboBox">
<Properties>
<Property name="maximumRowCount" type="int" value="2"/>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="2">
<StringItem index="0" value="By Attribute"/>
<StringItem index="1" value="By Full Path"/>
</StringArray>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="chooseComboBoxActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
<Container class="javax.swing.JLayeredPane" name="sharedLayeredPane">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="373" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,153 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.configurelogicalimager;
import java.awt.BorderLayout;
import java.io.IOException;
import javax.swing.JButton;
import javax.swing.JPanel;
import org.apache.commons.lang3.tuple.ImmutablePair;
/**
* New rule set panel
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class NewRuleSetPanel extends javax.swing.JPanel {
private final JPanel nonFullPathsJPanel;
private final EditNonFullPathsRulePanel editNonFullPathsRulePanel;
private final JPanel fullPathsPanel;
private final EditFullPathsRulePanel editFullPathsRulePanel;
/**
* Creates new form NewRuleSetPanel
*/
public NewRuleSetPanel(JButton okButton, JButton cancelButton) {
initComponents();
nonFullPathsJPanel = createPanel();
editNonFullPathsRulePanel = new EditNonFullPathsRulePanel(okButton, cancelButton, "", new LogicalImagerRule(), false);
nonFullPathsJPanel.add(editNonFullPathsRulePanel, BorderLayout.NORTH);
fullPathsPanel = createPanel();
editFullPathsRulePanel = new EditFullPathsRulePanel(okButton, cancelButton, "", new LogicalImagerRule(), false);
fullPathsPanel.add(editFullPathsRulePanel, BorderLayout.NORTH);
sharedLayeredPane.add(nonFullPathsJPanel, Integer.valueOf(0));
sharedLayeredPane.add(fullPathsPanel, Integer.valueOf(1));
nonFullPathsJPanel.setVisible(true);
fullPathsPanel.setVisible(false);
}
private JPanel createPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setSize(800, 640);
return panel;
}
/**
* 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
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
chooseLabel = new javax.swing.JLabel();
chooseComboBox = new javax.swing.JComboBox<>();
sharedLayeredPane = new javax.swing.JLayeredPane();
org.openide.awt.Mnemonics.setLocalizedText(chooseLabel, org.openide.util.NbBundle.getMessage(NewRuleSetPanel.class, "NewRuleSetPanel.chooseLabel.text")); // NOI18N
chooseComboBox.setMaximumRowCount(2);
chooseComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "By Attribute", "By Full Path" }));
chooseComboBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
chooseComboBoxActionPerformed(evt);
}
});
javax.swing.GroupLayout sharedLayeredPaneLayout = new javax.swing.GroupLayout(sharedLayeredPane);
sharedLayeredPane.setLayout(sharedLayeredPaneLayout);
sharedLayeredPaneLayout.setHorizontalGroup(
sharedLayeredPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 0, Short.MAX_VALUE)
);
sharedLayeredPaneLayout.setVerticalGroup(
sharedLayeredPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 373, Short.MAX_VALUE)
);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(chooseLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(chooseComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap(716, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(sharedLayeredPane)
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(chooseLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(chooseComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(sharedLayeredPane)
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents
private void chooseComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chooseComboBoxActionPerformed
int index = chooseComboBox.getSelectedIndex();
if (index == 0) {
nonFullPathsJPanel.setVisible(true);
fullPathsPanel.setVisible(false);
} else {
nonFullPathsJPanel.setVisible(false);
fullPathsPanel.setVisible(true);
}
}//GEN-LAST:event_chooseComboBoxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JComboBox<String> chooseComboBox;
private javax.swing.JLabel chooseLabel;
private javax.swing.JLayeredPane sharedLayeredPane;
// End of variables declaration//GEN-END:variables
ImmutablePair<String, LogicalImagerRule> toRule() throws IOException, NumberFormatException {
ImmutablePair<String, LogicalImagerRule> ruleMap;
if (chooseComboBox.getSelectedIndex() == 0) {
ruleMap = editNonFullPathsRulePanel.toRule();
} else {
ruleMap = editFullPathsRulePanel.toRule();
}
return ruleMap;
}
}

View File

@ -35,10 +35,18 @@ public final class TextPrompt extends JLabel
private int focusLost; private int focusLost;
public TextPrompt(String text, JTextComponent component) { public TextPrompt(String text, JTextComponent component) {
this(text, component, Show.ALWAYS); this(text, component, Show.ALWAYS, null);
} }
public TextPrompt(String text, JTextComponent component, Show show) { public TextPrompt(String text, JTextComponent component, Show show) {
this(text, component, show, null);
}
public TextPrompt(String text, JTextComponent component, String layoutConstraint) {
this(text, component, Show.ALWAYS, layoutConstraint);
}
public TextPrompt(String text, JTextComponent component, Show show, String layoutConstraint) {
this.component = component; this.component = component;
component.removeAll(); component.removeAll();
setShow(show); setShow(show);
@ -54,7 +62,11 @@ public final class TextPrompt extends JLabel
document.addDocumentListener(this); document.addDocumentListener(this);
component.setLayout(new BorderLayout()); component.setLayout(new BorderLayout());
if (layoutConstraint == null) {
component.add(this); component.add(this);
} else {
component.add(this, layoutConstraint);
}
checkForPrompt(); checkForPrompt();
} }

View File

View File

@ -89,6 +89,7 @@ public final class FileTypeUtils {
"application/json", //NON-NLS "application/json", //NON-NLS
"application/javascript", //NON-NLS "application/javascript", //NON-NLS
"application/xml", //NON-NLS "application/xml", //NON-NLS
"application/xhtml+xml", //NON-NLS
"application/x-msoffice", //NON-NLS "application/x-msoffice", //NON-NLS
"application/x-ooxml", //NON-NLS "application/x-ooxml", //NON-NLS
"application/msword", //NON-NLS "application/msword", //NON-NLS

View File

@ -47,7 +47,10 @@ class EmailMessage {
private long id = -1L; private long id = -1L;
private String messageID = ""; private String messageID = "";
private String inReplyToID = ""; private String inReplyToID = "";
private List<String> references = null; private List<String> references = new ArrayList();
private String simplifiedSubject = "";
private boolean replySubject = false;
private String messageThreadID = "";
boolean hasAttachment() { boolean hasAttachment() {
return hasAttachment; return hasAttachment;
@ -80,7 +83,33 @@ class EmailMessage {
void setSubject(String subject) { void setSubject(String subject) {
if (subject != null) { if (subject != null) {
this.subject = subject; this.subject = subject;
if(subject.matches("^[R|r][E|e].*?:.*")) {
this.simplifiedSubject = subject.replaceAll("[R|r][E|e].*?:", "").trim();
replySubject = true;
} else {
this.simplifiedSubject = subject;
} }
} else {
this.simplifiedSubject = "";
}
}
/**
* Returns the orginal subject with the "RE:" stripped off".
*
* @return Message subject with the "RE" stripped off
*/
String getSimplifiedSubject() {
return simplifiedSubject;
}
/**
* Returns whether or not the message subject started with "RE:"
*
* @return true if the original subject started with RE otherwise false.
*/
boolean isReplySubject() {
return replySubject;
} }
String getHeaders() { String getHeaders() {
@ -224,14 +253,14 @@ class EmailMessage {
* Returns a list of Message-IDs listing the parent, grandparent, * Returns a list of Message-IDs listing the parent, grandparent,
* great-grandparent, and so on, of this message. * great-grandparent, and so on, of this message.
* *
* @return reference list or empty string if non is available. * @return The reference list or empty string if none is available.
*/ */
List<String> getReferences() { List<String> getReferences() {
return references; return references;
} }
/** /**
* Set the list of reference message-IDs. * Set the list of reference message-IDs from the email message header.
* *
* @param references * @param references
*/ */
@ -239,6 +268,24 @@ class EmailMessage {
this.references = references; this.references = references;
} }
/**
* Sets the ThreadID of this message.
*
* @param threadID - the thread ID to set
*/
void setMessageThreadID(String threadID) {
this.messageThreadID = threadID;
}
/**
* Returns the ThreadID for this message.
*
* @return - the message thread ID or "" is non is available
*/
String getMessageThreadID() {
return this.messageThreadID;
}
/** /**
* A Record to hold generic information about attachments. * A Record to hold generic information about attachments.
* *

View File

@ -0,0 +1,700 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.thunderbirdparser;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Given a list of email messages arranges the message into threads using the
* message reference lists.
*
* This threader is based heavely off of the algorithum found at
* <a href="https://www.jwz.org/doc/threading.html">
* "message threading." by Jamie Zawinski</a>
*
*/
final class EmailMessageThreader {
private int bogus_id_count = 0;
private EmailMessageThreader(){}
public static void threadMessages(List<EmailMessage> emailMessages, String threadIDPrefix) {
EmailMessageThreader instance = new EmailMessageThreader();
Map<String, EmailContainer> id_table = instance.createIDTable(emailMessages);
Set<EmailContainer> rootSet = instance.getRootSet(id_table);
instance.pruneEmptyContainers(rootSet);
Set<EmailContainer> finalRootSet = instance.groupBySubject(rootSet);
instance.assignThreadIDs(finalRootSet, threadIDPrefix);
}
/**
* Walks the list of emailMessages creating a Container object for each
* unique message ID found. Adds the emailMessage to the container where
* possible.
*
* @param emailMessages
*
* @return - HashMap of all message where the key is the message-ID of the message
*/
private Map<String, EmailContainer> createIDTable(List<EmailMessage> emailMessages) {
HashMap<String, EmailContainer> id_table = new HashMap<>();
for (EmailMessage message : emailMessages) {
String messageID = message.getMessageID();
// Check the id_table for an existing Container for message-id
EmailContainer container = id_table.get(messageID);
// An existing container for message-id was found
if (container != null) {
// If the existing Container has a message already assocated with it
// emailMessage maybe a duplicate, so we don't lose the existance of
// the duplicate message assign it a bogus message-id
if (container.hasMessage()) {
messageID = String.format("<Bogus-id: %d >", bogus_id_count++);
container = null;
} else {
container.setMessage(message);
}
}
if (container == null) {
container = new EmailContainer(message);
id_table.put(messageID, container);
}
processMessageReferences(message, container, id_table);
}
return id_table;
}
/**
* Loops throught message's list of references, creating objects as needed
* and setting up the parent child relationships amoung the messages.
*
* @param message The current email messags
* @param container Container object for message
* @param id_table Hashtable of known message-id\container pairs
*/
void processMessageReferences(EmailMessage message, EmailContainer container, Map<String, EmailContainer> id_table) {
List<String> referenceList = message.getReferences();
// Make sure the inReplyToID is in the list of references
String inReplyToID = message.getInReplyToID();
if (inReplyToID != null && !inReplyToID.isEmpty()) {
if (referenceList == null) {
referenceList = new ArrayList<>();
}
referenceList.add(inReplyToID);
}
// No references, nothing to do
if (referenceList == null) {
return;
}
EmailContainer parent_ref = null;
EmailContainer ref;
for (String refID : referenceList) {
// Check id_table to see if there is already a container for this
// reference id, if not create a new Container and add to table
ref = id_table.get(refID);
if (ref == null) {
ref = new EmailContainer();
id_table.put(refID, ref);
}
// Set the parent\child relationship between parent_ref and ref
if (parent_ref != null
&& !ref.hasParent()
&& !parent_ref.equals(ref)
&& !parent_ref.isChild(ref)) {
ref.setParent(parent_ref);
parent_ref.addChild(ref);
}
parent_ref = ref;
}
// If the parent_ref and container are already linked, don't change
// anything
if (parent_ref != null
&& (parent_ref.equals(container)
|| container.isChild(parent_ref))) {
parent_ref = null;
}
// If container already has a parent, the parent was assumed based on
// the list of references from another message. parent_ref will be
// the real parent of container so throw away the old parent and set a
// new one.
if (container.hasParent()) {
container.getParent().removeChild(container);
container.setParent(null);
}
if (parent_ref != null) {
container.setParent(container);
parent_ref.addChild(container);
}
}
/**
* Creates a set of root container messages from the message-ID hashtable. A
* root Container is container that does not have a parent container.
*
* @param id_table Table of all known Containers
*
* @return A set of the root containers.
*/
Set<EmailContainer> getRootSet(Map<?, EmailContainer> id_table) {
HashSet<EmailContainer> rootSet = new HashSet<>();
id_table.values().stream().filter((container)
-> (!container.hasParent())).forEachOrdered((container) -> {
rootSet.add(container);
});
return rootSet;
}
/**
* Remove Containers from containerSet if they do not have a message or
* children.
*
* @param containerSet A set of Container objects
*/
void pruneEmptyContainers(Set<EmailContainer> containerSet) {
Set<EmailContainer> containersToRemove = new HashSet<>();
containerSet.forEach((container) -> {
if (!container.hasMessage() && !container.hasChildren()) {
containersToRemove.add(container);
} else {
pruneChildren(container);
}
});
containerSet.removeAll(containersToRemove);
}
/**
* Recursively work through the list of parent's children removing empty
* containers. If the passed in container does not have a message
* associated with it, it will get removed and its children will be assigned
* to their grandparent.
*
* @param parent returns true if their where children pruned, otherwise false.
*/
boolean pruneChildren(EmailContainer parent) {
if (parent == null) {
return false;
}
Set<EmailContainer> children = parent.getChildren();
if (children == null) {
return false;
}
EmailContainer grandParent = parent.getParent();
Set<EmailContainer> remove = new HashSet<>();
Set<EmailContainer> add = new HashSet<>();
for (EmailContainer child : parent.getChildren()) {
if (pruneChildren(child)) {
remove.add(child);
add.addAll(child.getChildren());
child.setParent(null);
child.clearChildren();
}
}
parent.addChildren(add);
parent.removeChildren(remove);
if (!parent.hasMessage() && grandParent != null) {
children.forEach((child) -> {
child.setParent(grandParent);
});
return true;
}
return false;
}
/**
* Now that the emails are grouped together by references\message ID take
* another pass through and group together messages with the same simplified
* subject.
*
* The purpose of grouping by subject is to bring threads together that may
* been separated due to missing messages. Group by subject to put attempt
* to put these threads together.
*
* This may cause "root" messages with identical subjects to get grouped
* together as children of an empty container. The code that uses the thread
* information can decide what to do in that situation as those message
* maybe part of a common thread or maybe their own unique messages.
*
* @param rootSet
*
* @return Final set of threaded messages.
*/
Set<EmailContainer> groupBySubject(Set<EmailContainer> rootSet) {
Map<String, EmailContainer> subject_table = createSubjectTable(rootSet);
Set<EmailContainer> finalSet = new HashSet<>();
for (EmailContainer rootSetContainer : rootSet) {
String rootSubject = rootSetContainer.getSimplifiedSubject();
EmailContainer tableContainer = subject_table.get(rootSubject);
if (tableContainer == null || tableContainer.equals(rootSetContainer)) {
finalSet.add(rootSetContainer);
continue;
}
// If both containers are dummy/empty append the children of one to the other
if (tableContainer.getMessage() == null && rootSetContainer.getMessage() == null) {
tableContainer.addChildren(rootSetContainer.getChildren());
rootSetContainer.clearChildren();
continue;
}
// one container is empty, but the other is not, make the non-empty one be a
// child of the empty
if ((tableContainer.getMessage() == null && rootSetContainer.getMessage() != null)
|| (tableContainer.getMessage() != null && rootSetContainer.getMessage() == null)) {
if (tableContainer.getMessage() == null) {
tableContainer.addChild(rootSetContainer);
} else {
rootSetContainer.addChild(tableContainer);
subject_table.remove(rootSubject, tableContainer);
subject_table.put(rootSubject, rootSetContainer);
finalSet.add(rootSetContainer);
}
continue;
}
// tableContainer is non-empty and it's message's subject does not begin
// with 'RE:' but rootSetContainer's message does begin with 'RE:', then
// make rootSetContainer a child of tableContainer
if (tableContainer.getMessage() != null
&& !tableContainer.isReplySubject()
&& rootSetContainer.isReplySubject()) {
tableContainer.addChild(rootSetContainer);
continue;
}
// If table container is non-empy, and table container's subject does
// begin with 'RE:', but rootSetContainer does not start with 'RE:'
// make tableContainer a child of rootSetContainer
if (tableContainer.getMessage() != null
&& tableContainer.isReplySubject()
&& !rootSetContainer.isReplySubject()) {
rootSetContainer.addChild(tableContainer);
subject_table.put(rootSubject, rootSetContainer);
finalSet.add(rootSetContainer);
continue;
}
// rootSetContainer and tableContainer either both have 'RE' or
// don't. Create a new dummy container with both containers as
// children.
EmailContainer newParent = new EmailContainer();
newParent.addChild(tableContainer);
newParent.addChild(rootSetContainer);
subject_table.remove(rootSubject, tableContainer);
subject_table.put(rootSubject, newParent);
finalSet.add(newParent);
}
return finalSet;
}
/**
* Creates a Hashtable of Container unique subjects. There will be one
* Container subject pair for each unique subject.
*
* @param rootSet The set of "root" Containers
*
* @return The subject hashtable
*/
Map<String, EmailContainer> createSubjectTable(Set<EmailContainer> rootSet) {
HashMap<String, EmailContainer> subject_table = new HashMap<>();
for (EmailContainer rootSetContainer : rootSet) {
String subject = "";
boolean reSubject = false;
if (rootSetContainer.hasMessage()) {
subject = rootSetContainer.getMessage().getSimplifiedSubject();
reSubject = rootSetContainer.getMessage().isReplySubject();
} else if (rootSetContainer.hasChildren()) {
Iterator<EmailContainer> childrenIterator = rootSetContainer.getChildren().iterator();
while (childrenIterator.hasNext()) {
EmailMessage childMessage = childrenIterator.next().getMessage();
if (childMessage != null) {
subject = childMessage.getSimplifiedSubject();
if (!subject.isEmpty()) {
reSubject = childMessage.isReplySubject();
break;
}
}
}
}
if (subject == null || subject.isEmpty()) {
continue; // Give up on this container
}
EmailContainer tableContainer = subject_table.get(subject);
// A container will be added to the table, if a container for its "simplified" subject
// does not currently exist in the table. Or if there is more than one container with the same
// subject, but one is an "empty container" the empty one will be added
// the table or in the one in the table has "RE" in the subject it will be replaced
// by the one that does not have "RE" in the subject (if it exists)
//
if (tableContainer == null ||
(tableContainer.getMessage() != null && rootSetContainer.getMessage() == null) ||
(!reSubject && (tableContainer.getMessage() != null && tableContainer.getMessage().isReplySubject()))) {
subject_table.put(subject, rootSetContainer);
}
}
return subject_table;
}
/**
* Assign "threadIDs" for each thread. It is assumed that each member of
* containerSet is a unique message thread.
*
* ThreadIDs will only be unique between runs if "IDPrefix" is unique between
* runs of the algorithm.
*
* @param containerSet A set of "root" containers
*
* @param IDPrefix A string to make the threadIDs unique.
*/
private void assignThreadIDs(Set<EmailContainer> containerSet, String IDPrefix) {
int threadCounter = 0;
for(EmailContainer container: containerSet) {
// Generate a threadID
String threadID = String.format("%s-%d", IDPrefix, threadCounter++);
// Add the IDs to this thread
addThreadID(container, threadID);
}
}
/**
* Recursively walk container's children adding the thread ID to
* the EmailMessage objects.
*
* @param container The root container of a set of related container objects
* @param threadID The String to assign as the "threadId" for this set of
* messages
*/
private void addThreadID(EmailContainer container, String threadID) {
if(container == null) {
return;
}
EmailMessage message = container.getMessage();
if(message != null) {
message.setMessageThreadID(threadID);
}
if(container.hasChildren()) {
for(EmailContainer child: container.getChildren()) {
addThreadID(child, threadID);
}
}
}
/**
* The container object is used to wrap and email message and track the
* messages parent and child messages.
*/
final class EmailContainer {
private EmailMessage message;
private EmailContainer parent;
private Set<EmailContainer> children;
/**
* Constructs an empty container.
*/
EmailContainer() {
// This constructor is intentially empty to allow for the creation of
// an EmailContainer without a message
}
/**
* Constructs a new Container object with the given EmailMessage.
*
* @param message Returns the message, or null if one was not set
*/
EmailContainer(EmailMessage message) {
this.message = message;
}
/**
* Returns the EmailMessage object.
*
* @return Then EmailMessage object or null if one was not set
*/
EmailMessage getMessage() {
return message;
}
/**
* Set the Container EmailMessage object.
*
* @param message - The container EmailMessage
*/
void setMessage(EmailMessage message) {
this.message = message;
}
/**
* Return whether or not this Container has a valid EmailMessage object.
*
* @return True if EmailMessage has been set otherwise false
*/
boolean hasMessage() {
return message != null;
}
/**
* Returns the Simplified Subject (original subject without RE:) of the
* EmailMessage or if this is an empty Container with Children, return
* the simplified subject of one of the children.
*
* @return Simplified subject of this Container
*/
String getSimplifiedSubject() {
String subject = "";
if (message != null) {
subject = message.getSimplifiedSubject();
} else if (children != null) {
for (EmailContainer child : children) {
if (child.hasMessage()) {
subject = child.getSimplifiedSubject();
}
if (subject != null && !subject.isEmpty()) {
break;
}
}
}
return subject;
}
/**
* Simialar to getSimplifiedSubject, isReplySubject is a helper function
* that will return the isReplySubject of the Containers message or if
* this is an empty container, the state of one of the children.
*
* @return
*/
boolean isReplySubject() {
if (message != null) {
return message.isReplySubject();
} else if (children != null) {
for (EmailContainer child : children) {
if (child.hasMessage()) {
boolean isReply = child.isReplySubject();
if (isReply) {
return isReply;
}
}
}
}
return false;
}
/**
* Returns the parent Container of this Container.
*
* @return The Container parent or null if one is not set
*/
EmailContainer getParent() {
return parent;
}
/**
* Sets the given container as the parent of this object.
*
* @param container - the object to set as the parent
*/
void setParent(EmailContainer container) {
parent = container;
}
/**
* Returns true if a parent object is current set.
*
* @return True if this container has a parent otherwise false
*/
boolean hasParent() {
return parent != null;
}
/**
* Adds the specified Container to the list of children.
*
* @param child - the Container to add to the child list
*
* @return true, if the element was added to the children list
*/
boolean addChild(EmailContainer child) {
if (children == null) {
children = new HashSet<>();
}
return children.add(child);
}
/**
* Adds to the list of children all of the elements that are contained
* in the specified collection.
*
* @param children - set containing the Containers to be added to the
* list of children
*
* @return true if the list of children was changed as a result of this
* call
*/
boolean addChildren(Set<EmailContainer> children) {
if (children == null || children.isEmpty()) {
return false;
}
if (this.children == null) {
this.children = new HashSet<>();
}
return this.children.addAll(children);
}
/**
* Removes from the children list all of the elements that are contained
* in the specified collection.
*
* @param children - set containing the elements to be removed from the
* list of children
*
* @return true if the set was changed as a result of this call
*/
boolean removeChildren(Set<EmailContainer> children) {
if (children != null) {
return this.children.removeAll(children);
}
return false;
}
/**
* Clears the Containers list of children.
*
*/
void clearChildren() {
if( children != null ) {
children.clear();
}
}
/**
* Removes the given container from the list of children.
*
* @param child - the container to remove from the children list
*
* @return - True if the given container successfully removed from the
* list of children
*/
boolean removeChild(EmailContainer child) {
if(children != null) {
return children.remove(child);
} else {
return false;
}
}
/**
* Returns whether or not this container has children.
*
* @return True if the child list is not null or empty
*/
boolean hasChildren() {
return children != null && !children.isEmpty();
}
/**
* Returns the list of children of this container.
*
* @return The child list or null if a child has not been added.
*/
Set<EmailContainer> getChildren() {
return children;
}
/**
* Search all of this containers children to make sure that the given
* container is not a related.
*
* @param container - the container object to search for
*
* @return True if the given container is in the child tree of this
* container, false otherwise.
*/
boolean isChild(EmailContainer container) {
if (children == null || children.isEmpty()) {
return false;
} else if (children.contains(container)) {
return true;
} else {
return children.stream().anyMatch((child) -> (child.isChild(container)));
}
}
}
}

View File

@ -410,7 +410,13 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
private void processEmails(List<EmailMessage> emails, AbstractFile abstractFile) { private void processEmails(List<EmailMessage> emails, AbstractFile abstractFile) {
List<AbstractFile> derivedFiles = new ArrayList<>(); List<AbstractFile> derivedFiles = new ArrayList<>();
// Putting try/catch around this to catch any exception and still allow
// the creation of the artifacts to continue.
try{
EmailMessageThreader.threadMessages(emails, String.format("%d", abstractFile.getId()));
} catch(Exception ex) {
logger.log(Level.WARNING, String.format("Exception thrown parsing emails from %s", abstractFile.getName()), ex);
}
for (EmailMessage email : emails) { for (EmailMessage email : emails) {
BlackboardArtifact msgArtifact = addEmailArtifact(email, abstractFile); BlackboardArtifact msgArtifact = addEmailArtifact(email, abstractFile);
@ -510,6 +516,7 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
String subject = email.getSubject(); String subject = email.getSubject();
long id = email.getId(); long id = email.getId();
String localPath = email.getLocalPath(); String localPath = email.getLocalPath();
String threadID = email.getMessageThreadID();
List<String> senderAddressList = new ArrayList<>(); List<String> senderAddressList = new ArrayList<>();
String senderAddress; String senderAddress;
@ -567,6 +574,7 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
addArtifactAttribute(cc, ATTRIBUTE_TYPE.TSK_EMAIL_CC, bbattributes); addArtifactAttribute(cc, ATTRIBUTE_TYPE.TSK_EMAIL_CC, bbattributes);
addArtifactAttribute(bodyHTML, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML, bbattributes); addArtifactAttribute(bodyHTML, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML, bbattributes);
addArtifactAttribute(rtf, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF, bbattributes); addArtifactAttribute(rtf, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF, bbattributes);
addArtifactAttribute(threadID, ATTRIBUTE_TYPE.TSK_THREAD_ID, bbattributes);
try { try {