Add interesting items module

Add factory and file ingest module skeletons for intersing items identifier module

Add additional classes to interestingitems package

Add getDefaultIngestJobSettings() impl to InterestingItemsIngestModuleFactory

Add more capability to interesting file set definitions and rules

Moved interesting items codwe closer to first version completion

Simplify interesting file rule classes and partially complete XM parse/write methpds

Flesh out more of InterestingItemDefinitions class

Continue work on interesting items module

Fix InterestingFilesIdentifierJobSettingsPanel bug

Begin implementation of global settings for interesting items module

Continue implementing global settings panel for interesting items module

Add new and edit interesting files set and files set rule dialog skeletons

Add copy contructors to FilesSet clases in interestingitems package

Implement new, edit and delete buttons for interesting item defs panel

Work on rule create, edit and delete capabilities for interesting files sets

Debug user interactions code for interesting item defs panel

Correct component interactions in InterestingItemDefsPanel

Debug/improve interesting files ingest module

Fix interesting files regex filters

Tie up loose ends for interesting items module

Fix comment in interesting items module

Fix warnings in interesting items module

Fix bugs in interesting items module

Apply fixes to interesting items modules

Implement fixes and artifact display changes for interesting file set hits

Added/updated some comments in the interesting items module
This commit is contained in:
Richard Cordovano 2014-08-12 14:09:35 -04:00
parent 2153ca3201
commit a76b840200
26 changed files with 4701 additions and 11 deletions

View File

@ -59,6 +59,7 @@ import org.sleuthkit.datamodel.SleuthkitJNI.CaseDbHandle.AddImageProcess;
* open at a time. Use getCurrentCase() to retrieve the object for the current
* case.
*/
@SuppressWarnings("deprecation") // TODO: Remove this when ErrorObserver is replaced.
public class Case implements SleuthkitCase.ErrorObserver {
private static final String autopsyVer = Version.getVersion(); // current version of autopsy. Change it when the version is changed

View File

@ -44,8 +44,8 @@ import org.sleuthkit.datamodel.TskException;
*/
public class BlackboardArtifactNode extends DisplayableItemNode {
private BlackboardArtifact artifact;
private Content associated;
private final BlackboardArtifact artifact;
private final Content associated;
private List<NodeProperty<? extends Object>> customProperties;
static final Logger logger = Logger.getLogger(BlackboardArtifactNode.class.getName());
/**
@ -58,6 +58,13 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(),
};
// TODO: This is an unattractive alternative to subclassing BlackboardArtifactNode,
// cut from the same cloth as the equally unattractive SHOW_UNIQUE_PATH array
// above. It should be removed when and if the subclassing is implemented.
private static final Integer[] SHOW_FILE_METADATA = new Integer[] {
BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(),
};
/**
* Construct blackboard artifact node from an artifact and using provided
* icon
@ -179,6 +186,30 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
NO_DESCR,
sourcePath));
}
if (Arrays.asList(SHOW_FILE_METADATA).contains(artifactTypeId)) {
AbstractFile file = associated instanceof AbstractFile ? (AbstractFile)associated : null;
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileModifiedTime.name"),
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileModifiedTime.displayName"),
"",
file != null ? ContentUtils.getStringTime(file.getMtime(), file) : ""));
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileChangedTime.name"),
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileChangedTime.displayName"),
"",
file != null ? ContentUtils.getStringTime(file.getCtime(), file) : ""));
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileAccessedTime.name"),
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileAccessedTime.displayName"),
"",
file != null ? ContentUtils.getStringTime(file.getAtime(), file) : ""));
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileCreatedTime.name"),
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileCreatedTime.displayName"),
"",
file != null ? ContentUtils.getStringTime(file.getCrtime(), file) : ""));
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.name"),
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.displayName"),
"",
associated.getSize()));
}
} else {
String dataSourceStr = "";
try {
@ -225,7 +256,7 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
* @param np NodeProperty to add
*/
public <T> void addNodeProperty(NodeProperty<T> np) {
if (customProperties == null) {
if (null == customProperties) {
//lazy create the list
customProperties = new ArrayList<>();
}
@ -240,6 +271,7 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
* put
* @param artifact to extract properties from
*/
@SuppressWarnings("deprecation") // TODO: Remove this when TSK_TAGGED_ARTIFACT rows aer removed in a database upgrade.
private void fillPropertyMap(Map<String, Object> map, BlackboardArtifact artifact) {
try {
for (BlackboardAttribute attribute : artifact.getAttributes()) {
@ -247,8 +279,8 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
//skip some internal attributes that user shouldn't see
if (attributeTypeID == ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID()
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID()
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) {
continue;
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) {
} else {
switch (attribute.getValueType()) {
case STRING:
@ -337,7 +369,6 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
List<BlackboardAttribute> attributes = artifact.getAttributes();
String keyword = null;
String regexp = null;
String origQuery = null;
for (BlackboardAttribute att : attributes) {
final int attributeTypeID = att.getAttributeTypeID();
if (attributeTypeID == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) {
@ -348,6 +379,7 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
}
if (keyword != null) {
boolean isRegexp = (regexp != null && !regexp.equals(""));
String origQuery;
if (isRegexp) {
origQuery = regexp;
} else {
@ -410,9 +442,9 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
return "encrypted-file.png"; //NON-NLS
case TSK_EXT_MISMATCH_DETECTED:
return "mismatch-16.png"; //NON-NLS
default:
return "artifact-icon.png"; //NON-NLS
}
return "artifact-icon.png"; //NON-NLS
}
@Override

View File

@ -108,7 +108,7 @@ public class InterestingHits implements AutopsyVisitableItem {
String value = rs.getString("value_text"); //NON-NLS
long artifactId = rs.getLong("artifact_id"); //NON-NLS
if (!interestingItemsMap.containsKey(value)) {
interestingItemsMap.put(value, new HashSet<Long>());
interestingItemsMap.put(value, new HashSet<>());
}
interestingItemsMap.get(value).add(artifactId);
}
@ -238,7 +238,7 @@ public class InterestingHits implements AutopsyVisitableItem {
}
public class SetNameNode extends DisplayableItemNode implements Observer {
private String setName;
private final String setName;
public SetNameNode(String setName) {//, Set<Long> children) {
super(Children.create(new HitFactory(setName), true), Lookups.singleton(setName));
this.setName = setName;
@ -286,7 +286,7 @@ public class InterestingHits implements AutopsyVisitableItem {
}
private class HitFactory extends ChildFactory<Long> implements Observer {
private String setName;
private final String setName;
private HitFactory(String setName) {
super();

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 686 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,36 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 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.ingest;
import org.sleuthkit.datamodel.Content;
/**
* An adapter that provides a no-op implementation of the startUp() method for
* data source ingest modules.
*/
public abstract class DataSourceIngestModuleAdapter implements DataSourceIngestModule {
@Override
public void startUp(IngestJobContext context) throws IngestModuleException {
}
@Override
public abstract ProcessResult process(Content dataSource, DataSourceIngestModuleProgress progressBar);
}

View File

@ -0,0 +1,39 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 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.ingest;
import org.sleuthkit.datamodel.AbstractFile;
/**
* An adapter that provides no-op implementations of the startUp() and
* shutDown() methods for file ingest modules.
*/
public abstract class FileIngestModuleAdapter implements FileIngestModule {
@Override
public void startUp(IngestJobContext context) throws IngestModuleException {
}
@Override
public abstract ProcessResult process(AbstractFile file);
@Override
public void shutDown() {
}
}

View File

@ -36,6 +36,7 @@ import org.sleuthkit.autopsy.modules.exif.ExifParserModuleFactory;
import org.sleuthkit.autopsy.modules.fileextmismatch.FileExtMismatchDetectorModuleFactory;
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeIdModuleFactory;
import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupModuleFactory;
import org.sleuthkit.autopsy.modules.interestingitems.InterestingItemsIngestModuleFactory;
import org.sleuthkit.autopsy.modules.sevenzip.ArchiveFileExtractorModuleFactory;
import org.sleuthkit.autopsy.python.JythonModuleLoader;
@ -58,6 +59,7 @@ final class IngestModuleFactoryLoader {
add(FileExtMismatchDetectorModuleFactory.class.getCanonicalName());
add(E01VerifierModuleFactory.class.getCanonicalName());
add(AndroidModuleFactory.class.getCanonicalName());
add(InterestingItemsIngestModuleFactory.class.getCanonicalName());
}
};

View File

@ -0,0 +1,64 @@
OpenIDE-Module-Display-Category=Ingest Module
OpenIDE-Module-Long-Description=Interesting Files Identifier ingest module. \n\n Identifies interesting files as defined by interesting files rule sets.
OpenIDE-Module-Short-Description=Interesting Files Identifier ingest module.
OpenIDE-Module-Name=Interesting Files Identifier
InterestingItemsIdentifierIngestModule.moduleName=Interesting Files Identifier
InterestingItemsIdentifierIngestModule.moduleDescription=Identifies interesting items as defined by interesting item rule sets.
InterestingFilesIdentifierJobSettingsPanel.filesSetTable.columnModel.title0=Title 1
InterestingFilesIdentifierJobSettingsPanel.filesSetTable.columnModel.title3=Title 4
InterestingFilesIdentifierJobSettingsPanel.filesSetTable.columnModel.title2=Title 3
InterestingFilesIdentifierJobSettingsPanel.filesSetTable.columnModel.title1=Title 2
InterestingItemDefsPanel.newSetButton.text=New Set...
InterestingItemDefsPanel.editSetButton.text=Edit Set...
InterestingItemDefsPanel.deleteSetButton.text=Delete Set
InterestingItemDefsPanel.newRuleButton.text=New Rule...
InterestingItemDefsPanel.editRuleButton.text=Edit Rule...
InterestingItemDefsPanel.deleteRuleButton.text=Delete Rule
InterestingItemDefsPanel.ruleNameTextField.text=
InterestingItemDefsPanel.setsListLabel.text=Interesting Files Set Definitions:
InterestingItemDefsPanel.selectedSetLabel.text=Selected Set:
InterestingItemDefsPanel.rulesListLabel.text=Rules:
InterestingItemDefsPanel.selectedRuleLabel.text=Selected Rule:
InterestingItemDefsPanel.setDescPanel.border.title=Description
FilesSetPanel.title=Interesting Files Set
FilesSetPanel.messages.filesSetsMustBeNamed=Interesting files sets must be named.
FilesSetPanel.ignoreKnownFilesCheckbox.text=Ignore Known Files
FilesSetPanel.descriptionPanel.border.title=Description
FilesSetPanel.nameLabel.text=Set Name:
FilesSetPanel.descPanel.border.title=Description
FilesSetRulePanel.title=Interesting Files Set Rule
FilesSetRulePanel.extensionRadioButton.text=Extension Only
FilesSetRulePanel.pathPanel.border.title=With parent path:
FilesSetRulePanel.pathRegexCheckBox.text=Regex
FilesSetRulePanel.pathTextField.text=
FilesSetRulePanel.fullNameRadioButton.text=Full Name
FilesSetRulePanel.nameRegexCheckbox.text=Regex
FilesSetRulePanel.namePanel.AccessibleContext.accessibleName=Name
FilesSetRulePanel.namePanel.border.title=Named:
FilesSetRulePanel.ruleNameTextField.text=
FilesSetRulePanel.nameTextField.text=
FilesSetRulePanel.ruleNameLabel.text=Rule Name:
FilesSetRulePanel.typePanel.border.title=Search for:
FilesSetRulePanel.messages.filesSetRulesMustBeNamed=Interesting files set rules must be named.
FilesSetRulePanel.messages.emptyNameFilter=Interesting files sets rules must have a name for which to search.
FilesSetRulePanel.messages.invalidNameRegex=The name regular expression is not valid:\n\n{0}
FilesSetRulePanel.messages.invalidCharInName=The name cannot contain \\, /, :, *, ?, \", <, or > unless it is a regular expression.
FilesSetRulePanel.messages.invalidCharInPath=The path cannot contain \\, :, *, ?, \", <, or > unless it is a regular expression.
FilesSetRulePanel.messages.invalidPathRegex=The path regular expression is not valid:\n\n{0}
FilesSetRulePanel.dirsRadioButton.text=Directories
FilesSetRulePanel.filesRadioButton.text=Files
InterestingItemDefsPanel.typePanel.border.title=Search for:
InterestingItemDefsPanel.bothRadioButton.text=Files and Directories
InterestingItemDefsPanel.dirsRadioButton.text=Directories
InterestingItemDefsPanel.filesRadioButton.text=Files
InterestingItemDefsPanel.fileNamePanel.border.title=Name
InterestingItemDefsPanel.fileNameRegexCheckbox.text=Regex
InterestingItemDefsPanel.fileNameExtensionRadioButton.text=Extension Only
InterestingItemDefsPanel.fileNameTextField.text=
InterestingItemDefsPanel.fileNameRadioButton.text=File Name
FilesSetRulePanel.pathSeparatorInfoLabel.text=Use / as path separator
FilesSetRulePanel.filesAndDirsRadioButton.text=Files and Directories
InterestingItemDefsPanel.rulePathFilterTextField.text=
InterestingItemDefsPanel.rulePathPanel.border.title=Path
InterestingItemDefsPanel.rulePathFilterRegexCheckBox.text=Regex
InterestingItemDefsPanel.ignoreKnownFilesCheckbox.text=Ignore Known Files

View File

@ -0,0 +1,63 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 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.modules.interestingitems;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
/**
* Ingest job settings for interesting files identifier ingest modules.
*/
final class FilesIdentifierIngestJobSettings implements IngestModuleIngestJobSettings {
private static final long serialVersionUID = 1L;
private final Set<String> enabledFilesSetNames = new HashSet<>();
/**
* Construct the ingest job settings for an interesting files identifier
* ingest module.
*
* @param enabledFilesSetNames The names of the interesting files sets
* that are enabled for the ingest job.
*/
FilesIdentifierIngestJobSettings(List<String> enabledFilesSetNames) {
this.enabledFilesSetNames.addAll(enabledFilesSetNames);
}
/**
* @inheritDoc
*/
@Override
public long getVersionNumber() {
return FilesIdentifierIngestJobSettings.serialVersionUID;
}
/**
* Determines whether or not an interesting files set definition is enabled
* for an ingest job.
*
* @param filesSetName The name of the files set definition to check.
* @return True if the file set is enabled, false otherwise.
*/
boolean isInterestingFilesSetEnabled(String filesSetName) {
return (this.enabledFilesSetNames.contains(filesSetName));
}
}

View File

@ -0,0 +1,65 @@
<?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"/>
<Component id="filesSetScrollPane" pref="254" 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="1" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="filesSetScrollPane" pref="188" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="filesSetScrollPane">
<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="filesSetTable">
<Properties>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="f0" green="f0" red="f0" type="rgb"/>
</Property>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.editors2.TableModelEditor">
<Table columnCount="0" rowCount="0"/>
</Property>
<Property name="columnModel" type="javax.swing.table.TableColumnModel" editor="org.netbeans.modules.form.editors2.TableColumnModelEditor">
<TableColumnModel selectionModel="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="true" resizingAllowed="true"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,303 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 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.modules.interestingitems;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.TreeMap;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel;
/**
* Ingest job settings panel for interesting files identifier ingest modules.
*/
final class FilesIdentifierIngestJobSettingsPanel extends IngestModuleIngestJobSettingsPanel implements Observer {
private final FilesSetsTableModel tableModel;
// This map of interesting interesting files set names to files sets is used
// both to sort interesting files sets by name and to detect when a new
// files set is defined, so that the new set can be enabled by default.
private TreeMap<String, FilesSet> filesSetSnapshot;
/**
* A factory method that avoids publishing the "this" reference from the
* constructor.
*
* @return An instance of the ingest job settings panel interesting files
* identifier ingest modules.
*/
static FilesIdentifierIngestJobSettingsPanel makePanel(FilesIdentifierIngestJobSettings settings) {
FilesIdentifierIngestJobSettingsPanel panel = new FilesIdentifierIngestJobSettingsPanel(settings);
// Observe the interesting item definitions manager for changes to the
// interesting file set definitions. This is used to keep this panel in
// synch with changes made using the global settings/option panel for
// this module.
InterestingItemDefsManager.getInstance().addObserver(panel);
return panel;
}
/**
* Constructs an ingest job settings panel for interesting files identifier
* ingest modules.
*/
private FilesIdentifierIngestJobSettingsPanel(FilesIdentifierIngestJobSettings settings) {
initComponents();
/* Make a table row object for each interesting files set, bundling the
* set with an enabled flag. The files sets are loaded into a tree map
* so they are sorted by name. The keys set also serves as a cache of
* set names so that new sets can be easily detected in the override of
* Observer.update().
*/
List<FilesSetRow> filesSetRows = new ArrayList<>();
this.filesSetSnapshot = new TreeMap<>(InterestingItemDefsManager.getInstance().getInterestingFilesSets());
for (FilesSet set : this.filesSetSnapshot.values()) {
filesSetRows.add(new FilesSetRow(set, settings.isInterestingFilesSetEnabled(set.getName())));
}
// Make a table model to manage the row objects.
this.tableModel = new FilesSetsTableModel(filesSetRows);
// Set up the table component that presents the table model that allows
// users to enable and disable interesting files set definitions for an
// ingest job.
this.filesSetTable.setModel(tableModel);
this.filesSetTable.setTableHeader(null);
this.filesSetTable.setRowSelectionAllowed(false);
final int width = this.filesSetScrollPane.getPreferredSize().width;
this.filesSetTable.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN);
TableColumn column;
for (int i = 0; i < this.filesSetTable.getColumnCount(); i++) {
column = this.filesSetTable.getColumnModel().getColumn(i);
if (i == 0) {
column.setPreferredWidth(((int) (width * 0.07)));
} else {
column.setPreferredWidth(((int) (width * 0.92)));
}
}
}
/**
* @inheritDoc
*/
@Override
public IngestModuleIngestJobSettings getSettings() {
List<String> enabledInterestingFilesSets = new ArrayList<>();
this.tableModel.filesSetRows.stream().filter((rowModel) -> (rowModel.isEnabled())).forEach((rowModel) -> {
enabledInterestingFilesSets.add(rowModel.getFilesSet().getName());
});
return new FilesIdentifierIngestJobSettings(enabledInterestingFilesSets);
}
/**
* @inheritDoc
*/
@Override
public void update(Observable o, Object arg
) {
// Get the user's current enabled/disabled settings.
FilesIdentifierIngestJobSettings settings = (FilesIdentifierIngestJobSettings) this.getSettings();
// Refresh the view of the interesting files set definitions.
List<FilesSetRow> rowModels = new ArrayList<>();
TreeMap<String, FilesSet> newFilesSetSnapshot = new TreeMap<>(InterestingItemDefsManager.getInstance().getInterestingFilesSets());
for (FilesSet set : newFilesSetSnapshot.values()) {
if (this.filesSetSnapshot.keySet().contains(set.getName())) {
// Preserve the current enabled/diabled state of the set.
rowModels.add(new FilesSetRow(set, settings.isInterestingFilesSetEnabled(set.getName())));
} else {
// New sets are enabled by default.
rowModels.add(new FilesSetRow(set, true));
}
}
this.tableModel.resetTableData(rowModels);
// Cache the snapshot so it will be avaialble for the next update.
this.filesSetSnapshot = newFilesSetSnapshot;
}
/**
* Table model for a JTable component that allows users to enable and
* disable interesting files set definitions for an ingest job.
*/
private final static class FilesSetsTableModel extends AbstractTableModel {
private List<FilesSetRow> filesSetRows;
/**
* Constructs a table model for a JTable component that allows users to
* enable and disable interesting files set definitions for an ingest
* job.
*
* @param filesSetRows A collection of row objects that bundles an
* interesting files set with an enabled flag
*/
FilesSetsTableModel(List<FilesSetRow> filesSetRows) {
this.filesSetRows = filesSetRows;
}
/**
* Refreshes the table with a new set of rows.
*
* @param filesSetRows A collection of row objects that bundles an
* interesting files set with an enabled flag
*/
void resetTableData(List<FilesSetRow> filesSetRows) {
this.filesSetRows = filesSetRows;
this.fireTableDataChanged();
}
/**
* @inheritDoc
*/
@Override
public int getRowCount() {
return this.filesSetRows.size();
}
/**
* @inheritDoc
*/
@Override
public int getColumnCount() {
return 2;
}
/**
* @inheritDoc
*/
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
if (columnIndex == 0) {
return this.filesSetRows.get(rowIndex).isEnabled();
} else {
return this.filesSetRows.get(rowIndex).getFilesSet().getName();
}
}
/**
* @inheritDoc
*/
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return (columnIndex == 0);
}
/**
* @inheritDoc
*/
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (columnIndex == 0) {
this.filesSetRows.get(rowIndex).setEnabled((Boolean) aValue);
}
}
/**
* @inheritDoc
*/
@Override
public Class<?> getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
}
/**
* Bundles an interesting files set with an enabled flag.
*/
private final static class FilesSetRow {
private final FilesSet set;
private boolean enabled;
FilesSetRow(FilesSet set, boolean enabled) {
this.set = set;
this.enabled = enabled;
}
FilesSet getFilesSet() {
return this.set;
}
boolean isEnabled() {
return this.enabled;
}
void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
/**
* 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() {
filesSetScrollPane = new javax.swing.JScrollPane();
filesSetTable = new javax.swing.JTable();
filesSetTable.setBackground(new java.awt.Color(240, 240, 240));
filesSetTable.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] {
},
new String [] {
}
));
filesSetTable.setShowHorizontalLines(false);
filesSetTable.setShowVerticalLines(false);
filesSetScrollPane.setViewportView(filesSetTable);
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()
.addComponent(filesSetScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 254, Short.MAX_VALUE)
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addComponent(filesSetScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 188, Short.MAX_VALUE)
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JScrollPane filesSetScrollPane;
private javax.swing.JTable filesSetTable;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,131 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 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.modules.interestingitems;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.TskCoreException;
/**
* A file ingest module that generates interesting files set hit artifacts for
* files that match interesting files set definitions.
*/
final class FilesIdentifierIngestModule implements FileIngestModule {
private static final Object sharedResourcesLock = new Object();
private static final Logger logger = Logger.getLogger(FilesIdentifierIngestModule.class.getName());
private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter();
private static final Map<Long, List<FilesSet>> interestingFileSetsByJob = new ConcurrentHashMap<>();
private final FilesIdentifierIngestJobSettings settings;
private IngestJobContext context;
/**
* Construct an interesting files identifier ingest module for an ingest
* job.
*
* @param settings An ingest job settings object for the module.
*/
FilesIdentifierIngestModule(FilesIdentifierIngestJobSettings settings) {
this.settings = settings;
}
/**
* @inheritDoc
*/
@Override
public void startUp(IngestJobContext context) throws IngestModuleException {
this.context = context;
synchronized (FilesIdentifierIngestModule.sharedResourcesLock) {
if (FilesIdentifierIngestModule.refCounter.incrementAndGet(context.getJobId()) == 1) {
// Starting up the first instance of this module for this ingest
// job, so get the interesting file sets definitions snapshot
// for the job. Note that getting this snapshot atomically via a
// synchronized definitions manager method eliminates the need
// to disable the interesting files set definition UI during ingest.
List<FilesSet> filesSets = new ArrayList<>();
for (FilesSet set : InterestingItemDefsManager.getInstance().getInterestingFilesSets().values()) {
if (settings.isInterestingFilesSetEnabled(set.getName())) {
filesSets.add(set);
}
}
FilesIdentifierIngestModule.interestingFileSetsByJob.put(context.getJobId(), filesSets);
}
}
}
/**
* @inheritDoc
*/
@Override
public ProcessResult process(AbstractFile file) {
// See if the file belongs to any defined interesting files set.
List<FilesSet> filesSets = FilesIdentifierIngestModule.interestingFileSetsByJob.get(this.context.getJobId());
for (FilesSet filesSet : filesSets) {
String ruleSatisfied = filesSet.fileIsMemberOf(file);
if (ruleSatisfied != null) {
try {
// Post an interesting files set hit artifact to the
// blackboard.
String moduleName = InterestingItemsIngestModuleFactory.getModuleName();
BlackboardArtifact artifact = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
// Add a set name attribute to the artifact. This adds a
// fair amount of redundant data to the attributes table
// (i.e., rows that differ only in artifact id), but doing
// otherwise would requires reworking the interesting files
// set hit artifact.
BlackboardAttribute setNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(), moduleName, filesSet.getName());
artifact.addAttribute(setNameAttribute);
// Add a category attribute to the artifact to record the
// interesting files set membership rule that was satisfied.
BlackboardAttribute ruleNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY.getTypeID(), moduleName, ruleSatisfied);
artifact.addAttribute(ruleNameAttribute);
} catch (TskCoreException ex) {
FilesIdentifierIngestModule.logger.log(Level.SEVERE, "Error posting to the blackboard", ex);
}
}
}
return ProcessResult.OK;
}
/**
* @inheritDoc
*/
@Override
public void shutDown() {
if (refCounter.decrementAndGet(this.context.getJobId()) == 0) {
// Shutting down the last instance of this module for this ingest
// job, so discard the interesting file sets definitions snapshot
// for the job.
FilesIdentifierIngestModule.interestingFileSetsByJob.remove(this.context.getJobId());
}
}
}

View File

@ -0,0 +1,635 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 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.modules.interestingitems;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.TskData;
/**
* A collection of set membership rules that define an interesting files set.
* The rules are independent, i.e., if any rule is satisfied by a file, the file
* belongs to the set.
*
* Interesting files set definition objects are immutable, so they may be safely
* published to multiple threads.
*/
final class FilesSet {
private final String name;
private final String description;
private final boolean ignoreKnownFiles;
private final Map<String, Rule> rules = new HashMap<>();
/**
* Constructs an interesting files set.
*
* @param name The name of the set.
* @param description A description of the set, may be null.
* @param ignoreKnownFiles Whether or not to exclude known files from the
* set.
* @param rules The rules that define the set. May be null, but a set with
* no rules is the empty set.
*/
FilesSet(String name, String description, boolean ignoreKnownFiles, Map<String, Rule> rules) {
if ((name == null) || (name.isEmpty())) {
throw new IllegalArgumentException("Interesting files set name cannot be null or empty");
}
this.name = name;
this.description = (description != null ? description : "");
this.ignoreKnownFiles = ignoreKnownFiles;
if (rules != null) {
this.rules.putAll(rules);
}
}
/**
* Gets the name of this interesting files set.
*
* @return A name string.
*/
String getName() {
return this.name;
}
/**
* Gets the description of this interesting files set.
*
* @return A description string, possibly the empty string.
*/
String getDescription() {
return this.description;
}
/**
* Returns whether or not this interesting files set ignores known files,
* i.e., files marked as known by a look up in a known files hash set such
* as the National Software Reference Library (NSRL). Note that the
* interesting files set does not do hash set look ups; it simply queries
* the known status of the files when testing them for set membership.
*
* @return True if known files are ignored, false otherwise.
*/
boolean ignoresKnownFiles() {
return this.ignoreKnownFiles;
}
/**
* Gets a copy of the set membership rules of this interesting files set.
*
* @return A map of set membership rule names to rules, possibly empty.
*/
Map<String, Rule> getRules() {
return new HashMap<>(this.rules);
}
/**
* Determines whether a file is a member of this interesting files set.
*
* @param file A file to test for set membership.
* @return The name of the first set membership rule satisfied by the file,
* will be null if the file does not belong to the set.
*/
String fileIsMemberOf(AbstractFile file) {
if ((this.ignoreKnownFiles) && (file.getKnown() == TskData.FileKnown.KNOWN)) {
return null;
}
for (Rule rule : rules.values()) {
if (rule.isSatisfied(file)) {
return rule.getName();
}
}
return null;
}
@Override
public String toString() {
// This override is designed to provide a display name for use with
// javax.swing.DefaultListModel<E>.
return this.name;
}
/**
* A set membership rule for an interesting files set. The immutability of a
* rule object allows it to be safely published to multiple threads.
*/
static class Rule {
private final String ruleName;
private final FileNameFilter fileNameFilter;
private final MetaTypeFilter metaTypeFilter;
private final ParentPathFilter pathFilter;
private final List<FileAttributeFilter> filters = new ArrayList<>();
/**
* Construct an interesting files set membership rule.
*
* @param ruleName The name of the rule.
* @param fileNameFilter A file name filter.
* @param metaTypeFilter A file meta-type filter.
* @param pathFilter A file path filter, may be null.
*/
Rule(String ruleName, FileNameFilter fileNameFilter, MetaTypeFilter metaTypeFilter, ParentPathFilter pathFilter) {
if ((ruleName == null) || (ruleName.isEmpty())) {
throw new IllegalArgumentException("Interesting files set rule name cannot be null or empty");
}
if (fileNameFilter == null) {
throw new IllegalArgumentException("Interesting files set rule file name filter cannot be null");
}
if (metaTypeFilter == null) {
throw new IllegalArgumentException("Interesting files set rule meta-type filter cannot be null");
}
this.ruleName = ruleName;
this.fileNameFilter = fileNameFilter;
this.filters.add(fileNameFilter);
this.metaTypeFilter = metaTypeFilter;
this.filters.add(this.metaTypeFilter);
this.pathFilter = pathFilter;
if (this.pathFilter != null) {
this.filters.add(this.pathFilter);
}
}
/**
* Get the name of the rule.
*
* @return A name string.
*/
String getName() {
return ruleName;
}
/**
* Get the file name filter for the rule.
*
* @return A file name filter.
*/
FileNameFilter getFileNameFilter() {
return this.fileNameFilter;
}
/**
* Get the meta-type filter for the rule.
*
* @return A meta-type filter.
*/
MetaTypeFilter getMetaTypeFilter() {
return this.metaTypeFilter;
}
/**
* Get the path filter for the rule.
*
* @return A path filter, may be null.
*/
ParentPathFilter getPathFilter() {
return this.pathFilter;
}
/**
* Determines whether or not a file satisfies the rule.
*
* @param file The file to test.
* @return True if the rule is satisfied, false otherwise.
*/
boolean isSatisfied(AbstractFile file) {
for (FileAttributeFilter filter : filters) {
if (!filter.passes(file)) {
return false;
}
}
return true;
}
/**
* @inheritDoc
*/
@Override
public String toString() {
// This override is designed to provide a display name for use with
// javax.swing.DefaultListModel<E>.
return this.ruleName;
}
/**
* An interface for the file attribute filters of which interesting
* files set membership rules are composed.
*/
static interface FileAttributeFilter {
/**
* Tests whether or not a file satisfies the conditions of a filter.
*
* @param file The file to test.
* @return True if the file passes the test, false otherwise.
*/
boolean passes(AbstractFile file);
}
/**
* A file meta-type filter for an interesting files set membership rule.
* The immutability of a meta-type filter object allows it to be safely
* published to multiple threads.
*/
static final class MetaTypeFilter implements FileAttributeFilter {
enum Type {
FILES,
DIRECTORIES,
FILES_AND_DIRECTORIES
}
private final Type type;
/**
* Construct a meta-type filter.
*
* @param metaType The meta-type to match, must.
*/
MetaTypeFilter(Type type) {
this.type = type;
}
/**
* @inheritDoc
*/
@Override
public boolean passes(AbstractFile file) {
switch (this.type) {
case FILES:
return file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG;
case DIRECTORIES:
return file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR;
default:
return file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG
|| file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR;
}
}
/**
* Gets the meta-type the filter matches.
*
* @return A member of the MetaTypeFilter.Type enumeration.
*/
Type getMetaType() {
return this.type;
}
}
/**
* An interface for file attribute filters that do textual matching.
*/
static interface TextFilter extends FileAttributeFilter {
/**
* Gets the text the filter matches.
*
* @return The text.
*/
String getTextToMatch();
/**
* Queries whether or not the text the filter matches is a regular
* expression.
*
* @return True if the text to be matched is a regular expression,
* false otherwise.
*/
boolean isRegex();
/**
* Determines whether a string of text matches the filter.
*
* @param textToMatch The text string.
* @return True if the text matches, false otherwise.
*/
boolean textMatches(String textToMatch);
}
/**
* An abstract base class for file attribute filters that do textual
* matching.
*/
private static abstract class AbstractTextFilter implements TextFilter {
private final TextMatcher textMatcher;
/**
* Construct a case-insensitive text filter.
*
* @param text The text to be matched.
*/
AbstractTextFilter(String text) {
this.textMatcher = new FilesSet.Rule.CaseInsensitiveStringComparisionMatcher(text);
}
/**
* Construct a regular expression text filter.
*
* @param regex The regular expression to be matched.
*/
AbstractTextFilter(Pattern regex) {
this.textMatcher = new FilesSet.Rule.RegexMatcher(regex);
}
/**
* Get the text the filter matches.
*
* @return The text.
*/
@Override
public String getTextToMatch() {
return this.textMatcher.getTextToMatch();
}
/**
* Queries whether or not the text the filter matches is a regular
* expression.
*
* @return True if the text to be matched is a regular expression,
* false otherwise.
*/
@Override
public boolean isRegex() {
return this.textMatcher.isRegex();
}
/**
* Determines whether a string of text matches the filter.
*
* @param textToMatch The text string.
* @return True if the text matches, false otherwise.
*/
@Override
public boolean textMatches(String textToMatch) {
return this.textMatcher.textMatches(textToMatch);
}
/**
* @inheritDoc
*/
@Override
public abstract boolean passes(AbstractFile file);
}
/**
* A file path filter for an interesting files set membership rule. The
* immutability of a path filter object allows it to be safely published
* to multiple threads.
*/
static final class ParentPathFilter extends AbstractTextFilter {
/**
* Construct a case-insensitive file path filter.
*
* @param path The path to be matched.
*/
ParentPathFilter(String path) {
super(path);
}
/**
* Construct a file path regular expression filter.
*
* @param path The path regular expression to be matched.
*/
ParentPathFilter(Pattern path) {
super(path);
}
/**
* @inheritDoc
*/
@Override
public boolean passes(AbstractFile file) {
return this.textMatches(file.getParentPath());
}
}
/**
* A "tagging" interface to group name and extension filters separately
* from path filters for type safety when constructing rules.
*/
static interface FileNameFilter extends TextFilter {
}
/**
* A file name filter for an interesting files set membership rule. The
* immutability of a file name filter object allows it to be safely
* published to multiple threads.
*/
static final class FullNameFilter extends AbstractTextFilter implements FileNameFilter {
/**
* Construct a case-insensitive full file name filter.
*
* @param name The file name to be matched.
*/
FullNameFilter(String name) {
super(name);
}
/**
* Construct a full file name regular expression filter.
*
* @param name The file name regular expression to be matched.
*/
FullNameFilter(Pattern name) {
super(name);
}
/**
* @inheritDoc
*/
@Override
public boolean passes(AbstractFile file) {
return this.textMatches(file.getName());
}
}
/**
* A file name extension filter for an interesting files set membership
* rule. The immutability of a file name extension filter object allows
* it to be safely published to multiple threads.
*/
static final class ExtensionFilter extends AbstractTextFilter implements FileNameFilter {
/**
* Construct a case-insensitive file name extension filter.
*
* @param extension The file name extension to be matched.
*/
ExtensionFilter(String extension) {
// If there is a leading ".", strip it since
// AbstractFile.getFileNameExtension() returns just the
// extension chars and not the dot.
super(extension.startsWith(".") ? extension.substring(1) : extension);
}
/**
* Construct a file name extension regular expression filter.
*
* @param extension The file name extension regular expression to be
* matched.
*/
ExtensionFilter(Pattern extension) {
super(extension.pattern());
}
/**
* @inheritDoc
*/
@Override
public boolean passes(AbstractFile file) {
return this.textMatches(file.getNameExtension());
}
}
/**
* An interface for objects that do textual matches, used to compose a
* text filter.
*/
private static interface TextMatcher {
/**
* Get the text the matcher examines.
*
* @return The text.
*/
String getTextToMatch();
/**
* Queries whether or not the text the matcher examines is a regular
* expression.
*
* @return True if the text to be matched is a regular expression,
* false otherwise.
*/
boolean isRegex();
/**
* Determines whether a string of text is matched.
*
* @param textToMatch The text string.
* @return True if the text matches, false otherwise.
*/
boolean textMatches(String subject);
}
/**
* A text matcher that does a case-insensitive string comparison.
*/
private static class CaseInsensitiveStringComparisionMatcher implements TextMatcher {
private final String textToMatch;
/**
* Construct a text matcher that does a case-insensitive string
* comparison.
*
* @param textToMatch The text to match.
*/
CaseInsensitiveStringComparisionMatcher(String textToMatch) {
this.textToMatch = textToMatch;
}
/**
* @inheritDoc
*/
@Override
public String getTextToMatch() {
return this.textToMatch;
}
/**
* @inheritDoc
*/
@Override
public boolean isRegex() {
return false;
}
/**
* @inheritDoc
*/
@Override
public boolean textMatches(String subject) {
return subject.equalsIgnoreCase(textToMatch);
}
}
/**
* A text matcher that does regular expression matching.
*/
private static class RegexMatcher implements TextMatcher {
private final Pattern regex;
/**
* Construct a text matcher that does a regular expression
* comparison.
*
* @param regex The regular expression to match.
*/
RegexMatcher(Pattern regex) {
this.regex = regex;
}
/**
* @inheritDoc
*/
@Override
public String getTextToMatch() {
return this.regex.pattern();
}
/**
* @inheritDoc
*/
@Override
public boolean isRegex() {
return true;
}
/**
* @inheritDoc
*/
@Override
public boolean textMatches(String subject) {
// A single match is sufficient.
return this.regex.matcher(subject).find();
}
}
}
}

View File

@ -0,0 +1,118 @@
<?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">
<Group type="102" alignment="1" attributes="0">
<Component id="nameLabel" min="-2" pref="71" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="nameTextField" min="-2" pref="299" max="-2" attributes="0"/>
</Group>
<Component id="descPanel" max="32767" attributes="0"/>
<Component id="ignoreKnownFilesCheckbox" alignment="0" max="32767" attributes="0"/>
</Group>
<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 max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="nameLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="nameTextField" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="descPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="ignoreKnownFilesCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="nameLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="FilesSetPanel.nameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="nameTextField">
</Component>
<Container class="javax.swing.JPanel" name="descPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Description">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="FilesSetPanel.descPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="descScrollPanel" 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="1" attributes="0">
<EmptySpace max="32767" attributes="0"/>
<Component id="descScrollPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="descScrollPanel">
<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.JTextArea" name="descTextArea">
<Properties>
<Property name="columns" type="int" value="20"/>
<Property name="rows" type="int" value="5"/>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Component class="javax.swing.JCheckBox" name="ignoreKnownFilesCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="FilesSetPanel.ignoreKnownFilesCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,179 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 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.modules.interestingitems;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.util.NbBundle;
/**
* A panel that allows a user to create and edit interesting files set
* definitions.
*/
public class FilesSetPanel extends javax.swing.JPanel {
/**
* Construct a files set panel in create mode.
*/
FilesSetPanel() {
initComponents();
}
/**
* Construct a files set panel in edit mode.
*
* @param filesSet The files set to be edited.
*/
FilesSetPanel(FilesSet filesSet) {
initComponents();
this.nameTextField.setText(filesSet.getName());
this.descTextArea.setText(filesSet.getDescription());
this.ignoreKnownFilesCheckbox.setSelected(filesSet.ignoresKnownFiles());
}
/**
* Returns whether or not the data entered in the panel constitutes a valid
* interesting files set definition, displaying a dialog explaining the
* deficiency if the definition is invalid
*
* @return True if the definition is valid, false otherwise.
*/
boolean isValidDefinition() {
if (this.nameTextField.getText().isEmpty()) {
NotifyDescriptor notifyDesc = new NotifyDescriptor.Message(
NbBundle.getMessage(FilesSetPanel.class, "FilesSetPanel.messages.filesSetsMustBeNamed"),
NotifyDescriptor.WARNING_MESSAGE);
DialogDisplayer.getDefault().notify(notifyDesc);
return false;
}
return true;
}
/**
* Get the name for the interesting files set defined using this panel.
*
* @return A name string.
*/
String getFilesSetName() {
return this.nameTextField.getText();
}
/**
* Get the description for the interesting files set defined using this
* panel.
*
* @return A description string.
*/
String getFilesSetDescription() {
return this.descTextArea.getText();
}
/**
* Get whether or not the interesting files set defined using this panel
* ignores known files.
*
* @return True if the set ignores known files, false otherwise.
*/
boolean getFileSetIgnoresKnownFiles() {
return this.ignoreKnownFilesCheckbox.isSelected();
}
/**
* 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() {
nameLabel = new javax.swing.JLabel();
nameTextField = new javax.swing.JTextField();
descPanel = new javax.swing.JPanel();
descScrollPanel = new javax.swing.JScrollPane();
descTextArea = new javax.swing.JTextArea();
ignoreKnownFilesCheckbox = new javax.swing.JCheckBox();
org.openide.awt.Mnemonics.setLocalizedText(nameLabel, org.openide.util.NbBundle.getMessage(FilesSetPanel.class, "FilesSetPanel.nameLabel.text")); // NOI18N
descPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(FilesSetPanel.class, "FilesSetPanel.descPanel.border.title"))); // NOI18N
descTextArea.setColumns(20);
descTextArea.setRows(5);
descScrollPanel.setViewportView(descTextArea);
javax.swing.GroupLayout descPanelLayout = new javax.swing.GroupLayout(descPanel);
descPanel.setLayout(descPanelLayout);
descPanelLayout.setHorizontalGroup(
descPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(descPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(descScrollPanel)
.addContainerGap())
);
descPanelLayout.setVerticalGroup(
descPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, descPanelLayout.createSequentialGroup()
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(descScrollPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
org.openide.awt.Mnemonics.setLocalizedText(ignoreKnownFilesCheckbox, org.openide.util.NbBundle.getMessage(FilesSetPanel.class, "FilesSetPanel.ignoreKnownFilesCheckbox.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)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(nameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(nameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 299, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(descPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(ignoreKnownFilesCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(nameLabel)
.addComponent(nameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(descPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(ignoreKnownFilesCheckbox)
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JPanel descPanel;
private javax.swing.JScrollPane descScrollPanel;
private javax.swing.JTextArea descTextArea;
private javax.swing.JCheckBox ignoreKnownFilesCheckbox;
private javax.swing.JLabel nameLabel;
private javax.swing.JTextField nameTextField;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,316 @@
<?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="nameButtonGroup">
</Component>
<Component class="javax.swing.ButtonGroup" name="typeButtonGroup">
</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" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="typePanel" alignment="0" max="32767" attributes="0"/>
<Component id="namePanel" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="ruleNameLabel" min="-2" pref="59" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="ruleNameTextField" min="-2" pref="256" max="-2" attributes="0"/>
</Group>
<Component id="pathPanel" alignment="0" max="32767" attributes="0"/>
</Group>
<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 max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="ruleNameTextField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="ruleNameLabel" alignment="3" max="32767" attributes="0"/>
</Group>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="typePanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="namePanel" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="pathPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<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/modules/interestingitems/Bundle.properties" key="FilesSetRulePanel.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/modules/interestingitems/Bundle.properties" key="FilesSetRulePanel.ruleNameTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JPanel" name="namePanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Named:">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="FilesSetRulePanel.namePanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
</Properties>
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleName" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="FilesSetRulePanel.namePanel.AccessibleContext.accessibleName" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</AccessibilityProperties>
<Layout>
<DimensionLayout dim="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">
<Group type="102" alignment="0" attributes="0">
<Component id="fullNameRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Component id="extensionRadioButton" min="-2" pref="114" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="nameRegexCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Component id="nameTextField" alignment="0" max="32767" attributes="0"/>
</Group>
<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 max="-2" attributes="0"/>
<Component id="nameTextField" min="-2" pref="20" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="fullNameRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="extensionRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="nameRegexCheckbox" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JCheckBox" name="nameRegexCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="FilesSetRulePanel.nameRegexCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JRadioButton" name="extensionRadioButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="nameButtonGroup"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="FilesSetRulePanel.extensionRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="nameTextField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="FilesSetRulePanel.nameTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JRadioButton" name="fullNameRadioButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="nameButtonGroup"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="FilesSetRulePanel.fullNameRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="typePanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Search for:">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="FilesSetRulePanel.typePanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="filesRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="dirsRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="filesAndDirsRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="filesRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="dirsRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="filesAndDirsRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JRadioButton" name="filesRadioButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="typeButtonGroup"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="FilesSetRulePanel.filesRadioButton.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="filesRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="dirsRadioButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="typeButtonGroup"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="FilesSetRulePanel.dirsRadioButton.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="dirsRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="filesAndDirsRadioButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="typeButtonGroup"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="FilesSetRulePanel.filesAndDirsRadioButton.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="filesAndDirsRadioButtonActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="pathPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="With parent path:">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="FilesSetRulePanel.pathPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
</Properties>
<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" max="-2" attributes="0">
<Group type="102" attributes="0">
<Component id="pathRegexCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="pathSeparatorInfoLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="pathTextField" min="-2" pref="283" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="pathTextField" min="-2" pref="20" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="pathRegexCheckBox" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="pathSeparatorInfoLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JCheckBox" name="pathRegexCheckBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="FilesSetRulePanel.pathRegexCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="pathTextField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="FilesSetRulePanel.pathTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="pathSeparatorInfoLabel">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/info-icon-16.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="FilesSetRulePanel.pathSeparatorInfoLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,558 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 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.modules.interestingitems;
import java.util.List;
import java.util.logging.Level;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* A panel that allows a user to create and edit interesting files set
* membership rules.
*/
final class FilesSetRulePanel extends javax.swing.JPanel {
private static final Logger logger = Logger.getLogger(FilesSetRulePanel.class.getName());
private static final String SLEUTHKIT_PATH_SEPARATOR = "/"; // NON-NLS
private static final List<String> ILLEGAL_FILE_NAME_CHARS = InterestingItemDefsManager.getIllegalFileNameChars();
private static final List<String> ILLEGAL_FILE_PATH_CHARS = InterestingItemDefsManager.getIllegalFilePathChars();
/**
* Constructs a files set rule panel in create rule mode.
*/
FilesSetRulePanel() {
initComponents();
populateComponentsWithDefaultValues();
}
/**
* Constructs a files set rule panel in edit rule mode.
*
* @param rule The files set rule to be edited.
*/
FilesSetRulePanel(FilesSet.Rule rule) {
initComponents();
populateRuleNameComponent(rule);
populateTypeFilterComponents(rule);
populateNameFilterComponents(rule);
populatePathFilterComponents(rule);
}
/**
* Populates the UI components with default values.
*/
private void populateComponentsWithDefaultValues() {
this.filesRadioButton.setSelected(true);
this.fullNameRadioButton.setSelected(true);
}
/**
* Populates the UI component that displays the rule name.
*
* @param rule The files set rule to be edited.
*/
private void populateRuleNameComponent(FilesSet.Rule rule) {
this.ruleNameTextField.setText(rule.getName());
}
/**
* Populates the UI components that display the meta-type filter for a rule.
*
* @param rule The files set rule to be edited.
*/
private void populateTypeFilterComponents(FilesSet.Rule rule) {
FilesSet.Rule.MetaTypeFilter typeFilter = rule.getMetaTypeFilter();
switch (typeFilter.getMetaType()) {
case FILES:
this.filesRadioButton.setSelected(true);
break;
case DIRECTORIES:
this.dirsRadioButton.setSelected(true);
break;
case FILES_AND_DIRECTORIES:
this.filesAndDirsRadioButton.setSelected(true);
break;
}
}
/**
* Populates the UI components that display the name filter for a rule.
*
* @param rule The files set rule to be edited.
*/
private void populateNameFilterComponents(FilesSet.Rule rule) {
FilesSet.Rule.FileNameFilter nameFilter = rule.getFileNameFilter();
this.nameTextField.setText(nameFilter.getTextToMatch());
this.nameRegexCheckbox.setSelected(nameFilter.isRegex());
if (nameFilter instanceof FilesSet.Rule.FullNameFilter) {
this.fullNameRadioButton.setSelected(true);
} else {
this.extensionRadioButton.setSelected(true);
}
}
/**
* Populates the UI components that display the optional path filter for a
* rule.
*
* @param rule The files set rule to be edited.
*/
private void populatePathFilterComponents(FilesSet.Rule rule) {
FilesSet.Rule.ParentPathFilter pathFilter = rule.getPathFilter();
if (pathFilter != null) {
this.pathTextField.setText(pathFilter.getTextToMatch());
this.pathRegexCheckBox.setSelected(pathFilter.isRegex());
}
}
/**
* Returns whether or not the data entered in the panel constitutes a valid
* interesting files set membership rule definition, displaying a dialog
* explaining the deficiency if the definition is invalid.
*
* @return True if the definition is valid, false otherwise.
*/
boolean isValidRuleDefinition() {
// The rule must have a name.
if (this.ruleNameTextField.getText().isEmpty()) {
NotifyDescriptor notifyDesc = new NotifyDescriptor.Message(
NbBundle.getMessage(FilesSetPanel.class, "FilesSetRulePanel.messages.filesSetRulesMustBeNamed"),
NotifyDescriptor.WARNING_MESSAGE);
DialogDisplayer.getDefault().notify(notifyDesc);
return false;
}
// The rule must have name filter text.
if (this.nameTextField.getText().isEmpty()) {
NotifyDescriptor notifyDesc = new NotifyDescriptor.Message(
NbBundle.getMessage(FilesSetPanel.class, "FilesSetRulePanel.messages.emptyNameFilter"),
NotifyDescriptor.WARNING_MESSAGE);
DialogDisplayer.getDefault().notify(notifyDesc);
return false;
}
// The name filter must either be a regular expression that compiles or
// a string without illegal file name chars.
if (this.nameRegexCheckbox.isSelected()) {
try {
Pattern.compile(this.nameTextField.getText());
} catch (PatternSyntaxException ex) {
NotifyDescriptor notifyDesc = new NotifyDescriptor.Message(
NbBundle.getMessage(FilesSetPanel.class, "FilesSetRulePanel.messages.invalidNameRegex", ex.getLocalizedMessage()),
NotifyDescriptor.WARNING_MESSAGE);
DialogDisplayer.getDefault().notify(notifyDesc);
return false;
}
} else {
if (!FilesSetRulePanel.containsOnlyLegalChars(this.nameTextField.getText(), FilesSetRulePanel.ILLEGAL_FILE_NAME_CHARS)) {
NotifyDescriptor notifyDesc = new NotifyDescriptor.Message(
NbBundle.getMessage(FilesSetPanel.class, "FilesSetRulePanel.messages.invalidCharInName"),
NotifyDescriptor.WARNING_MESSAGE);
DialogDisplayer.getDefault().notify(notifyDesc);
return false;
}
}
// The path filter, if specified, must either be a regular expression
// that compiles or a string without illegal file path chars.
if (!this.pathTextField.getText().isEmpty()) {
if (this.pathRegexCheckBox.isSelected()) {
try {
Pattern.compile(this.pathTextField.getText());
} catch (PatternSyntaxException ex) {
NotifyDescriptor notifyDesc = new NotifyDescriptor.Message(
NbBundle.getMessage(FilesSetPanel.class, "FilesSetRulePanel.messages.invalidPathRegex", ex.getLocalizedMessage()),
NotifyDescriptor.WARNING_MESSAGE);
DialogDisplayer.getDefault().notify(notifyDesc);
return false;
}
} else {
if (!FilesSetRulePanel.containsOnlyLegalChars(this.pathTextField.getText(), FilesSetRulePanel.ILLEGAL_FILE_PATH_CHARS)) {
NotifyDescriptor notifyDesc = new NotifyDescriptor.Message(
NbBundle.getMessage(FilesSetPanel.class, "FilesSetRulePanel.messages.invalidCharInPath"),
NotifyDescriptor.WARNING_MESSAGE);
DialogDisplayer.getDefault().notify(notifyDesc);
return false;
}
}
}
return true;
}
/**
* Gets the name of the files set rule created or edited.
*
* @return A name string.
*/
String getRuleName() {
return this.ruleNameTextField.getText();
}
/**
* Gets the name filter for the rule that was created or edited. Should only
* be called if isValidDefintion() returns true.
*
* @return A name filter.
* @throws IllegalStateException if the specified name filter is not valid.
*/
FilesSet.Rule.FileNameFilter getFileNameFilter() throws IllegalStateException {
FilesSet.Rule.FileNameFilter filter = null;
if (!this.nameTextField.getText().isEmpty()) {
if (this.nameRegexCheckbox.isSelected()) {
try {
Pattern pattern = Pattern.compile(this.nameTextField.getText());
if (this.fullNameRadioButton.isSelected()) {
filter = new FilesSet.Rule.FullNameFilter(pattern);
} else {
filter = new FilesSet.Rule.ExtensionFilter(pattern);
}
} catch (PatternSyntaxException ex) {
logger.log(Level.SEVERE, "Attempt to get regex name filter that does not compile", ex); // NON-NLS
throw new IllegalStateException("The files set rule panel name filter is not in a valid state"); // NON-NLS
}
} else {
if (FilesSetRulePanel.containsOnlyLegalChars(this.nameTextField.getText(), FilesSetRulePanel.ILLEGAL_FILE_NAME_CHARS)) {
if (this.fullNameRadioButton.isSelected()) {
filter = new FilesSet.Rule.FullNameFilter(this.nameTextField.getText());
} else {
filter = new FilesSet.Rule.ExtensionFilter(this.nameTextField.getText());
}
} else {
logger.log(Level.SEVERE, "Attempt to get name filter with illegal chars"); // NON-NLS
throw new IllegalStateException("The files set rule panel name filter is not in a valid state"); // NON-NLS
}
}
}
return filter;
}
/**
* Gets the file meta-type filter for the rule that was created or edited.
*
* @return A type filter.
*/
FilesSet.Rule.MetaTypeFilter getMetaTypeFilter() {
if (this.filesRadioButton.isSelected()) {
return new FilesSet.Rule.MetaTypeFilter(FilesSet.Rule.MetaTypeFilter.Type.FILES);
} else if (this.dirsRadioButton.isSelected()) {
return new FilesSet.Rule.MetaTypeFilter(FilesSet.Rule.MetaTypeFilter.Type.DIRECTORIES);
} else {
return new FilesSet.Rule.MetaTypeFilter(FilesSet.Rule.MetaTypeFilter.Type.FILES_AND_DIRECTORIES);
}
}
/**
* Gets the optional path filter for the rule that was created or edited.
* Should only be called if isValidDefintion() returns true.
*
* @return A path filter or null if no path filter was specified.
* @throws IllegalStateException if the specified path filter is not valid.
*/
FilesSet.Rule.ParentPathFilter getPathFilter() throws IllegalStateException {
FilesSet.Rule.ParentPathFilter filter = null;
if (!this.pathTextField.getText().isEmpty()) {
if (this.pathRegexCheckBox.isSelected()) {
try {
filter = new FilesSet.Rule.ParentPathFilter(Pattern.compile(this.pathTextField.getText()));
} catch (PatternSyntaxException ex) {
logger.log(Level.SEVERE, "Attempt to get malformed path filter", ex); // NON-NLS
throw new IllegalStateException("The files set rule panel path filter is not in a valid state"); // NON-NLS
}
} else {
String path = this.pathTextField.getText();
if (FilesSetRulePanel.containsOnlyLegalChars(path, FilesSetRulePanel.ILLEGAL_FILE_PATH_CHARS)) {
// Add a leading path separator if omitted.
if (!path.startsWith(FilesSetRulePanel.SLEUTHKIT_PATH_SEPARATOR)) {
path = FilesSetRulePanel.SLEUTHKIT_PATH_SEPARATOR + path;
}
// Add a trailing path separator if omitted.
if (!path.endsWith(FilesSetRulePanel.SLEUTHKIT_PATH_SEPARATOR)) {
path += FilesSetRulePanel.SLEUTHKIT_PATH_SEPARATOR;
}
filter = new FilesSet.Rule.ParentPathFilter(path);
} else {
logger.log(Level.SEVERE, "Attempt to get path filter with illegal chars"); // NON-NLS
throw new IllegalStateException("The files set rule panel path filter is not in a valid state"); // NON-NLS
}
}
}
return filter;
}
/**
* Checks an input string for the use of illegal characters.
*
* @param toBeChecked The input string.
* @param illegalChars The characters deemed to be illegal.
* @return True if the string does not contain illegal characters, false
* otherwise.
*/
private static boolean containsOnlyLegalChars(String toBeChecked, List<String> illegalChars) {
for (String illegalChar : illegalChars) {
if (toBeChecked.contains(illegalChar)) {
return false;
}
}
return true;
}
/**
* Sets the state of the name filter UI components consistent with the state
* of the UI components in the type button group.
*/
private void setComponentsForSearchType() {
if (!this.filesRadioButton.isSelected()) {
this.fullNameRadioButton.setSelected(true);
this.extensionRadioButton.setEnabled(false);
} else {
this.extensionRadioButton.setEnabled(true);
}
}
/**
* 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() {
nameButtonGroup = new javax.swing.ButtonGroup();
typeButtonGroup = new javax.swing.ButtonGroup();
ruleNameLabel = new javax.swing.JLabel();
ruleNameTextField = new javax.swing.JTextField();
namePanel = new javax.swing.JPanel();
nameRegexCheckbox = new javax.swing.JCheckBox();
extensionRadioButton = new javax.swing.JRadioButton();
nameTextField = new javax.swing.JTextField();
fullNameRadioButton = new javax.swing.JRadioButton();
typePanel = new javax.swing.JPanel();
filesRadioButton = new javax.swing.JRadioButton();
dirsRadioButton = new javax.swing.JRadioButton();
filesAndDirsRadioButton = new javax.swing.JRadioButton();
pathPanel = new javax.swing.JPanel();
pathRegexCheckBox = new javax.swing.JCheckBox();
pathTextField = new javax.swing.JTextField();
pathSeparatorInfoLabel = new javax.swing.JLabel();
org.openide.awt.Mnemonics.setLocalizedText(ruleNameLabel, org.openide.util.NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.ruleNameLabel.text")); // NOI18N
ruleNameTextField.setText(org.openide.util.NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.ruleNameTextField.text")); // NOI18N
namePanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.namePanel.border.title"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(nameRegexCheckbox, org.openide.util.NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.nameRegexCheckbox.text")); // NOI18N
nameButtonGroup.add(extensionRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(extensionRadioButton, org.openide.util.NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.extensionRadioButton.text")); // NOI18N
nameTextField.setText(org.openide.util.NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.nameTextField.text")); // NOI18N
nameButtonGroup.add(fullNameRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(fullNameRadioButton, org.openide.util.NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.fullNameRadioButton.text")); // NOI18N
javax.swing.GroupLayout namePanelLayout = new javax.swing.GroupLayout(namePanel);
namePanel.setLayout(namePanelLayout);
namePanelLayout.setHorizontalGroup(
namePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(namePanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(namePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(namePanelLayout.createSequentialGroup()
.addComponent(fullNameRadioButton)
.addGap(10, 10, 10)
.addComponent(extensionRadioButton, javax.swing.GroupLayout.PREFERRED_SIZE, 114, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(nameRegexCheckbox)
.addGap(0, 0, Short.MAX_VALUE))
.addComponent(nameTextField))
.addContainerGap())
);
namePanelLayout.setVerticalGroup(
namePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(namePanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(nameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(namePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(fullNameRadioButton)
.addComponent(extensionRadioButton)
.addComponent(nameRegexCheckbox))
.addContainerGap())
);
typePanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.typePanel.border.title"))); // NOI18N
typeButtonGroup.add(filesRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(filesRadioButton, org.openide.util.NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.filesRadioButton.text")); // NOI18N
filesRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
filesRadioButtonActionPerformed(evt);
}
});
typeButtonGroup.add(dirsRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(dirsRadioButton, org.openide.util.NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.dirsRadioButton.text")); // NOI18N
dirsRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
dirsRadioButtonActionPerformed(evt);
}
});
typeButtonGroup.add(filesAndDirsRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(filesAndDirsRadioButton, org.openide.util.NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.filesAndDirsRadioButton.text")); // NOI18N
filesAndDirsRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
filesAndDirsRadioButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout typePanelLayout = new javax.swing.GroupLayout(typePanel);
typePanel.setLayout(typePanelLayout);
typePanelLayout.setHorizontalGroup(
typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(typePanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(filesRadioButton)
.addGap(18, 18, 18)
.addComponent(dirsRadioButton)
.addGap(18, 18, 18)
.addComponent(filesAndDirsRadioButton)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
typePanelLayout.setVerticalGroup(
typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(typePanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(filesRadioButton)
.addComponent(dirsRadioButton)
.addComponent(filesAndDirsRadioButton))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pathPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.pathPanel.border.title"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(pathRegexCheckBox, org.openide.util.NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.pathRegexCheckBox.text")); // NOI18N
pathTextField.setText(org.openide.util.NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.pathTextField.text")); // NOI18N
pathSeparatorInfoLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/info-icon-16.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(pathSeparatorInfoLabel, org.openide.util.NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.pathSeparatorInfoLabel.text")); // NOI18N
javax.swing.GroupLayout pathPanelLayout = new javax.swing.GroupLayout(pathPanel);
pathPanel.setLayout(pathPanelLayout);
pathPanelLayout.setHorizontalGroup(
pathPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pathPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(pathPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addGroup(pathPanelLayout.createSequentialGroup()
.addComponent(pathRegexCheckBox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(pathSeparatorInfoLabel))
.addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 283, javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pathPanelLayout.setVerticalGroup(
pathPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pathPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(pathPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(pathRegexCheckBox)
.addComponent(pathSeparatorInfoLabel))
.addContainerGap())
);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(typePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(namePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(ruleNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 59, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(ruleNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 256, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(pathPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(ruleNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(ruleNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGap(18, 18, 18)
.addComponent(typePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(namePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(pathPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
namePanel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.namePanel.AccessibleContext.accessibleName")); // NOI18N
}// </editor-fold>//GEN-END:initComponents
private void filesAndDirsRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_filesAndDirsRadioButtonActionPerformed
setComponentsForSearchType();
}//GEN-LAST:event_filesAndDirsRadioButtonActionPerformed
private void dirsRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dirsRadioButtonActionPerformed
setComponentsForSearchType();
}//GEN-LAST:event_dirsRadioButtonActionPerformed
private void filesRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_filesRadioButtonActionPerformed
setComponentsForSearchType();
}//GEN-LAST:event_filesRadioButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JRadioButton dirsRadioButton;
private javax.swing.JRadioButton extensionRadioButton;
private javax.swing.JRadioButton filesAndDirsRadioButton;
private javax.swing.JRadioButton filesRadioButton;
private javax.swing.JRadioButton fullNameRadioButton;
private javax.swing.ButtonGroup nameButtonGroup;
private javax.swing.JPanel namePanel;
private javax.swing.JCheckBox nameRegexCheckbox;
private javax.swing.JTextField nameTextField;
private javax.swing.JPanel pathPanel;
private javax.swing.JCheckBox pathRegexCheckBox;
private javax.swing.JLabel pathSeparatorInfoLabel;
private javax.swing.JTextField pathTextField;
private javax.swing.JLabel ruleNameLabel;
private javax.swing.JTextField ruleNameTextField;
private javax.swing.ButtonGroup typeButtonGroup;
private javax.swing.JPanel typePanel;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,577 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 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.modules.interestingitems;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.logging.Level;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.coreutils.XMLUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* Provides access to interesting item definitions persisted to disk. Clients
* receive copies of the most recent interesting item definitions via
* synchronized methods, allowing the definitions to be safely published to
* multiple threads.
*/
final class InterestingItemDefsManager extends Observable {
private static final List<String> ILLEGAL_FILE_NAME_CHARS = Collections.unmodifiableList(new ArrayList<>(Arrays.asList("\\", "/", ":", "*", "?", "\"", "<", ">")));
private static final List<String> ILLEGAL_FILE_PATH_CHARS = Collections.unmodifiableList(new ArrayList<>(Arrays.asList("\\", ":", "*", "?", "\"", "<", ">")));
private static final String INTERESTING_FILES_SET_DEFS_FILE_NAME = "InterestingFilesSetDefs.xml"; //NON-NLS
private static final String DEFAULT_FILE_SET_DEFS_PATH = PlatformUtil.getUserConfigDirectory() + File.separator + INTERESTING_FILES_SET_DEFS_FILE_NAME;
private static InterestingItemDefsManager instance;
/**
* Gets the interesting item definitions manager singleton.
*/
synchronized static InterestingItemDefsManager getInstance() {
if (instance == null) {
instance = new InterestingItemDefsManager();
}
return instance;
}
/**
* Gets the set of chars deemed to be illegal in file names (Windows).
*
* @return A list of characters.
*/
static List<String> getIllegalFileNameChars() {
return InterestingItemDefsManager.ILLEGAL_FILE_NAME_CHARS;
}
/**
* Gets the set of chars deemed to be illegal in file path (SleuthKit/Windows).
*
* @return A list of characters.
*/
static List<String> getIllegalFilePathChars() {
return InterestingItemDefsManager.ILLEGAL_FILE_PATH_CHARS;
}
/**
* Gets a copy of the current interesting files set definitions.
*
* @return A map of interesting files set names to interesting file sets,
* possibly empty.
*/
synchronized Map<String, FilesSet> getInterestingFilesSets() {
return FilesSetXML.readDefinitionsFile(DEFAULT_FILE_SET_DEFS_PATH);
}
/**
* Sets the current interesting file sets definitions, replacing any
* previous definitions.
*
* @param filesSets A mapping of interesting files set names to files sets,
* used to enforce unique files set names.
*/
synchronized void setInterestingFilesSets(Map<String, FilesSet> filesSets) {
FilesSetXML.writeDefinitionsFile(DEFAULT_FILE_SET_DEFS_PATH, filesSets);
this.setChanged();
this.notifyObservers();
}
/**
* Reads and writes interesting files set definitions to and from disk in
* XML format.
*/
private final static class FilesSetXML {
private static final Logger logger = Logger.getLogger(FilesSetXML.class.getName());
private static final String XML_ENCODING = "UTF-8"; //NON-NLS
private static final List<String> illegalFileNameChars = InterestingItemDefsManager.getIllegalFileNameChars();
// The following tags and attributes are identical to those used in the
// TSK Framework interesting files set definitions file schema.
private static final String FILE_SETS_ROOT_TAG = "INTERESTING_FILE_SETS"; //NON-NLS
private static final String FILE_SET_TAG = "INTERESTING_FILE_SET"; //NON-NLS
private static final String NAME_RULE_TAG = "NAME"; //NON-NLS
private static final String EXTENSION_RULE_TAG = "EXTENSION"; //NON-NLS
private static final String NAME_ATTR = "name"; //NON-NLS
private static final String DESC_ATTR = "description"; //NON-NLS
private static final String IGNORE_KNOWN_FILES_ATTR = "ignoreKnown"; //NON-NLS
private static final String TYPE_FILTER_ATTR = "typeFilter"; //NON-NLS
private static final String PATH_FILTER_ATTR = "pathFilter"; //NON-NLS
private static final String TYPE_FILTER_VALUE_FILES = "file"; //NON-NLS
private static final String TYPE_FILTER_VALUE_DIRS = "dir"; //NON-NLS
// The following tags and attributes are currently specific to the
// Autopsy implementation of interesting files set definitions. Autopsy
// definitions that use these will not be able to be used by TSK
// Framework. However, Autopsy can accept TSK Framework definitions:
//
// 1. Rules do not have names in the TSK Framework schema, but rules do
// have names in the Autopsy schema. Names will be synthesized as needed
// to allow Autopsy to use TSK Framework interesting files set
// definitions.
// 2. The TSK Framework has an interesting files module that supports
// simple globbing with "*" characters. Name rules and path filters with
// "*" characters will be converted to regexes to allow Autopsy to use
// TSK Framework interesting files set definitions.
// 3. Type filters are required by Autopsy, but not by TSK Frmaework.
// Missing type filters will defualt to "files" filters.
private static final String REGEX_ATTR = "regex"; //NON-NLS
private static final String PATH_REGEX_ATTR = "pathRegex"; //NON-NLS
private static final String TYPE_FILTER_VALUE_FILES_AND_DIRS = "files_and_dirs"; //NON-NLS
private static final String UNNAMED_LEGACY_RULE_PREFIX = "Unnamed Rule "; // NON-NLS
private static int unnamedLegacyRuleCounter;
/**
* Reads interesting file set definitions from an XML file.
*
* @param filePath Path of the set definitions file as a string.
* @return The set definitions in a map of set names to sets.
*/
// Note: This method takes a file path to support the possibility of
// multiple intersting files set definition files, e.g., one for
// definitions that ship with Autopsy and one for user definitions.
static Map<String, FilesSet> readDefinitionsFile(String filePath) {
Map<String, FilesSet> filesSets = new HashMap<>();
// Check if the file exists.
File defsFile = new File(filePath);
if (!defsFile.exists()) {
return filesSets;
}
// Check if the file can be read.
if (!defsFile.canRead()) {
logger.log(Level.SEVERE, "Interesting file sets definition file at {0} exists, but cannot be read", filePath); // NON-NLS
return filesSets;
}
// Parse the XML in the file.
Document doc = XMLUtil.loadDoc(FilesSetXML.class, filePath);
if (doc == null) {
logger.log(Level.SEVERE, "Failed to parse interesting file sets definition file at {0}", filePath); // NON-NLS
return filesSets;
}
// Get the root element.
Element root = doc.getDocumentElement();
if (root == null) {
logger.log(Level.SEVERE, "Failed to get root {0} element tag of interesting file sets definition file at {1}", new Object[]{FilesSetXML.FILE_SETS_ROOT_TAG, filePath}); // NON-NLS
return filesSets;
}
// Read in the files set definitions.
NodeList setElems = root.getElementsByTagName(FILE_SET_TAG);
for (int i = 0; i < setElems.getLength(); ++i) {
readFilesSet((Element) setElems.item(i), filesSets, filePath);
}
return filesSets;
}
/**
* Reads in an interesting files set.
*
* @param setElem An interesting files set XML element
* @param filesSets A collection to which the set is to be added.
* @param filePath The source file, used for error reporting.
*/
private static void readFilesSet(Element setElem, Map<String, FilesSet> filesSets, String filePath) {
// The file set must have a unique name.
String setName = setElem.getAttribute(FilesSetXML.NAME_ATTR);
if (setName.isEmpty()) {
logger.log(Level.SEVERE, "Found {0} element without required {1} attribute, ignoring malformed file set definition in interesting file sets definition file at {2}", new Object[]{FilesSetXML.FILE_SET_TAG, FilesSetXML.NAME_ATTR, filePath}); // NON-NLS
return;
}
if (filesSets.containsKey(setName)) {
logger.log(Level.SEVERE, "Found duplicate definition of set named {0} in interesting file sets definition file at {1}, discarding duplicate set", new Object[]{setName, filePath}); // NON-NLS
return;
}
// The file set may have a description. The empty string is o.k.
String description = setElem.getAttribute(FilesSetXML.DESC_ATTR);
// The file set may or may not ignore known files. The default behavior
// is to not ignore them.
String ignoreKnown = setElem.getAttribute(FilesSetXML.IGNORE_KNOWN_FILES_ATTR);
boolean ignoreKnownFiles = false;
if (!ignoreKnown.isEmpty()) {
ignoreKnownFiles = Boolean.parseBoolean(ignoreKnown);
}
// Read file name set membership rules, if any.
FilesSetXML.unnamedLegacyRuleCounter = 1;
Map<String, FilesSet.Rule> rules = new HashMap<>();
NodeList nameRuleElems = setElem.getElementsByTagName(FilesSetXML.NAME_RULE_TAG);
for (int j = 0; j < nameRuleElems.getLength(); ++j) {
Element elem = (Element) nameRuleElems.item(j);
FilesSet.Rule rule = FilesSetXML.readFileNameRule(elem);
if (rule != null) {
if (!rules.containsKey(rule.getName())) {
rules.put(rule.getName(), rule);
} else {
logger.log(Level.SEVERE, "Found duplicate rule {0} for set named {1} in interesting file sets definition file at {2}, discarding malformed set", new Object[]{rule.getName(), setName, filePath}); // NON-NLS
return;
}
} else {
logger.log(Level.SEVERE, "Found malformed rule for set named {0} in interesting file sets definition file at {1}, discarding malformed set", new Object[]{setName, filePath}); // NON-NLS
return;
}
}
// Read file extension set membership rules, if any.
NodeList extRuleElems = setElem.getElementsByTagName(FilesSetXML.EXTENSION_RULE_TAG);
for (int j = 0; j < extRuleElems.getLength(); ++j) {
Element elem = (Element) extRuleElems.item(j);
FilesSet.Rule rule = FilesSetXML.readFileExtensionRule(elem);
if (rule != null) {
if (!rules.containsKey(rule.getName())) {
rules.put(rule.getName(), rule);
} else {
logger.log(Level.SEVERE, "Found duplicate rule {0} for set named {1} in interesting file sets definition file at {2}, discarding malformed set", new Object[]{rule.getName(), setName, filePath});
return;
}
} else {
logger.log(Level.SEVERE, "Found malformed rule for set named {0} in interesting file sets definition file at {1}, discarding malformed set", new Object[]{setName, filePath});
return;
}
}
// Make the files set. Note that degenerate sets with no rules are
// allowed to facilitate the separation of set definition and rule
// definitions. A set without rules is simply the empty set.
FilesSet set = new FilesSet(setName, description, ignoreKnownFiles, rules);
filesSets.put(set.getName(), set);
}
/**
* Construct an interesting files set file name rule from the data in an
* XML element.
*
* @param filePath The path of the definitions file.
* @param setName The name of the files set.
* @param elem The file name rule XML element.
* @return A file name rule, or null if there is an error (the error is
* logged).
*/
private static FilesSet.Rule readFileNameRule(Element elem) {
String ruleName = FilesSetXML.readRuleName(elem);
// The content of the rule tag is a file name filter. It may be a
// regex, or it may be from a TSK Framework rule definition with a
// "*" globbing char, or it may be simple text.
String content = elem.getTextContent();
FilesSet.Rule.FullNameFilter nameFilter;
String regex = elem.getAttribute(FilesSetXML.REGEX_ATTR);
if ((!regex.isEmpty() && regex.equalsIgnoreCase("true")) || content.contains("*")) { // NON_NLS
Pattern pattern = compileRegex(content);
if (pattern != null) {
nameFilter = new FilesSet.Rule.FullNameFilter(pattern);
} else {
logger.log(Level.SEVERE, "Error compiling " + FilesSetXML.NAME_RULE_TAG + " regex, ignoring malformed '{0}' rule definition", ruleName); // NON-NLS
return null;
}
} else {
for (String illegalChar : illegalFileNameChars) {
if (content.contains(illegalChar)) {
logger.log(Level.SEVERE, FilesSetXML.NAME_RULE_TAG + " content has illegal chars, ignoring malformed '{0}' rule definition", new Object[]{FilesSetXML.NAME_RULE_TAG, ruleName}); // NON-NLS
return null;
}
}
nameFilter = new FilesSet.Rule.FullNameFilter(content);
}
// Read in the type filter.
FilesSet.Rule.MetaTypeFilter metaTypeFilter = FilesSetXML.readMetaTypeFilter(elem);
if (metaTypeFilter == null) {
// Malformed attribute.
return null;
}
// Read in the optional path filter. Null is o.k., but if the attribute
// is there, be sure it is not malformed.
FilesSet.Rule.ParentPathFilter pathFilter = null;
if (!elem.getAttribute(FilesSetXML.PATH_FILTER_ATTR).isEmpty()
|| !elem.getAttribute(FilesSetXML.PATH_REGEX_ATTR).isEmpty()) {
pathFilter = FilesSetXML.readPathFilter(elem);
if (pathFilter == null) {
// Malformed attribute.
return null;
}
}
return new FilesSet.Rule(ruleName, nameFilter, metaTypeFilter, pathFilter);
}
/**
* Construct an interesting files set file name extension rule from the
* data in an XML element.
*
* @param elem The file name extension rule XML element.
* @return A file name extension rule, or null if there is an error (the
* error is logged).
*/
private static FilesSet.Rule readFileExtensionRule(Element elem) {
String ruleName = FilesSetXML.readRuleName(elem);
// The content of the rule tag is a file name extension filter. It may
// be a regex, or it may be from a TSK Framework rule definition
// with a "*" globbing char.
String content = elem.getTextContent();
FilesSet.Rule.ExtensionFilter extFilter;
String regex = elem.getAttribute(FilesSetXML.REGEX_ATTR);
if ((!regex.isEmpty() && regex.equalsIgnoreCase("true")) || content.contains("*")) { // NON_NLS
Pattern pattern = compileRegex(content);
if (pattern != null) {
extFilter = new FilesSet.Rule.ExtensionFilter(pattern);
} else {
logger.log(Level.SEVERE, "Error compiling " + FilesSetXML.EXTENSION_RULE_TAG + " regex, ignoring malformed {0} rule definition", ruleName); // NON-NLS
return null;
}
} else {
for (String illegalChar : illegalFileNameChars) {
if (content.contains(illegalChar)) {
logger.log(Level.SEVERE, "{0} content has illegal chars, ignoring malformed {1} rule definition", ruleName); // NON-NLS
return null;
}
}
extFilter = new FilesSet.Rule.ExtensionFilter(content);
}
// The rule must have a meta-type filter, unless a TSK Framework
// definitions file is being read.
FilesSet.Rule.MetaTypeFilter metaTypeFilter = null;
if (!elem.getAttribute(FilesSetXML.TYPE_FILTER_ATTR).isEmpty()) {
metaTypeFilter = FilesSetXML.readMetaTypeFilter(elem);
if (metaTypeFilter == null) {
// Malformed attribute.
return null;
}
} else {
metaTypeFilter = new FilesSet.Rule.MetaTypeFilter(FilesSet.Rule.MetaTypeFilter.Type.FILES);
}
// The rule may have a path filter. Null is o.k., but if the attribute
// is there, it must not be malformed.
FilesSet.Rule.ParentPathFilter pathFilter = null;
if (!elem.getAttribute(FilesSetXML.PATH_FILTER_ATTR).isEmpty()
|| !elem.getAttribute(FilesSetXML.PATH_REGEX_ATTR).isEmpty()) {
pathFilter = FilesSetXML.readPathFilter(elem);
if (pathFilter == null) {
// Malformed attribute.
return null;
}
}
return new FilesSet.Rule(ruleName, extFilter, metaTypeFilter, pathFilter);
}
/**
* Read a rule name attribute from a rule element.
*
* @param elem A rule element.
* @return A rule name.
*/
private static String readRuleName(Element elem) {
// The rule must have a name.
String ruleName = elem.getAttribute(FilesSetXML.NAME_ATTR);
if (ruleName.isEmpty()) {
// Assume a TSK Framework definitions file is being read and
// synthesize a rule name.
ruleName = UNNAMED_LEGACY_RULE_PREFIX + Integer.toString(FilesSetXML.unnamedLegacyRuleCounter++);
}
return ruleName;
}
/**
* Attempts to compile a regular expression.
*
* @param regex The regular expression.
* @return A pattern object, or null if the compilation fails.
*/
private static Pattern compileRegex(String regex) {
try {
return Pattern.compile(regex);
} catch (PatternSyntaxException ex) {
logger.log(Level.SEVERE, "Error compiling rule regex: " + ex.getMessage(), ex); // NON-NLS
return null;
}
}
/**
* Construct a meta-type filter for an interesting files set membership
* rule from data in an XML element.
*
* @param ruleElement The XML element.
* @return The meta-type filter, or null if there is an error (logged).
*/
private static FilesSet.Rule.MetaTypeFilter readMetaTypeFilter(Element ruleElement) {
FilesSet.Rule.MetaTypeFilter filter = null;
String filterAttribute = ruleElement.getAttribute(FilesSetXML.TYPE_FILTER_ATTR);
if (!filterAttribute.isEmpty()) {
switch (filterAttribute) {
case FilesSetXML.TYPE_FILTER_VALUE_FILES:
filter = new FilesSet.Rule.MetaTypeFilter(FilesSet.Rule.MetaTypeFilter.Type.FILES);
break;
case FilesSetXML.TYPE_FILTER_VALUE_DIRS:
filter = new FilesSet.Rule.MetaTypeFilter(FilesSet.Rule.MetaTypeFilter.Type.DIRECTORIES);
break;
case FilesSetXML.TYPE_FILTER_VALUE_FILES_AND_DIRS:
filter = new FilesSet.Rule.MetaTypeFilter(FilesSet.Rule.MetaTypeFilter.Type.FILES_AND_DIRECTORIES);
break;
default:
logger.log(Level.SEVERE, "Found {0} " + FilesSetXML.TYPE_FILTER_ATTR + " attribute with unrecognized value ''{0}'', ignoring malformed rule definition", filterAttribute); // NON-NLS
break;
}
} else {
// Accept TSK Framework interesting files set definitions,
// default to files.
filter = new FilesSet.Rule.MetaTypeFilter(FilesSet.Rule.MetaTypeFilter.Type.FILES);
}
return filter;
}
/**
* Construct a path filter for an interesting files set membership rule
* from data in an XML element.
*
* @param ruleElement The XML element.
* @return The path filter, or null if there is an error (logged).
*/
private static FilesSet.Rule.ParentPathFilter readPathFilter(Element ruleElement) {
FilesSet.Rule.ParentPathFilter filter = null;
String path = ruleElement.getAttribute(FilesSetXML.PATH_FILTER_ATTR);
String pathRegex = ruleElement.getAttribute(FilesSetXML.PATH_REGEX_ATTR);
if (!pathRegex.isEmpty() && path.isEmpty()) {
try {
Pattern pattern = Pattern.compile(pathRegex);
filter = new FilesSet.Rule.ParentPathFilter(pattern);
} catch (PatternSyntaxException ex) {
logger.log(Level.SEVERE, "Error compiling " + FilesSetXML.PATH_REGEX_ATTR + " regex, ignoring malformed path filter definition", ex); // NON-NLS
}
} else if (!path.isEmpty() && pathRegex.isEmpty()) {
filter = new FilesSet.Rule.ParentPathFilter(path);
}
return filter;
}
/**
* Writes interesting files set definitions to disk as an XML file,
* logging any errors.
*
* @param filePath Path of the set definitions file as a string.
* @returns True if the definitions are written to disk, false
* otherwise.
*/
// Note: This method takes a file path to support the possibility of
// multiple intersting files set definition files, e.g., one for
// definitions that ship with Autopsy and one for user definitions.
static boolean writeDefinitionsFile(String filePath, Map<String, FilesSet> interestingFilesSets) {
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
try {
// Create the new XML document.
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element rootElement = doc.createElement(FilesSetXML.FILE_SETS_ROOT_TAG);
doc.appendChild(rootElement);
// Add the interesting files sets to the document.
for (FilesSet set : interestingFilesSets.values()) {
// Add the files set element and its attributes.
Element setElement = doc.createElement(FilesSetXML.FILE_SET_TAG);
setElement.setAttribute(FilesSetXML.NAME_ATTR, set.getName());
setElement.setAttribute(FilesSetXML.DESC_ATTR, set.getDescription());
setElement.setAttribute(FilesSetXML.IGNORE_KNOWN_FILES_ATTR, Boolean.toString(set.ignoresKnownFiles()));
// Add the child elements for the set membership rules.
for (FilesSet.Rule rule : set.getRules().values()) {
// Add a rule element with the appropriate name filter
// type tag.
FilesSet.Rule.FileNameFilter nameFilter = rule.getFileNameFilter();
Element ruleElement;
if (nameFilter instanceof FilesSet.Rule.FullNameFilter) {
ruleElement = doc.createElement(FilesSetXML.NAME_RULE_TAG);
} else {
ruleElement = doc.createElement(FilesSetXML.EXTENSION_RULE_TAG);
}
// Add the rule name attribute.
ruleElement.setAttribute(FilesSetXML.NAME_ATTR, rule.getName());
// Add the name filter regex attribute
ruleElement.setAttribute(FilesSetXML.REGEX_ATTR, Boolean.toString(nameFilter.isRegex()));
// Add the type filter attribute.
FilesSet.Rule.MetaTypeFilter typeFilter = rule.getMetaTypeFilter();
switch (typeFilter.getMetaType()) {
case FILES:
ruleElement.setAttribute(FilesSetXML.TYPE_FILTER_ATTR, FilesSetXML.TYPE_FILTER_VALUE_FILES);
break;
case DIRECTORIES:
ruleElement.setAttribute(FilesSetXML.TYPE_FILTER_ATTR, FilesSetXML.TYPE_FILTER_VALUE_DIRS);
break;
default:
ruleElement.setAttribute(FilesSetXML.TYPE_FILTER_ATTR, FilesSetXML.TYPE_FILTER_VALUE_FILES_AND_DIRS);
break;
}
// Add the optional path filter.
FilesSet.Rule.ParentPathFilter pathFilter = rule.getPathFilter();
if (pathFilter != null) {
if (pathFilter.isRegex()) {
ruleElement.setAttribute(FilesSetXML.PATH_REGEX_ATTR, pathFilter.getTextToMatch());
} else {
ruleElement.setAttribute(FilesSetXML.PATH_FILTER_ATTR, pathFilter.getTextToMatch());
}
}
// Add the name filter text as the rule element content.
ruleElement.setTextContent(nameFilter.getTextToMatch());
setElement.appendChild(ruleElement);
}
rootElement.appendChild(setElement);
}
// Overwrite the previous definitions file. Note that the utility
// method logs an error on failure.
return XMLUtil.saveDoc(FilesSetXML.class, filePath, XML_ENCODING, doc);
} catch (ParserConfigurationException ex) {
logger.log(Level.SEVERE, "Error writing interesting files definition file to " + filePath, ex); // NON-NLS
return false;
}
}
}
}

View File

@ -0,0 +1,110 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 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.modules.interestingitems;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import org.netbeans.spi.options.OptionsPanelController;
import org.openide.util.HelpCtx;
import org.openide.util.Lookup;
@OptionsPanelController.TopLevelRegistration(
categoryName = "#OptionsCategory_Name_InterestingItemDefinitions",
iconBase = "org/sleuthkit/autopsy/images/interesting_item_32x32.png",
keywords = "#OptionsCategory_Keywords_InterestingItemDefinitions",
keywordsCategory = "InterestingItemDefinitions",
position = 5
)
@org.openide.util.NbBundle.Messages({"OptionsCategory_Name_InterestingItemDefinitions=Interesting Item Definitions", "OptionsCategory_Keywords_InterestingItemDefinitions=InterestingItemDefinitions"})
public final class InterestingItemDefsOptionsPanelController extends OptionsPanelController {
private InterestingItemDefsPanel panel;
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
private boolean changed;
@Override
public void update() {
getPanel().load();
changed = false;
}
@Override
public void applyChanges() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
getPanel().store();
changed = false;
}
});
}
@Override
public void cancel() {
// need not do anything special, if no changes have been persisted yet
}
@Override
public boolean isValid() {
return true;
}
@Override
public boolean isChanged() {
return changed;
}
@Override
public HelpCtx getHelpCtx() {
return null;
}
@Override
public JComponent getComponent(Lookup masterLookup) {
return getPanel();
}
@Override
public void addPropertyChangeListener(PropertyChangeListener l) {
pcs.addPropertyChangeListener(l);
}
@Override
public void removePropertyChangeListener(PropertyChangeListener l) {
pcs.removePropertyChangeListener(l);
}
private InterestingItemDefsPanel getPanel() {
if (panel == null) {
panel = new InterestingItemDefsPanel();
}
return panel;
}
void changed() {
if (!changed) {
changed = true;
pcs.firePropertyChange(OptionsPanelController.PROP_CHANGED, false, true);
}
pcs.firePropertyChange(OptionsPanelController.PROP_VALID, null, null);
}
}

View File

@ -0,0 +1,558 @@
<?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="fileNameButtonGroup">
</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 max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="newSetButton" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="editSetButton" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="deleteSetButton" linkSize="1" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="setsListLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="setsListScrollPane" max="32767" attributes="0"/>
<Component id="ignoreKnownFilesCheckbox" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="selectedSetLabel" min="-2" pref="71" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="setNameTextField" min="-2" pref="208" max="-2" attributes="0"/>
</Group>
<Component id="setDescPanel" max="32767" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="separator" min="-2" pref="2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="selectedRuleLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="ruleNameTextField" max="32767" attributes="0"/>
</Group>
<Component id="rulesListLabel" min="-2" max="-2" attributes="0"/>
<Component id="fileNamePanel" alignment="0" max="32767" attributes="0"/>
<Component id="rulePathPanel" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Component id="newRuleButton" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="editRuleButton" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="deleteRuleButton" linkSize="1" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="rulesListScrollPane" max="32767" attributes="0"/>
<Component id="typePanel" alignment="0" max="32767" attributes="0"/>
</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="0" max="-2" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="3" attributes="0">
<Component id="setsListLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="rulesListLabel" 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="setsListScrollPane" min="-2" pref="199" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="selectedSetLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="setNameTextField" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="setDescPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="ignoreKnownFilesCheckbox" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="rulesListScrollPane" min="-2" pref="122" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="selectedRuleLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="ruleNameTextField" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="16" max="-2" attributes="0"/>
<Component id="typePanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="fileNamePanel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="rulePathPanel" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="deleteRuleButton" linkSize="2" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="editRuleButton" linkSize="2" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="newRuleButton" linkSize="2" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="deleteSetButton" linkSize="2" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="editSetButton" linkSize="2" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="newSetButton" linkSize="2" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Component id="separator" alignment="0" min="-2" pref="474" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="setsListLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.setsListLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="rulesListLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.rulesListLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JScrollPane" name="setsListScrollPane">
<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.JList" name="setsList">
<Properties>
<Property name="selectionMode" type="int" value="0"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;FilesSet&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JScrollPane" name="rulesListScrollPane">
<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.JList" name="rulesList">
<Properties>
<Property name="selectionMode" type="int" value="0"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;FilesSet.Rule&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="selectedSetLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.selectedSetLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="ignoreKnownFilesCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.ignoreKnownFilesCheckbox.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="selectedRuleLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.selectedRuleLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="newSetButton">
<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/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.newSetButton.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="newSetButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="editSetButton">
<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/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.editSetButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="editSetButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="deleteSetButton">
<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/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.deleteSetButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="deleteSetButtonActionPerformed"/>
</Events>
</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/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.newRuleButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="newRuleButtonActionPerformed"/>
</Events>
</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/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.editRuleButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="editRuleButtonActionPerformed"/>
</Events>
</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/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.deleteRuleButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="deleteRuleButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JSeparator" name="separator">
<Properties>
<Property name="orientation" type="int" value="1"/>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="setNameTextField">
<Properties>
<Property name="editable" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="ruleNameTextField">
<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/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.ruleNameTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JPanel" name="fileNamePanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Name">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.fileNamePanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="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="fileNameTextField" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="fileNameRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Component id="fileNameExtensionRadioButton" min="-2" pref="114" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="fileNameRegexCheckbox" min="-2" max="-2" 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 max="-2" attributes="0"/>
<Component id="fileNameTextField" min="-2" pref="20" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="fileNameRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="fileNameExtensionRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="fileNameRegexCheckbox" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JCheckBox" name="fileNameRegexCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.fileNameRegexCheckbox.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.JRadioButton" name="fileNameExtensionRadioButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="fileNameButtonGroup"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.fileNameExtensionRadioButton.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.JTextField" name="fileNameTextField">
<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/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.fileNameTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JRadioButton" name="fileNameRadioButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="fileNameButtonGroup"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.fileNameRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="rulePathPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Path">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.rulePathPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="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="rulePathFilterRegexCheckBox" min="-2" max="-2" attributes="0"/>
<Component id="rulePathFilterTextField" alignment="0" min="-2" pref="283" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" 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"/>
<Component id="rulePathFilterTextField" min="-2" pref="20" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="rulePathFilterRegexCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JCheckBox" name="rulePathFilterRegexCheckBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.rulePathFilterRegexCheckBox.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.JTextField" name="rulePathFilterTextField">
<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/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.rulePathFilterTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="setDescPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Description">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.setDescPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="setDescScrollPanel" min="-2" pref="296" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="32767" attributes="0"/>
<Component id="setDescScrollPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="setDescScrollPanel">
<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.JTextArea" name="setDescriptionTextArea">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="columns" type="int" value="20"/>
<Property name="rows" type="int" value="5"/>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="typePanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Search for:">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.typePanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="filesRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="dirsRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="bothRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="filesRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="dirsRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="bothRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JRadioButton" name="filesRadioButton">
<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/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.filesRadioButton.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.JRadioButton" name="dirsRadioButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.dirsRadioButton.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.JRadioButton" name="bothRadioButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties" key="InterestingItemDefsPanel.bothRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,793 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 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.modules.interestingitems;
import java.awt.EventQueue;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import javax.swing.DefaultListModel;
import javax.swing.JOptionPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
/**
* A panel that allows a user to make interesting item definitions.
*/
final class InterestingItemDefsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel {
private final DefaultListModel<FilesSet> setsListModel = new DefaultListModel<>();
private final DefaultListModel<FilesSet.Rule> rulesListModel = new DefaultListModel<>();
// The following is a map of interesting files set names to interesting
// files set definitions. It is a snapshot of the files set definitions
// obtained from the interesting item definitions manager at the time the
// the panel is loaded. When the panel saves or stores its settings, these
// definitions, possibly changed, are submitted back to the interesting item
// definitions manager. Note that it is a tree map to aid in displaying
// files sets in sorted order by name.
private TreeMap<String, FilesSet> filesSets;
/**
* Constructs an interesting item definitions panel.
*/
InterestingItemDefsPanel() {
this.initComponents();
this.setsList.setModel(setsListModel);
this.setsList.addListSelectionListener(new InterestingItemDefsPanel.SetsListSelectionListener());
this.rulesList.setModel(rulesListModel);
this.rulesList.addListSelectionListener(new InterestingItemDefsPanel.RulesListSelectionListener());
}
/**
* @inheritDoc
*/
@Override
public void saveSettings() {
InterestingItemDefsManager.getInstance().setInterestingFilesSets(this.filesSets);
}
/**
* @inheritDoc
*/
@Override
public void store() {
this.saveSettings();
}
/**
* @inheritDoc
*/
@Override
public void load() {
this.resetComponents();
// Get a working copy of the interesting files set definitions and sort
// by set name.
this.filesSets = new TreeMap<>(InterestingItemDefsManager.getInstance().getInterestingFilesSets());
// Populate the list model for the interesting files sets list
// component.
for (FilesSet set : this.filesSets.values()) {
this.setsListModel.addElement(set);
}
if (!this.filesSets.isEmpty()) {
// Select the first files set by default. The list selections
// listeners will then populate the other components.
EventQueue.invokeLater(() -> {
InterestingItemDefsPanel.this.setsList.setSelectedIndex(0);
});
}
}
/**
* Clears the list models and resets all of the components.
*/
private void resetComponents() {
this.resetRuleComponents();
this.setsListModel.clear();
this.setNameTextField.setText("");
this.setDescriptionTextArea.setText("");
this.ignoreKnownFilesCheckbox.setSelected(true);
this.newSetButton.setEnabled(true);
this.editSetButton.setEnabled(false);
this.deleteSetButton.setEnabled(false);
}
/**
* Clears the rules list model and resets all of the rule-related
* components.
*/
private void resetRuleComponents() {
this.ruleNameTextField.setText("");
this.fileNameTextField.setText("");
this.fileNameRadioButton.setSelected(true);
this.fileNameRegexCheckbox.setSelected(false);
this.filesRadioButton.setSelected(true);
this.rulePathFilterTextField.setText("");
this.rulePathFilterRegexCheckBox.setSelected(false);
this.newRuleButton.setEnabled(!this.setsListModel.isEmpty());
this.editRuleButton.setEnabled(false);
this.deleteRuleButton.setEnabled(false);
}
/**
* A list events listener for the interesting files sets list component.
*/
private final class SetsListSelectionListener implements ListSelectionListener {
@Override
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting()) {
return;
}
InterestingItemDefsPanel.this.rulesListModel.clear();
InterestingItemDefsPanel.this.resetRuleComponents();
// Get the selected interesting files set and populate the set
// components.
FilesSet selectedSet = InterestingItemDefsPanel.this.setsList.getSelectedValue();
if (selectedSet != null) {
// Populate the components that display the properties of the
// selected files set.
InterestingItemDefsPanel.this.setNameTextField.setText(selectedSet.getName());
InterestingItemDefsPanel.this.setDescriptionTextArea.setText(selectedSet.getDescription());
InterestingItemDefsPanel.this.ignoreKnownFilesCheckbox.setSelected(selectedSet.ignoresKnownFiles());
// Enable the new, edit and delete set buttons.
InterestingItemDefsPanel.this.newSetButton.setEnabled(true);
InterestingItemDefsPanel.this.editSetButton.setEnabled(true);
InterestingItemDefsPanel.this.deleteSetButton.setEnabled(true);
// Populate the rule definitions list, sorted by name.
TreeMap<String, FilesSet.Rule> rules = new TreeMap<>(selectedSet.getRules());
for (FilesSet.Rule rule : rules.values()) {
InterestingItemDefsPanel.this.rulesListModel.addElement(rule);
}
// Select the first rule by default.
if (!InterestingItemDefsPanel.this.rulesListModel.isEmpty()) {
InterestingItemDefsPanel.this.rulesList.setSelectedIndex(0);
}
}
}
}
/**
* A list events listener for the interesting files set rules list
* component.
*/
private final class RulesListSelectionListener implements ListSelectionListener {
@Override
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting()) {
return;
}
// Get the selected rule and populate the rule components.
FilesSet.Rule rule = InterestingItemDefsPanel.this.rulesList.getSelectedValue();
if (rule != null) {
// Get the filters that make up the rule.
FilesSet.Rule.FileNameFilter nameFilter = rule.getFileNameFilter();
FilesSet.Rule.MetaTypeFilter typeFilter = rule.getMetaTypeFilter();
FilesSet.Rule.ParentPathFilter pathFilter = rule.getPathFilter();
// Populate the components that display the properties of the
// selected rule.
InterestingItemDefsPanel.this.ruleNameTextField.setText(rule.getName());
InterestingItemDefsPanel.this.fileNameTextField.setText(nameFilter.getTextToMatch());
InterestingItemDefsPanel.this.fileNameRadioButton.setSelected(nameFilter instanceof FilesSet.Rule.FullNameFilter);
InterestingItemDefsPanel.this.fileNameExtensionRadioButton.setSelected(nameFilter instanceof FilesSet.Rule.ExtensionFilter);
InterestingItemDefsPanel.this.fileNameRegexCheckbox.setSelected(nameFilter.isRegex());
switch (typeFilter.getMetaType()) {
case FILES:
InterestingItemDefsPanel.this.filesRadioButton.setSelected(true);
break;
case DIRECTORIES:
InterestingItemDefsPanel.this.dirsRadioButton.setSelected(true);
break;
case FILES_AND_DIRECTORIES:
InterestingItemDefsPanel.this.bothRadioButton.setSelected(true);
break;
}
if (pathFilter != null) {
InterestingItemDefsPanel.this.rulePathFilterTextField.setText(pathFilter.getTextToMatch());
InterestingItemDefsPanel.this.rulePathFilterRegexCheckBox.setSelected(pathFilter.isRegex());
} else {
InterestingItemDefsPanel.this.rulePathFilterTextField.setText("");
InterestingItemDefsPanel.this.rulePathFilterRegexCheckBox.setSelected(false);
}
// Enable the new, edit and delete rule buttons.
InterestingItemDefsPanel.this.newRuleButton.setEnabled(true);
InterestingItemDefsPanel.this.editRuleButton.setEnabled(true);
InterestingItemDefsPanel.this.deleteRuleButton.setEnabled(true);
} else {
InterestingItemDefsPanel.this.resetRuleComponents();
}
}
}
/**
* Display an interesting files set definition panel in a dialog box and
* respond to user interactions with the dialog.
*
* @param selectedSet The currently selected files set, may be null to
* indicate a new interesting files set definition is to be created.
*/
private void doFileSetsDialog(FilesSet selectedSet) {
// Create a files set defintion panle.
FilesSetPanel panel;
if (selectedSet != null) {
// Editing an existing set definition.
panel = new FilesSetPanel(selectedSet);
} else {
// Creating a new set definition.
panel = new FilesSetPanel();
}
// Do a dialog box with the files set panel until the user either enters
// a valid definition or cancels. Note that the panel gives the user
// feedback when isValidDefinition() is called.
int option = JOptionPane.OK_OPTION;
do {
option = JOptionPane.showConfirmDialog(null, panel, NbBundle.getMessage(FilesSetPanel.class, "FilesSetPanel.title"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
} while (option == JOptionPane.OK_OPTION && !panel.isValidDefinition());
if (option == JOptionPane.OK_OPTION) {
Map<String, FilesSet.Rule> rules = new HashMap<>();
if (selectedSet != null) {
// Interesting file sets are immutable for thread safety,
// so editing a files set definition is a replacement operation.
// Preserve the existing rules from the set being edited.
rules.putAll(selectedSet.getRules());
}
this.replaceFilesSet(selectedSet, panel.getFilesSetName(), panel.getFilesSetDescription(), panel.getFileSetIgnoresKnownFiles(), rules);
}
}
/**
* Display an interesting files set membership rule definition panel in a
* dialog box and respond to user interactions with the dialog.
*
* @param selectedRule The currently selected rule, may be null to indicate
* a new rule definition is to be created.
*/
private void doFilesSetRuleDialog(FilesSet.Rule selectedRule) {
// Create a files set rule panel.
FilesSetRulePanel panel;
if (selectedRule != null) {
// Editing an existing rule definition.
panel = new FilesSetRulePanel(selectedRule);
} else {
// Creating a new rule definition.
panel = new FilesSetRulePanel();
}
// Do a dialog box with the files set panel until the user either enters
// a valid definition or cancels. Note that the panel gives the user
// feedback when isValidDefinition() is called.
int option = JOptionPane.OK_OPTION;
do {
option = JOptionPane.showConfirmDialog(null, panel, NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.title"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
} while (option == JOptionPane.OK_OPTION && !panel.isValidRuleDefinition());
if (option == JOptionPane.OK_OPTION) {
// Interesting file sets are immutable for thread safety,
// so editing a files set rule definition is a replacement
// operation. Preserve the existing rules from the set being edited.
FilesSet selectedSet = this.setsList.getSelectedValue();
Map<String, FilesSet.Rule> rules = new HashMap<>(selectedSet.getRules());
// Remove the "old" rule definition and add the new/edited
// definition.
if (selectedRule != null) {
rules.remove(selectedRule.getName());
}
FilesSet.Rule newRule = new FilesSet.Rule(panel.getRuleName(), panel.getFileNameFilter(), panel.getMetaTypeFilter(), panel.getPathFilter());
rules.put(newRule.getName(), newRule);
// Add the new/edited files set definition, replacing any previous
// definition with the same name and refreshing the display.
this.replaceFilesSet(selectedSet, selectedSet.getName(), selectedSet.getDescription(), selectedSet.ignoresKnownFiles(), rules);
// Select the new/edited rule. Queue it up so it happens after the
// selection listeners react to the selection of the "new" files
// set.
EventQueue.invokeLater(() -> {
this.rulesList.setSelectedValue(newRule, true);
});
}
}
/**
* Adds an interesting files set definition to the collection of definitions
* owned by this panel. If there is a definition with the same name, it will
* be replaced, so this is an add/edit operation.
*
* @param oldSet A set to replace, null if the new set is not a replacement.
* @param name The name of the files set.
* @param description The description of the files set.
* @param ignoresKnownFiles Whether or not the files set ignores known
* files.
* @param rules The set membership rules for the set.
*/
void replaceFilesSet(FilesSet oldSet, String name, String description, boolean ignoresKnownFiles, Map<String, FilesSet.Rule> rules) {
if (oldSet != null) {
// Remove the set to be replaced from the working copy if the files
// set definitions.
this.filesSets.remove(oldSet.getName());
}
// Make the new/edited set definition and add it to the working copy of
// the files set definitions.
FilesSet newSet = new FilesSet(name, description, ignoresKnownFiles, rules);
this.filesSets.put(newSet.getName(), newSet);
// Redo the list model for the files set list component, which will make
// everything stays sorted as in the working copy tree set.
InterestingItemDefsPanel.this.setsListModel.clear();
for (FilesSet set : this.filesSets.values()) {
this.setsListModel.addElement(set);
}
// Select the new/edited files set definition in the set definitions
// list. This will cause the selection listeners to repopulate the
// subordinate components.
this.setsList.setSelectedValue(newSet, true);
}
/**
* 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() {
fileNameButtonGroup = new javax.swing.ButtonGroup();
setsListLabel = new javax.swing.JLabel();
rulesListLabel = new javax.swing.JLabel();
setsListScrollPane = new javax.swing.JScrollPane();
setsList = new javax.swing.JList<FilesSet>();
rulesListScrollPane = new javax.swing.JScrollPane();
rulesList = new javax.swing.JList<FilesSet.Rule>();
selectedSetLabel = new javax.swing.JLabel();
ignoreKnownFilesCheckbox = new javax.swing.JCheckBox();
selectedRuleLabel = new javax.swing.JLabel();
newSetButton = new javax.swing.JButton();
editSetButton = new javax.swing.JButton();
deleteSetButton = new javax.swing.JButton();
newRuleButton = new javax.swing.JButton();
editRuleButton = new javax.swing.JButton();
deleteRuleButton = new javax.swing.JButton();
separator = new javax.swing.JSeparator();
setNameTextField = new javax.swing.JTextField();
ruleNameTextField = new javax.swing.JTextField();
fileNamePanel = new javax.swing.JPanel();
fileNameRegexCheckbox = new javax.swing.JCheckBox();
fileNameExtensionRadioButton = new javax.swing.JRadioButton();
fileNameTextField = new javax.swing.JTextField();
fileNameRadioButton = new javax.swing.JRadioButton();
rulePathPanel = new javax.swing.JPanel();
rulePathFilterRegexCheckBox = new javax.swing.JCheckBox();
rulePathFilterTextField = new javax.swing.JTextField();
setDescPanel = new javax.swing.JPanel();
setDescScrollPanel = new javax.swing.JScrollPane();
setDescriptionTextArea = new javax.swing.JTextArea();
typePanel = new javax.swing.JPanel();
filesRadioButton = new javax.swing.JRadioButton();
dirsRadioButton = new javax.swing.JRadioButton();
bothRadioButton = new javax.swing.JRadioButton();
org.openide.awt.Mnemonics.setLocalizedText(setsListLabel, org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.setsListLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(rulesListLabel, org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.rulesListLabel.text")); // NOI18N
setsList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
setsListScrollPane.setViewportView(setsList);
rulesList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
rulesListScrollPane.setViewportView(rulesList);
org.openide.awt.Mnemonics.setLocalizedText(selectedSetLabel, org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.selectedSetLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(ignoreKnownFilesCheckbox, org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.ignoreKnownFilesCheckbox.text")); // NOI18N
ignoreKnownFilesCheckbox.setEnabled(false);
org.openide.awt.Mnemonics.setLocalizedText(selectedRuleLabel, org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.selectedRuleLabel.text")); // NOI18N
newSetButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add16.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(newSetButton, org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.newSetButton.text")); // NOI18N
newSetButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
newSetButtonActionPerformed(evt);
}
});
editSetButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/edit16.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(editSetButton, org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.editSetButton.text")); // NOI18N
editSetButton.setEnabled(false);
editSetButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
editSetButtonActionPerformed(evt);
}
});
deleteSetButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/delete16.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(deleteSetButton, org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.deleteSetButton.text")); // NOI18N
deleteSetButton.setEnabled(false);
deleteSetButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
deleteSetButtonActionPerformed(evt);
}
});
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(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.newRuleButton.text")); // NOI18N
newRuleButton.setEnabled(false);
newRuleButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
newRuleButtonActionPerformed(evt);
}
});
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(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.editRuleButton.text")); // NOI18N
editRuleButton.setEnabled(false);
editRuleButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
editRuleButtonActionPerformed(evt);
}
});
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(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.deleteRuleButton.text")); // NOI18N
deleteRuleButton.setEnabled(false);
deleteRuleButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
deleteRuleButtonActionPerformed(evt);
}
});
separator.setOrientation(javax.swing.SwingConstants.VERTICAL);
setNameTextField.setEditable(false);
ruleNameTextField.setEditable(false);
ruleNameTextField.setText(org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.ruleNameTextField.text")); // NOI18N
fileNamePanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.fileNamePanel.border.title"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(fileNameRegexCheckbox, org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.fileNameRegexCheckbox.text")); // NOI18N
fileNameRegexCheckbox.setEnabled(false);
fileNameButtonGroup.add(fileNameExtensionRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(fileNameExtensionRadioButton, org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.fileNameExtensionRadioButton.text")); // NOI18N
fileNameExtensionRadioButton.setEnabled(false);
fileNameTextField.setEditable(false);
fileNameTextField.setText(org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.fileNameTextField.text")); // NOI18N
fileNameButtonGroup.add(fileNameRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(fileNameRadioButton, org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.fileNameRadioButton.text")); // NOI18N
fileNameRadioButton.setEnabled(false);
javax.swing.GroupLayout fileNamePanelLayout = new javax.swing.GroupLayout(fileNamePanel);
fileNamePanel.setLayout(fileNamePanelLayout);
fileNamePanelLayout.setHorizontalGroup(
fileNamePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(fileNamePanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(fileNamePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(fileNameTextField)
.addGroup(fileNamePanelLayout.createSequentialGroup()
.addComponent(fileNameRadioButton)
.addGap(10, 10, 10)
.addComponent(fileNameExtensionRadioButton, javax.swing.GroupLayout.PREFERRED_SIZE, 114, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(fileNameRegexCheckbox)))
.addContainerGap())
);
fileNamePanelLayout.setVerticalGroup(
fileNamePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(fileNamePanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(fileNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(fileNamePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(fileNameRadioButton)
.addComponent(fileNameExtensionRadioButton)
.addComponent(fileNameRegexCheckbox))
.addContainerGap())
);
rulePathPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.rulePathPanel.border.title"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(rulePathFilterRegexCheckBox, org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.rulePathFilterRegexCheckBox.text")); // NOI18N
rulePathFilterRegexCheckBox.setEnabled(false);
rulePathFilterTextField.setEditable(false);
rulePathFilterTextField.setText(org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.rulePathFilterTextField.text")); // NOI18N
javax.swing.GroupLayout rulePathPanelLayout = new javax.swing.GroupLayout(rulePathPanel);
rulePathPanel.setLayout(rulePathPanelLayout);
rulePathPanelLayout.setHorizontalGroup(
rulePathPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(rulePathPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(rulePathPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(rulePathFilterRegexCheckBox)
.addComponent(rulePathFilterTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 283, javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
rulePathPanelLayout.setVerticalGroup(
rulePathPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(rulePathPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(rulePathFilterTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(rulePathFilterRegexCheckBox)
.addContainerGap())
);
setDescPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.setDescPanel.border.title"))); // NOI18N
setDescriptionTextArea.setEditable(false);
setDescriptionTextArea.setColumns(20);
setDescriptionTextArea.setRows(5);
setDescScrollPanel.setViewportView(setDescriptionTextArea);
javax.swing.GroupLayout setDescPanelLayout = new javax.swing.GroupLayout(setDescPanel);
setDescPanel.setLayout(setDescPanelLayout);
setDescPanelLayout.setHorizontalGroup(
setDescPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(setDescPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(setDescScrollPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 296, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
setDescPanelLayout.setVerticalGroup(
setDescPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, setDescPanelLayout.createSequentialGroup()
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(setDescScrollPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
typePanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.typePanel.border.title"))); // NOI18N
filesRadioButton.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(filesRadioButton, org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.filesRadioButton.text")); // NOI18N
filesRadioButton.setEnabled(false);
org.openide.awt.Mnemonics.setLocalizedText(dirsRadioButton, org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.dirsRadioButton.text")); // NOI18N
dirsRadioButton.setEnabled(false);
org.openide.awt.Mnemonics.setLocalizedText(bothRadioButton, org.openide.util.NbBundle.getMessage(InterestingItemDefsPanel.class, "InterestingItemDefsPanel.bothRadioButton.text")); // NOI18N
bothRadioButton.setEnabled(false);
javax.swing.GroupLayout typePanelLayout = new javax.swing.GroupLayout(typePanel);
typePanel.setLayout(typePanelLayout);
typePanelLayout.setHorizontalGroup(
typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(typePanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(filesRadioButton)
.addGap(18, 18, 18)
.addComponent(dirsRadioButton)
.addGap(18, 18, 18)
.addComponent(bothRadioButton)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
typePanelLayout.setVerticalGroup(
typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(typePanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(filesRadioButton)
.addComponent(dirsRadioButton)
.addComponent(bothRadioButton))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, 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()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addGroup(layout.createSequentialGroup()
.addComponent(newSetButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(editSetButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(deleteSetButton))
.addComponent(setsListLabel)
.addComponent(setsListScrollPane)
.addComponent(ignoreKnownFilesCheckbox)
.addGroup(layout.createSequentialGroup()
.addComponent(selectedSetLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(setNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 208, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(setDescPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(separator, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addGroup(layout.createSequentialGroup()
.addComponent(selectedRuleLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(ruleNameTextField))
.addComponent(rulesListLabel)
.addComponent(fileNamePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(rulePathPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addGap(10, 10, 10)
.addComponent(newRuleButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(editRuleButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(deleteRuleButton))
.addComponent(rulesListScrollPane)
.addComponent(typePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {deleteRuleButton, deleteSetButton, editRuleButton, editSetButton, newRuleButton, newSetButton});
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(setsListLabel)
.addComponent(rulesListLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(setsListScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 199, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(selectedSetLabel)
.addComponent(setNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(setDescPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(ignoreKnownFilesCheckbox))
.addGroup(layout.createSequentialGroup()
.addComponent(rulesListScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 122, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(selectedRuleLabel)
.addComponent(ruleNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(16, 16, 16)
.addComponent(typePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(fileNamePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(rulePathPanel, 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.LEADING)
.addComponent(deleteRuleButton)
.addComponent(editRuleButton)
.addComponent(newRuleButton)
.addComponent(deleteSetButton)
.addComponent(editSetButton)
.addComponent(newSetButton)))
.addComponent(separator, javax.swing.GroupLayout.PREFERRED_SIZE, 474, javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap())
);
layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {deleteRuleButton, deleteSetButton, editRuleButton, editSetButton, newRuleButton, newSetButton});
}// </editor-fold>//GEN-END:initComponents
private void newSetButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newSetButtonActionPerformed
this.doFileSetsDialog(null);
}//GEN-LAST:event_newSetButtonActionPerformed
private void editSetButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editSetButtonActionPerformed
this.doFileSetsDialog(this.setsList.getSelectedValue());
}//GEN-LAST:event_editSetButtonActionPerformed
private void newRuleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newRuleButtonActionPerformed
this.doFilesSetRuleDialog(null);
}//GEN-LAST:event_newRuleButtonActionPerformed
private void editRuleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editRuleButtonActionPerformed
this.doFilesSetRuleDialog(this.rulesList.getSelectedValue());
}//GEN-LAST:event_editRuleButtonActionPerformed
private void deleteSetButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteSetButtonActionPerformed
FilesSet selectedSet = this.setsList.getSelectedValue();
this.filesSets.remove(selectedSet.getName());
this.setsListModel.removeElement(selectedSet);
// Select the first of the remaining set definitions. This will cause
// the selection listeners to repopulate the subordinate components.
if (!this.filesSets.isEmpty()) {
this.setsList.setSelectedIndex(0);
} else {
this.resetComponents();
}
}//GEN-LAST:event_deleteSetButtonActionPerformed
private void deleteRuleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteRuleButtonActionPerformed
// Interesting file sets are immutable for thread safety,
// so editing a files set rule definition is a replacement
// operation. Preserve the existing rules from the set being
// edited, except for the deleted rule.
FilesSet oldSet = this.setsList.getSelectedValue();
Map<String, FilesSet.Rule> rules = new HashMap<>(oldSet.getRules());
FilesSet.Rule selectedRule = this.rulesList.getSelectedValue();
rules.remove(selectedRule.getName());
this.replaceFilesSet(oldSet, oldSet.getName(), oldSet.getDescription(), oldSet.ignoresKnownFiles(), rules);
}//GEN-LAST:event_deleteRuleButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JRadioButton bothRadioButton;
private javax.swing.JButton deleteRuleButton;
private javax.swing.JButton deleteSetButton;
private javax.swing.JRadioButton dirsRadioButton;
private javax.swing.JButton editRuleButton;
private javax.swing.JButton editSetButton;
private javax.swing.ButtonGroup fileNameButtonGroup;
private javax.swing.JRadioButton fileNameExtensionRadioButton;
private javax.swing.JPanel fileNamePanel;
private javax.swing.JRadioButton fileNameRadioButton;
private javax.swing.JCheckBox fileNameRegexCheckbox;
private javax.swing.JTextField fileNameTextField;
private javax.swing.JRadioButton filesRadioButton;
private javax.swing.JCheckBox ignoreKnownFilesCheckbox;
private javax.swing.JButton newRuleButton;
private javax.swing.JButton newSetButton;
private javax.swing.JTextField ruleNameTextField;
private javax.swing.JCheckBox rulePathFilterRegexCheckBox;
private javax.swing.JTextField rulePathFilterTextField;
private javax.swing.JPanel rulePathPanel;
private javax.swing.JList<FilesSet.Rule> rulesList;
private javax.swing.JLabel rulesListLabel;
private javax.swing.JScrollPane rulesListScrollPane;
private javax.swing.JLabel selectedRuleLabel;
private javax.swing.JLabel selectedSetLabel;
private javax.swing.JSeparator separator;
private javax.swing.JPanel setDescPanel;
private javax.swing.JScrollPane setDescScrollPanel;
private javax.swing.JTextArea setDescriptionTextArea;
private javax.swing.JTextField setNameTextField;
private javax.swing.JList<FilesSet> setsList;
private javax.swing.JLabel setsListLabel;
private javax.swing.JScrollPane setsListScrollPane;
private javax.swing.JPanel typePanel;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,110 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 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.modules.interestingitems;
import java.util.ArrayList;
import java.util.List;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel;
/**
* A factory that creates ingest modules that use interesting files set
* definitions to identify files that may be of interest to the user.
*/
@ServiceProvider(service = IngestModuleFactory.class)
final public class InterestingItemsIngestModuleFactory extends IngestModuleFactoryAdapter {
@Override
public String getModuleDisplayName() {
return getModuleName();
}
static String getModuleName() {
return NbBundle.getMessage(InterestingItemsIngestModuleFactory.class, "InterestingItemsIdentifierIngestModule.moduleName");
}
@Override
public String getModuleDescription() {
return NbBundle.getMessage(InterestingItemsIngestModuleFactory.class, "InterestingItemsIdentifierIngestModule.moduleDescription");
}
@Override
public String getModuleVersionNumber() {
return Version.getVersion();
}
@Override
public boolean hasGlobalSettingsPanel() {
return true;
}
@Override
public IngestModuleGlobalSettingsPanel getGlobalSettingsPanel() {
InterestingItemDefsPanel panel = new InterestingItemDefsPanel();
panel.load();
return panel;
}
@Override
public IngestModuleIngestJobSettings getDefaultIngestJobSettings() {
// All interesting files set definitions are enabled by default. The
// names of the set definitions are stored instead of the set
// definitions to make per ingest job enabling and disabling of the
// definitions independent of the rules that make up the defintions.
// Doing so also keeps the serialization simple.
List<String> enabledFilesSetNames = new ArrayList<>();
for (String name : InterestingItemDefsManager.getInstance().getInterestingFilesSets().keySet()) {
enabledFilesSetNames.add(name);
}
return new FilesIdentifierIngestJobSettings(enabledFilesSetNames);
}
@Override
public boolean hasIngestJobSettingsPanel() {
return true;
}
@Override
public IngestModuleIngestJobSettingsPanel getIngestJobSettingsPanel(IngestModuleIngestJobSettings settings) {
if (!(settings instanceof FilesIdentifierIngestJobSettings)) {
throw new IllegalArgumentException("Settings not instanceof org.sleuthkit.autopsy.modules.interestingitems.InterestingItemsIngestJobSettings");
}
return FilesIdentifierIngestJobSettingsPanel.makePanel((FilesIdentifierIngestJobSettings) settings);
}
@Override
public boolean isFileIngestModuleFactory() {
return true;
}
@Override
public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings settings) {
if (!(settings instanceof FilesIdentifierIngestJobSettings)) {
throw new IllegalArgumentException("Settings not instanceof org.sleuthkit.autopsy.modules.interestingitems.InterestingItemsIngestJobSettings");
}
return new FilesIdentifierIngestModule((FilesIdentifierIngestJobSettings) settings);
}
}