diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index 002f87acba..df1358833f 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -29,6 +29,7 @@ import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootChildren.FileSizeNod import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootNode; import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesNode; import org.sleuthkit.autopsy.datamodel.accounts.Accounts; +import org.sleuthkit.autopsy.othercasessearch.CorrelationAttributeInstanceNode; /** * Visitor pattern that goes over all nodes in the directory tree. This includes @@ -125,6 +126,8 @@ public interface DisplayableItemNodeVisitor { T visit(CentralRepoCommonAttributeInstanceNode crfin); T visit(InstanceCountNode icn); + + T visit(CorrelationAttributeInstanceNode cain); /* * Tags @@ -214,6 +217,11 @@ public interface DisplayableItemNodeVisitor { return defaultVisit(icn); } + @Override + public T visit(CorrelationAttributeInstanceNode cain) { + return defaultVisit(cain); + } + @Override public T visit(CentralRepoCommonAttributeInstanceNode crfin){ return defaultVisit(crfin); diff --git a/Core/src/org/sleuthkit/autopsy/othercasessearch/Bundle.properties b/Core/src/org/sleuthkit/autopsy/othercasessearch/Bundle.properties new file mode 100755 index 0000000000..17ea13ee0b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/othercasessearch/Bundle.properties @@ -0,0 +1,10 @@ + +OtherCasesSearchDialog.searchButton.AccessibleContext.accessibleDescription= +OtherCasesSearchDialog.searchButton.AccessibleContext.accessibleName=Search +OtherCasesSearchDialog.searchButton.text=Search +OtherCasesSearchDialog.correlationValueTextField.text= +OtherCasesSearchDialog.correlationValueLabel.text=Correlation Property Value: +OtherCasesSearchDialog.descriptionLabel.text=Search data in the Central Repository from other cases. +OtherCasesSearchDialog.errorLabel.text=\ +OtherCasesSearchDialog.correlationTypeLabel.text=Correlation Property Type: +OtherCasesSearchDialog.casesLabel.text=\ diff --git a/Core/src/org/sleuthkit/autopsy/othercasessearch/CorrelationAttributeInstanceNode.java b/Core/src/org/sleuthkit/autopsy/othercasessearch/CorrelationAttributeInstanceNode.java new file mode 100755 index 0000000000..f3248d293b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/othercasessearch/CorrelationAttributeInstanceNode.java @@ -0,0 +1,141 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit 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.othercasessearch; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import javax.swing.Action; +import org.openide.nodes.Children; +import org.openide.nodes.Sheet; +import org.openide.util.NbBundle; +import org.openide.util.lookup.Lookups; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource; +import org.sleuthkit.autopsy.othercasessearch.Bundle; +import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; +import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; +import org.sleuthkit.autopsy.datamodel.NodeProperty; + +/** + * Used by the Other Cases Search feature to encapsulate instances of a given + * search match. + */ +public final class CorrelationAttributeInstanceNode extends DisplayableItemNode { + + private final CorrelationAttributeInstance instance; + + CorrelationAttributeInstanceNode(CorrelationAttributeInstance content) { + super(Children.LEAF, Lookups.fixed(content)); + this.instance = content; + this.setDisplayName(new File(this.instance.getFilePath()).getName()); + } + + /** + * Get the CorrelationAttributeInstance attached to the node. + * + * @return The CorrelationAttributeInstance object. + */ + public CorrelationAttributeInstance getCorrelationAttributeInstance(){ + return this.instance; + } + + @Override + public Action[] getActions(boolean context){ + List actionsList = new ArrayList<>(); + + actionsList.addAll(Arrays.asList(super.getActions(true))); + + return actionsList.toArray(new Action[actionsList.size()]); + } + + @Override + public T accept(DisplayableItemNodeVisitor visitor) { + return visitor.visit(this); + } + + @Override + public boolean isLeafTypeNode() { + return true; + } + + @Override + public String getItemType() { + return CorrelationAttributeInstanceNode.class.getName(); + } + + @NbBundle.Messages({ + "CorrelationAttributeInstanceNode.columnName.name=Name", + "CorrelationAttributeInstanceNode.columnName.case=Case", + "CorrelationAttributeInstanceNode.columnName.dataSource=Data Source", + "CorrelationAttributeInstanceNode.columnName.known=Known", + "CorrelationAttributeInstanceNode.columnName.path=Path", + "CorrelationAttributeInstanceNode.columnName.comment=Comment", + "CorrelationAttributeInstanceNode.columnName.device=Device" + }) + @Override + protected Sheet createSheet(){ + Sheet sheet = new Sheet(); + Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES); + + if(sheetSet == null){ + sheetSet = Sheet.createPropertiesSet(); + sheet.put(sheetSet); + } + + final CorrelationAttributeInstance centralRepoFile = this.getCorrelationAttributeInstance(); + + final String path = centralRepoFile.getFilePath(); + final File file = new File(path); + final String name = file.getName(); + final String caseName = centralRepoFile.getCorrelationCase().getDisplayName(); + final CorrelationDataSource dataSource = centralRepoFile.getCorrelationDataSource(); + final String dataSourceName = dataSource.getName(); + final String known = centralRepoFile.getKnownStatus().getName(); + final String comment = centralRepoFile.getComment(); + final String device = dataSource.getDeviceID(); + + final String NO_DESCR = ""; + + sheetSet.put(new NodeProperty<>( + Bundle.CorrelationAttributeInstanceNode_columnName_name(), + Bundle.CorrelationAttributeInstanceNode_columnName_name(), NO_DESCR, name)); + sheetSet.put(new NodeProperty<>( + Bundle.CorrelationAttributeInstanceNode_columnName_case(), + Bundle.CorrelationAttributeInstanceNode_columnName_case(), NO_DESCR, caseName)); + sheetSet.put(new NodeProperty<>( + Bundle.CorrelationAttributeInstanceNode_columnName_dataSource(), + Bundle.CorrelationAttributeInstanceNode_columnName_dataSource(), NO_DESCR, dataSourceName)); + sheetSet.put(new NodeProperty<>( + Bundle.CorrelationAttributeInstanceNode_columnName_known(), + Bundle.CorrelationAttributeInstanceNode_columnName_known(), NO_DESCR, known)); + sheetSet.put(new NodeProperty<>( + Bundle.CorrelationAttributeInstanceNode_columnName_path(), + Bundle.CorrelationAttributeInstanceNode_columnName_path(), NO_DESCR, path)); + sheetSet.put(new NodeProperty<>( + Bundle.CorrelationAttributeInstanceNode_columnName_comment(), + Bundle.CorrelationAttributeInstanceNode_columnName_comment(), NO_DESCR, comment)); + sheetSet.put(new NodeProperty<>( + Bundle.CorrelationAttributeInstanceNode_columnName_device(), + Bundle.CorrelationAttributeInstanceNode_columnName_device(), NO_DESCR, device)); + + return sheet; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesFilterChildren.java b/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesFilterChildren.java new file mode 100755 index 0000000000..abe37bb15e --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesFilterChildren.java @@ -0,0 +1,85 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit 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.othercasessearch; + +import org.openide.nodes.Children; +import org.openide.nodes.FilterNode; +import org.openide.nodes.Node; +import org.sleuthkit.autopsy.corecomponents.TableFilterNode; + +/** + * A Children implementation for a + * CorrelationPropertyFilterNode. + */ +final class OtherCasesFilterChildren extends FilterNode.Children { + + /** + * Create a new Children instance. + * + * @param wrappedNode The node to be wrapped. + * @param createChildren If false, return LEAF. Otherwise, return a new + * CorrelationPropertyFilterChildren instance. + * + * @return A Children instance. + */ + static Children createInstance(Node wrappedNode, boolean createChildren) { + + if (createChildren) { + return new OtherCasesFilterChildren(wrappedNode); + } else { + return Children.LEAF; + } + } + + /** + * Constructs a children (child factory) implementation for a + * CorrelationPropertyFilterNode. + * + * @param wrappedNode The node wrapped by CorrelationPropertyFilterNode. + */ + OtherCasesFilterChildren(Node wrappedNode) { + super(wrappedNode); + } + + /** + * Copies a CorrelationPropertyFilterNode, with the children (child factory) + * flag set to false. + * + * @param nodeToCopy The CorrelationPropertyFilterNode to copy. + * + * @return A copy of a CorrelationPropertyFilterNode. + */ + @Override + protected Node copyNode(Node nodeToCopy) { + return new TableFilterNode(nodeToCopy, false); + } + + /** + * Creates the child nodes represented by this children (child factory) + * object. + * + * @param key The key, i.e., the node, for which to create the child nodes. + * + * @return A single-element node array. + */ + @Override + protected Node[] createNodes(Node key) { + return new Node[]{this.copyNode(key)}; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchAction.java b/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchAction.java new file mode 100755 index 0000000000..55dcda0a24 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchAction.java @@ -0,0 +1,69 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit 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.othercasessearch; + +import java.awt.event.ActionEvent; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.awt.ActionRegistration; +import org.openide.util.HelpCtx; +import org.openide.util.NbBundle; +import org.openide.util.actions.CallableSystemAction; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; +import org.sleuthkit.autopsy.othercasessearch.Bundle; + +/** + * Action for accessing the Search Other Cases dialog. + */ +@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.othercasessearch.OtherCasesSearchAction") +@ActionRegistration(displayName = "#CTL_OtherCasesSearchAction=Search Other Cases", lazy = false) +@ActionReference(path = "Menu/Tools", position = 104) +@NbBundle.Messages({"CTL_OtherCasesSearchAction=Search Other Cases"}) +public class OtherCasesSearchAction extends CallableSystemAction { + + @Override + public boolean isEnabled() { + return EamDb.isEnabled() && Case.isCaseOpen(); + } + + @Override + public void actionPerformed(ActionEvent event) { + performAction(); + } + + @Override + public void performAction() { + OtherCasesSearchDialog dialog = new OtherCasesSearchDialog(); + dialog.display(); + } + + @NbBundle.Messages({ + "OtherCasesSearchAction.getName.text=Search Other Cases"}) + @Override + public String getName() { + return Bundle.OtherCasesSearchAction_getName_text(); + } + + @Override + public HelpCtx getHelpCtx() { + return HelpCtx.DEFAULT_HELP; + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchChildren.java b/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchChildren.java new file mode 100755 index 0000000000..eea55a6518 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchChildren.java @@ -0,0 +1,49 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit 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.othercasessearch; + +import java.util.List; +import org.openide.nodes.Children; +import org.openide.nodes.Node; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; + +/** + * Creates CorrelationAttributeInstanceNodes from a collection of + * CorrelationAttributeInstances. + */ +class OtherCasesSearchChildren extends Children.Keys { + + /** + * Create an instance of OtherCasesSearchChildren. + * + * @param lazy Lazy load? + * @param fileList List of CorrelationAttributeInstances. + */ + OtherCasesSearchChildren(boolean lazy, List instances) { + super(lazy); + this.setKeys(instances); + } + + @Override + protected Node[] createNodes(CorrelationAttributeInstance t) { + Node[] node = new Node[1]; + node[0] = new CorrelationAttributeInstanceNode(t); + return node; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.form b/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.form new file mode 100755 index 0000000000..00eb862b4a --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.form @@ -0,0 +1,159 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.java b/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.java new file mode 100755 index 0000000000..51e21631d2 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.java @@ -0,0 +1,381 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit 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.othercasessearch; + +import java.awt.Color; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.swing.JFrame; +import javax.swing.SwingWorker; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import org.openide.nodes.Node; +import org.openide.util.Exceptions; +import org.openide.util.NbBundle.Messages; +import org.openide.windows.TopComponent; +import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer; +import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; +import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; +import org.sleuthkit.autopsy.corecomponents.TableFilterNode; +import org.sleuthkit.autopsy.corecomponents.TextPrompt; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.EmptyNode; + +@Messages({ + "OtherCasesSearchDialog.dialogTitle.text=Search Other Cases", + "OtherCasesSearchDialog.resultsTitle.text=Other Cases", + "OtherCasesSearchDialog.resultsDescription.text=Other Cases Search", + "OtherCasesSearchDialog.emptyNode.text=No results found.", + "OtherCasesSearchDialog.validation.invalidHash=The supplied value is not a valid MD5 hash.", + "# {0} - number of cases", + "OtherCasesSearchDialog.caseLabel.text=The current Central Repository contains {0} case(s)." +}) +/** + * The Search Other Cases dialog allows users to search for specific + * types of correlation properties in the Central Repository. + */ +@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives +final class OtherCasesSearchDialog extends javax.swing.JDialog { + private static final Logger logger = Logger.getLogger(OtherCasesSearchDialog.class.getName()); + private static final long serialVersionUID = 1L; + + private static final String FILES_CORRELATION_TYPE = "Files"; + + private final List correlationTypes; + private TextPrompt correlationValueTextFieldPrompt; + + /** + * Creates a new instance of the Search Other Cases dialog. + */ + OtherCasesSearchDialog() { + super((JFrame) WindowManager.getDefault().getMainWindow(), Bundle.OtherCasesSearchDialog_dialogTitle_text(), true); + this.correlationTypes = new ArrayList<>(); + initComponents(); + customizeComponents(); + } + + /** + * Perform the other cases search. + */ + private void search() { + new SwingWorker, Void>() { + + @Override + protected List doInBackground() { + List correlationTypes; + List correlationInstances = new ArrayList<>(); + + try { + correlationTypes = EamDb.getInstance().getDefinedCorrelationTypes(); + for (CorrelationAttributeInstance.Type type : correlationTypes) { + if (type.getDisplayName().equals((String) correlationTypeComboBox.getSelectedItem())) { + correlationInstances = EamDb.getInstance().getArtifactInstancesByTypeValue(type, correlationValueTextField.getText()); + break; + } + } + } catch (EamDbException ex) { + logger.log(Level.SEVERE, "Unable to connect to the Central Repository database.", ex); + } catch (CorrelationAttributeNormalizationException ex) { + logger.log(Level.SEVERE, "Unable to retrieve data from the Central Repository.", ex); + } + + return correlationInstances; + } + + @Override + protected void done() { + try { + super.done(); + List correlationInstances = this.get(); + DataResultViewerTable table = new DataResultViewerTable(); + Collection viewers = new ArrayList<>(1); + viewers.add(table); + + OtherCasesSearchNode searchNode = new OtherCasesSearchNode(correlationInstances); + TableFilterNode tableFilterNode = new TableFilterNode(searchNode, true, searchNode.getName()); + + String resultsText = String.format("%s (%s; \"%s\")", + Bundle.OtherCasesSearchDialog_resultsTitle_text(), + (String) correlationTypeComboBox.getSelectedItem(), + correlationValueTextField.getText()); + final TopComponent searchResultWin; + if (correlationInstances.isEmpty()) { + Node emptyNode = new TableFilterNode( + new EmptyNode(Bundle.OtherCasesSearchDialog_emptyNode_text()), true); + searchResultWin = DataResultTopComponent.createInstance( + resultsText, Bundle.OtherCasesSearchDialog_resultsDescription_text(), emptyNode, 0); + } else { + searchResultWin = DataResultTopComponent.createInstance( + resultsText, Bundle.OtherCasesSearchDialog_resultsDescription_text(), tableFilterNode, correlationInstances.size(), viewers); + } + searchResultWin.requestActive(); // make it the active top component + } catch (ExecutionException | InterruptedException ex) { + logger.log(Level.SEVERE, "Unable to get CorrelationAttributeInstances.", ex); + } + } + }.execute(); + } + + /** + * 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") + // //GEN-BEGIN:initComponents + private void initComponents() { + + correlationValueLabel = new javax.swing.JLabel(); + correlationValueTextField = new javax.swing.JTextField(); + searchButton = new javax.swing.JButton(); + correlationTypeComboBox = new javax.swing.JComboBox<>(); + correlationTypeLabel = new javax.swing.JLabel(); + errorLabel = new javax.swing.JLabel(); + descriptionLabel = new javax.swing.JLabel(); + casesLabel = new javax.swing.JLabel(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setResizable(false); + + org.openide.awt.Mnemonics.setLocalizedText(correlationValueLabel, org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.correlationValueLabel.text")); // NOI18N + + correlationValueTextField.setText(org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.correlationValueTextField.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(searchButton, org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.searchButton.text")); // NOI18N + searchButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + searchButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(correlationTypeLabel, org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.correlationTypeLabel.text")); // NOI18N + + errorLabel.setForeground(new java.awt.Color(255, 0, 0)); + org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.errorLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel, org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.descriptionLabel.text")); // NOI18N + + casesLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + org.openide.awt.Mnemonics.setLocalizedText(casesLabel, org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.casesLabel.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().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(casesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(18, 18, 18) + .addComponent(searchButton)) + .addGroup(layout.createSequentialGroup() + .addComponent(descriptionLabel) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(correlationValueLabel) + .addComponent(correlationTypeLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(correlationTypeComboBox, 0, 289, Short.MAX_VALUE) + .addComponent(correlationValueTextField) + .addComponent(errorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addComponent(descriptionLabel) + .addGap(18, 18, 18) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(correlationTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(correlationTypeLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(correlationValueLabel) + .addComponent(correlationValueTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(errorLabel) + .addGap(11, 11, 11) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(searchButton) + .addComponent(casesLabel)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + searchButton.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.searchButton.AccessibleContext.accessibleName")); // NOI18N + searchButton.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.searchButton.AccessibleContext.accessibleDescription")); // NOI18N + + pack(); + }// //GEN-END:initComponents + + private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed + if (validateInputs()) { + /* + * Just in case, we'll lock down the type and value components to + * avoid the possibly of a race condition. + */ + correlationTypeComboBox.setEnabled(false); + correlationValueTextField.setEnabled(false); + + search(); + dispose(); + } else { + searchButton.setEnabled(false); + errorLabel.setText(Bundle.OtherCasesSearchDialog_validation_invalidHash()); + correlationValueTextField.grabFocus(); + } + }//GEN-LAST:event_searchButtonActionPerformed + + /** + * Further customize the components beyond the standard initialization. + */ + private void customizeComponents() { + searchButton.setEnabled(false); + + /* + * Add correlation types to the combo-box. + */ + try { + EamDb dbManager = EamDb.getInstance(); + correlationTypes.clear(); + correlationTypes.addAll(dbManager.getDefinedCorrelationTypes()); + int numberOfCases = dbManager.getCases().size(); + casesLabel.setText(Bundle.OtherCasesSearchDialog_caseLabel_text(numberOfCases)); + } catch (EamDbException ex) { + logger.log(Level.SEVERE, "Unable to connect to the Central Repository database.", ex); + } + + for (CorrelationAttributeInstance.Type type : correlationTypes) { + // We only support the "Files" type for now. + if (type.getDisplayName().equals(FILES_CORRELATION_TYPE)) { + correlationTypeComboBox.addItem(type.getDisplayName()); + } + } + correlationTypeComboBox.setSelectedIndex(0); + + correlationTypeComboBox.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + updateSearchButton(); + } + }); + + /* + * Create listener for text input. + */ + correlationValueTextField.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void changedUpdate(DocumentEvent e) { + updateSearchButton(); + } + + @Override + public void insertUpdate(DocumentEvent e) { + updateSearchButton(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + updateSearchButton(); + } + }); + + updateCorrelationValueTextFieldPrompt(); + } + + @Messages({ + "OtherCasesSearchDialog.correlationValueTextField.filesExample=Example: \"f0e1d2c3b4a5968778695a4b3c2d1e0f\"" + }) + /** + * Update the text prompt of the name text field based on the input type + * selection. + */ + private void updateCorrelationValueTextFieldPrompt() { + /** + * Add text prompt to the text field. + */ + String text = Bundle.OtherCasesSearchDialog_correlationValueTextField_filesExample(); + correlationValueTextFieldPrompt = new TextPrompt(text, correlationValueTextField); + + /** + * Sets the foreground color and transparency of the text prompt. + */ + correlationValueTextFieldPrompt.setForeground(Color.LIGHT_GRAY); + correlationValueTextFieldPrompt.changeAlpha(0.9f); // Mostly opaque + + validate(); + repaint(); + } + + /** + * Enable or disable the Search button depending on whether or not text has + * been provided for the correlation property value. + */ + private void updateSearchButton() { + searchButton.setEnabled(correlationValueTextField.getText().isEmpty() == false); + } + + /** + * Validate the value input. + * + * @return True if the input is valid for the selected type; otherwise false. + */ + private boolean validateInputs() { + Pattern md5Pattern = Pattern.compile("^[a-fA-F0-9]{32}$"); // NON-NLS + Matcher matcher = md5Pattern.matcher(correlationValueTextField.getText().trim()); + if (matcher.find()) { + return true; + } + return false; + } + + /** + * Display the Search Other Cases dialog. + */ + public void display() { + this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); + setVisible(true); + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel casesLabel; + private javax.swing.JComboBox correlationTypeComboBox; + private javax.swing.JLabel correlationTypeLabel; + private javax.swing.JLabel correlationValueLabel; + private javax.swing.JTextField correlationValueTextField; + private javax.swing.JLabel descriptionLabel; + private javax.swing.JLabel errorLabel; + private javax.swing.JButton searchButton; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchNode.java b/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchNode.java new file mode 100755 index 0000000000..ff9c3a6d80 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchNode.java @@ -0,0 +1,47 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit 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.othercasessearch; + +import java.util.List; +import org.openide.nodes.AbstractNode; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; + +/** + * Parent node to OtherCasesSearchChildren. + */ +class OtherCasesSearchNode extends AbstractNode { + + /** + * Create an instance of OtherCasesSearchNode. + * + * @param keys The list of CorrelationAttributeInstances. + */ + OtherCasesSearchNode(List keys) { + super(new OtherCasesSearchChildren(true, keys)); + } + + @Messages({ + "OtherCasesSearchNode.getName.text=Other Cases Search" + }) + @Override + public String getName() { + return Bundle.OtherCasesSearchNode_getName_text(); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java b/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java index 618cba2a38..8ed4c46111 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java @@ -50,8 +50,8 @@ import org.sleuthkit.datamodel.BlackboardArtifact; @ActionID(category = "Tools", id = "org.sleuthkit.autopsy.report.ReportWizardAction") @ActionRegistration(displayName = "#CTL_ReportWizardAction", lazy = false) @ActionReferences(value = { - @ActionReference(path = "Menu/Tools", position = 103), - @ActionReference(path = "Toolbars/Case", position = 103)}) + @ActionReference(path = "Menu/Tools", position = 105), + @ActionReference(path = "Toolbars/Case", position = 105)}) public final class ReportWizardAction extends CallableSystemAction implements Presenter.Toolbar, ActionListener { private final JButton toolbarButton = new JButton(); diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java index 45563a4f4b..56f13e172a 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2017 Basis Technology Corp. + * Copyright 2017-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,7 +28,7 @@ import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; @ActionID(category = "Tools", id = "org.sleuthkit.autopsy.experimental.autoingest.AutoIngestDashboardOpenAction") -@ActionReference(path = "Menu/Tools", position = 104) +@ActionReference(path = "Menu/Tools", position = 106) @ActionRegistration(displayName = "#CTL_AutoIngestDashboardOpenAction", lazy = false) @Messages({"CTL_AutoIngestDashboardOpenAction=Auto Ingest Dashboard"}) public final class AutoIngestDashboardOpenAction extends CallableSystemAction {