19 package org.sleuthkit.autopsy.allcasessearch;
 
   21 import java.awt.Color;
 
   22 import java.awt.event.ItemEvent;
 
   23 import java.awt.event.ItemListener;
 
   24 import java.text.Collator;
 
   25 import java.util.ArrayList;
 
   26 import java.util.Collection;
 
   27 import java.util.Collections;
 
   28 import java.util.List;
 
   29 import java.util.concurrent.ExecutionException;
 
   30 import java.util.logging.Level;
 
   31 import javax.swing.JFrame;
 
   32 import javax.swing.SwingWorker;
 
   33 import javax.swing.event.DocumentEvent;
 
   34 import javax.swing.event.DocumentListener;
 
   35 import org.apache.commons.lang3.StringUtils;
 
   36 import org.openide.nodes.Node;
 
   37 import org.openide.util.NbBundle.Messages;
 
   38 import org.openide.windows.TopComponent;
 
   39 import org.openide.windows.WindowManager;
 
   54     "AllCasesSearchDialog.dialogTitle.text=Search Central Repository",
 
   55     "AllCasesSearchDialog.resultsTitle.text=All Cases",
 
   56     "AllCasesSearchDialog.resultsDescription.text=Search Central Repository",
 
   57     "AllCasesSearchDialog.emptyNode.text=No results found.",
 
   58     "AllCasesSearchDialog.validation.invalidHash=The supplied value is not a valid MD5 hash.",
 
   59     "AllCasesSearchDialog.validation.invalidEmail=The supplied value is not a valid e-mail address.",
 
   60     "AllCasesSearchDialog.validation.invalidDomain=The supplied value is not a valid domain.",
 
   61     "AllCasesSearchDialog.validation.invalidPhone=The supplied value is not a valid phone number.",
 
   62     "AllCasesSearchDialog.validation.invalidSsid=The supplied value is not a valid wireless network.",
 
   63     "AllCasesSearchDialog.validation.invalidMac=The supplied value is not a valid MAC address.",
 
   64     "AllCasesSearchDialog.validation.invalidImei=The supplied value is not a valid IMEI number.",
 
   65     "AllCasesSearchDialog.validation.invalidImsi=The supplied value is not a valid IMSI number.",
 
   66     "AllCasesSearchDialog.validation.invalidIccid=The supplied value is not a valid ICCID number.",
 
   67     "AllCasesSearchDialog.validation.genericMessage=The supplied value is not valid.",
 
   68     "# {0} - number of cases",
 
   69     "AllCasesSearchDialog.caseLabel.text=The Central Repository contains {0} case(s)." 
   75 @SuppressWarnings(
"PMD.SingularField") 
 
   76     final class AllCasesSearchDialog extends javax.swing.JDialog {
 
   78     private static final Logger logger = Logger.getLogger(AllCasesSearchDialog.class.getName());
 
   79     private static final long serialVersionUID = 1L;
 
   81     private final List<CorrelationAttributeInstance.Type> correlationTypes;
 
   82     private CorrelationAttributeInstance.Type selectedCorrelationType;
 
   83     private TextPrompt correlationValueTextFieldPrompt;
 
   88     AllCasesSearchDialog() {
 
   89         super((JFrame) WindowManager.getDefault().getMainWindow(), Bundle.AllCasesSearchDialog_dialogTitle_text(), 
true);
 
   90         this.correlationTypes = 
new ArrayList<>();
 
   92         customizeComponents();
 
  101     private void search(CorrelationAttributeInstance.Type type, String[] values) {
 
  102         new SwingWorker<List<CorrelationAttributeInstance>, Void>() {
 
  105             protected List<CorrelationAttributeInstance> doInBackground() {
 
  106                 List<CorrelationAttributeInstance> correlationInstances = 
new ArrayList<>();
 
  108                 for (String value : values) {
 
  110                         correlationInstances.addAll(CentralRepository.getInstance().getArtifactInstancesByTypeValue(type, value));
 
  111                     } 
catch (CentralRepoException ex) {
 
  112                         logger.log(Level.SEVERE, 
"Unable to connect to the Central Repository database.", ex);
 
  113                     } 
catch (CorrelationAttributeNormalizationException ex) {
 
  114                         logger.log(Level.SEVERE, 
"Unable to retrieve data from the Central Repository.", ex);
 
  118                 return correlationInstances;
 
  122             protected void done() {
 
  125                     List<CorrelationAttributeInstance> correlationInstances = this.
get();
 
  126                     DataResultViewerTable table = 
new DataResultViewerTable();
 
  127                     Collection<DataResultViewer> viewers = 
new ArrayList<>(1);
 
  130                     AllCasesSearchNode searchNode = 
new AllCasesSearchNode(correlationInstances);
 
  131                     TableFilterNode tableFilterNode = 
new TableFilterNode(searchNode, 
true, searchNode.getName());
 
  133                     String resultsText = String.format(
"%s (%s)",
 
  134                             Bundle.AllCasesSearchDialog_resultsTitle_text(), type.getDisplayName());
 
  135                     final TopComponent searchResultWin;
 
  136                     if (correlationInstances.isEmpty()) {
 
  137                         Node emptyNode = 
new TableFilterNode(
 
  138                                 new EmptyNode(Bundle.AllCasesSearchDialog_emptyNode_text()), 
true);
 
  139                         searchResultWin = DataResultTopComponent.createInstance(
 
  140                                 resultsText, Bundle.AllCasesSearchDialog_resultsDescription_text(), emptyNode, 0);
 
  142                         searchResultWin = DataResultTopComponent.createInstance(
 
  143                                 resultsText, Bundle.AllCasesSearchDialog_resultsDescription_text(), tableFilterNode, correlationInstances.size(), viewers);
 
  145                     searchResultWin.requestActive(); 
 
  146                 } 
catch (ExecutionException | InterruptedException ex) {
 
  147                     logger.log(Level.SEVERE, 
"Unable to get CorrelationAttributeInstances.", ex);
 
  158     @SuppressWarnings(
"unchecked")
 
  160     private 
void initComponents() {
 
  162         correlationValueLabel = 
new javax.swing.JLabel();
 
  163         searchButton = 
new javax.swing.JButton();
 
  164         correlationTypeComboBox = 
new javax.swing.JComboBox<>();
 
  165         correlationTypeLabel = 
new javax.swing.JLabel();
 
  166         errorLabel = 
new javax.swing.JLabel();
 
  167         descriptionLabel = 
new javax.swing.JLabel();
 
  168         casesLabel = 
new javax.swing.JLabel();
 
  169         correlationValueScrollPane = 
new javax.swing.JScrollPane();
 
  170         correlationValueTextArea = 
new javax.swing.JTextArea();
 
  171         normalizedLabel = 
new javax.swing.JLabel();
 
  173         setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
 
  176         org.openide.awt.Mnemonics.setLocalizedText(correlationValueLabel, 
org.openide.util.NbBundle.getMessage(AllCasesSearchDialog.class, 
"AllCasesSearchDialog.correlationValueLabel.text")); 
 
  178         org.openide.awt.Mnemonics.setLocalizedText(searchButton, 
org.openide.util.NbBundle.getMessage(AllCasesSearchDialog.class, 
"AllCasesSearchDialog.searchButton.text")); 
 
  179         searchButton.addActionListener(
new java.awt.event.ActionListener() {
 
  180             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  181                 searchButtonActionPerformed(evt);
 
  185         correlationTypeComboBox.addActionListener(
new java.awt.event.ActionListener() {
 
  186             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  187                 correlationTypeComboBoxActionPerformed(evt);
 
  191         org.openide.awt.Mnemonics.setLocalizedText(correlationTypeLabel, 
org.openide.util.NbBundle.getMessage(AllCasesSearchDialog.class, 
"AllCasesSearchDialog.correlationTypeLabel.text")); 
 
  193         errorLabel.setForeground(
new java.awt.Color(255, 0, 0));
 
  194         org.openide.awt.Mnemonics.setLocalizedText(errorLabel, 
org.openide.util.NbBundle.getMessage(AllCasesSearchDialog.class, 
"AllCasesSearchDialog.errorLabel.text")); 
 
  196         org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel, 
org.openide.util.NbBundle.getMessage(AllCasesSearchDialog.class, 
"AllCasesSearchDialog.descriptionLabel.text")); 
 
  198         casesLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
 
  199         org.openide.awt.Mnemonics.setLocalizedText(casesLabel, 
org.openide.util.NbBundle.getMessage(AllCasesSearchDialog.class, 
"AllCasesSearchDialog.casesLabel.text")); 
 
  201         correlationValueTextArea.setColumns(20);
 
  202         correlationValueTextArea.setRows(5);
 
  203         correlationValueTextArea.setText(
org.openide.util.NbBundle.getMessage(AllCasesSearchDialog.class, 
"AllCasesSearchDialog.correlationValueTextArea.text")); 
 
  204         correlationValueScrollPane.setViewportView(correlationValueTextArea);
 
  206         org.openide.awt.Mnemonics.setLocalizedText(normalizedLabel, 
org.openide.util.NbBundle.getMessage(AllCasesSearchDialog.class, 
"AllCasesSearchDialog.normalizedLabel.text")); 
 
  208         javax.swing.GroupLayout layout = 
new javax.swing.GroupLayout(getContentPane());
 
  209         getContentPane().setLayout(layout);
 
  210         layout.setHorizontalGroup(
 
  211             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  212             .addGroup(layout.createSequentialGroup()
 
  214                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  215                     .addComponent(descriptionLabel)
 
  216                     .addGroup(layout.createSequentialGroup()
 
  217                         .addComponent(casesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  218                         .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  219                         .addComponent(searchButton))
 
  220                     .addGroup(layout.createSequentialGroup()
 
  221                         .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  222                             .addComponent(correlationValueLabel)
 
  223                             .addComponent(correlationTypeLabel))
 
  224                         .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
 
  225                         .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  226                             .addGroup(layout.createSequentialGroup()
 
  227                                 .addComponent(normalizedLabel)
 
  228                                 .addGap(0, 0, Short.MAX_VALUE))
 
  229                             .addGroup(layout.createSequentialGroup()
 
  230                                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  231                                     .addComponent(correlationTypeComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  232                                     .addGroup(layout.createSequentialGroup()
 
  233                                         .addComponent(correlationValueScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 379, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  234                                         .addGap(0, 0, Short.MAX_VALUE)))
 
  235                                 .addGap(142, 142, 142))
 
  236                             .addComponent(errorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
 
  239         layout.setVerticalGroup(
 
  240             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  241             .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
 
  243                 .addComponent(descriptionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 39, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  245                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
 
  246                     .addComponent(correlationTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  247                     .addComponent(correlationTypeLabel))
 
  249                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  250                     .addComponent(correlationValueLabel)
 
  251                     .addComponent(correlationValueScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 190, javax.swing.GroupLayout.PREFERRED_SIZE))
 
  252                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  253                 .addComponent(normalizedLabel)
 
  254                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 19, Short.MAX_VALUE)
 
  255                 .addComponent(errorLabel)
 
  256                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  257                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  258                     .addComponent(casesLabel, javax.swing.GroupLayout.Alignment.TRAILING)
 
  259                     .addComponent(searchButton, javax.swing.GroupLayout.Alignment.TRAILING))
 
  263         searchButton.getAccessibleContext().setAccessibleName(
org.openide.util.NbBundle.getMessage(AllCasesSearchDialog.class, 
"AllCasesSearchDialog.searchButton.AccessibleContext.accessibleName")); 
 
  264         searchButton.getAccessibleContext().setAccessibleDescription(
org.openide.util.NbBundle.getMessage(AllCasesSearchDialog.class, 
"AllCasesSearchDialog.searchButton.AccessibleContext.accessibleDescription")); 
 
  269     private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {
 
  270         CorrelationAttributeInstance.Type correlationType = selectedCorrelationType;
 
  271         String correlationValue = correlationValueTextArea.getText().trim();
 
  273         String[] correlationValueLines = correlationValue.split(
"\r\n|\n|\r");
 
  276             if (validateInputs(correlationType, correlationValueLines)) {
 
  277                 search(correlationType, correlationValueLines);
 
  280                 String validationMessage;
 
  281                 switch (correlationType.getId()) {
 
  282                     case CorrelationAttributeInstance.FILES_TYPE_ID:
 
  283                         validationMessage = Bundle.AllCasesSearchDialog_validation_invalidHash();
 
  285                     case CorrelationAttributeInstance.DOMAIN_TYPE_ID:
 
  286                         validationMessage = Bundle.AllCasesSearchDialog_validation_invalidDomain();
 
  288                     case CorrelationAttributeInstance.EMAIL_TYPE_ID:
 
  289                         validationMessage = Bundle.AllCasesSearchDialog_validation_invalidEmail();
 
  291                     case CorrelationAttributeInstance.PHONE_TYPE_ID:
 
  292                         validationMessage = Bundle.AllCasesSearchDialog_validation_invalidPhone();
 
  294                     case CorrelationAttributeInstance.SSID_TYPE_ID:
 
  295                         validationMessage = Bundle.AllCasesSearchDialog_validation_invalidSsid();
 
  297                     case CorrelationAttributeInstance.MAC_TYPE_ID:
 
  298                         validationMessage = Bundle.AllCasesSearchDialog_validation_invalidMac();
 
  300                     case CorrelationAttributeInstance.IMEI_TYPE_ID:
 
  301                         validationMessage = Bundle.AllCasesSearchDialog_validation_invalidImei();
 
  303                     case CorrelationAttributeInstance.IMSI_TYPE_ID:
 
  304                         validationMessage = Bundle.AllCasesSearchDialog_validation_invalidImsi();
 
  306                     case CorrelationAttributeInstance.ICCID_TYPE_ID:
 
  307                         validationMessage = Bundle.AllCasesSearchDialog_validation_invalidIccid();
 
  310                         validationMessage = Bundle.AllCasesSearchDialog_validation_genericMessage();
 
  315                 errorLabel.setText(validationMessage);
 
  316                 searchButton.setEnabled(
false);
 
  317                 correlationValueTextArea.grabFocus();
 
  322     private void correlationTypeComboBoxActionPerformed(java.awt.event.ActionEvent evt) {
 
  324         errorLabel.setText(
"");
 
  335     private boolean validateInputs(CorrelationAttributeInstance.Type type, String[] values) {
 
  337              for (String value : values) {
 
  338                 CorrelationAttributeNormalizer.normalize(type, value);
 
  340         } 
catch (CorrelationAttributeNormalizationException ex) {
 
  351     private void customizeComponents() {
 
  352         searchButton.setEnabled(
false);
 
  358             CentralRepository dbManager = CentralRepository.getInstance();
 
  359             correlationTypes.clear();
 
  360             correlationTypes.addAll(dbManager.getDefinedCorrelationTypes());
 
  362             int numberOfCases = dbManager.getCases().size();
 
  363             casesLabel.setText(Bundle.AllCasesSearchDialog_caseLabel_text(numberOfCases));
 
  364         } 
catch (CentralRepoException ex) {
 
  365             logger.log(Level.SEVERE, 
"Unable to connect to the Central Repository database.", ex);
 
  368         List<String> displayNames = 
new ArrayList<>();
 
  369         for (CorrelationAttributeInstance.Type type : correlationTypes) {
 
  370             String displayName = type.getDisplayName();
 
  371             if (displayName.toLowerCase().contains(
"addresses")) {
 
  372                 type.setDisplayName(displayName.replace(
"Addresses", 
"Address"));
 
  373             } 
else if (displayName.toLowerCase().equals(
"files")) {
 
  374                 type.setDisplayName(
"File MD5");
 
  375             } 
else if (displayName.toLowerCase().endsWith(
"s") && !displayName.toLowerCase().endsWith(
"address")) {
 
  376                 type.setDisplayName(StringUtils.substring(displayName, 0, displayName.length() - 1));
 
  378                 type.setDisplayName(displayName);
 
  381             displayNames.add(type.getDisplayName());
 
  383         Collections.sort(displayNames);
 
  384         for (String displayName : displayNames) {
 
  385             correlationTypeComboBox.addItem(displayName);
 
  388         correlationTypeComboBox.setSelectedIndex(0);
 
  390         correlationTypeComboBox.addItemListener(
new ItemListener() {
 
  392             public void itemStateChanged(ItemEvent e) {
 
  393                 updateSelectedType();
 
  394                 updateCorrelationValueTextFieldPrompt();
 
  395                 updateSearchButton();
 
  399         updateSelectedType();
 
  404         correlationValueTextArea.getDocument().addDocumentListener(
new DocumentListener() {
 
  406             public void changedUpdate(DocumentEvent e) {
 
  407                 updateSearchButton();
 
  411             public void insertUpdate(DocumentEvent e) {
 
  412                 updateSearchButton();
 
  416             public void removeUpdate(DocumentEvent e) {
 
  417                 updateSearchButton();
 
  421         updateCorrelationValueTextFieldPrompt();
 
  425         "AllCasesSearchDialog.correlationValueTextField.filesExample=Example: \"f0e1d2c3b4a5968778695a4b3c2d1e0f\"",
 
  426         "AllCasesSearchDialog.correlationValueTextField.domainExample=Example: \"domain.com\"",
 
  427         "AllCasesSearchDialog.correlationValueTextField.emailExample=Example: \"user@host.com\"",
 
  428         "AllCasesSearchDialog.correlationValueTextField.phoneExample=Example: \"(800)123-4567\"",
 
  429         "AllCasesSearchDialog.correlationValueTextField.usbExample=Example: \"4&1234567&0\"",
 
  430         "AllCasesSearchDialog.correlationValueTextField.ssidExample=Example: \"WirelessNetwork-5G\"",
 
  431         "AllCasesSearchDialog.correlationValueTextField.macExample=Example: \"0C-14-F2-01-AF-45\"",
 
  432         "AllCasesSearchDialog.correlationValueTextField.imeiExample=Example: \"351756061523999\"",
 
  433         "AllCasesSearchDialog.correlationValueTextField.imsiExample=Example: \"310150123456789\"",
 
  434         "AllCasesSearchDialog.correlationValueTextField.iccidExample=Example: \"89 91 19 1299 99 329451 0\"" 
  440     private void updateCorrelationValueTextFieldPrompt() {
 
  445         switch (selectedCorrelationType.getId()) {
 
  446             case CorrelationAttributeInstance.FILES_TYPE_ID:
 
  447                 text = Bundle.AllCasesSearchDialog_correlationValueTextField_filesExample();
 
  449             case CorrelationAttributeInstance.DOMAIN_TYPE_ID:
 
  450                 text = Bundle.AllCasesSearchDialog_correlationValueTextField_domainExample();
 
  452             case CorrelationAttributeInstance.EMAIL_TYPE_ID:
 
  453                 text = Bundle.AllCasesSearchDialog_correlationValueTextField_emailExample();
 
  455             case CorrelationAttributeInstance.PHONE_TYPE_ID:
 
  456                 text = Bundle.AllCasesSearchDialog_correlationValueTextField_phoneExample();
 
  458             case CorrelationAttributeInstance.USBID_TYPE_ID:
 
  459                 text = Bundle.AllCasesSearchDialog_correlationValueTextField_usbExample();
 
  461             case CorrelationAttributeInstance.SSID_TYPE_ID:
 
  462                 text = Bundle.AllCasesSearchDialog_correlationValueTextField_ssidExample();
 
  464             case CorrelationAttributeInstance.MAC_TYPE_ID:
 
  465                 text = Bundle.AllCasesSearchDialog_correlationValueTextField_macExample();
 
  467             case CorrelationAttributeInstance.IMEI_TYPE_ID:
 
  468                 text = Bundle.AllCasesSearchDialog_correlationValueTextField_imeiExample();
 
  470             case CorrelationAttributeInstance.IMSI_TYPE_ID:
 
  471                 text = Bundle.AllCasesSearchDialog_correlationValueTextField_imsiExample();
 
  473             case CorrelationAttributeInstance.ICCID_TYPE_ID:
 
  474                 text = Bundle.AllCasesSearchDialog_correlationValueTextField_iccidExample();
 
  480         correlationValueTextFieldPrompt = 
new TextPrompt(text, correlationValueTextArea);
 
  485         correlationValueTextFieldPrompt.setForeground(Color.LIGHT_GRAY);
 
  486         correlationValueTextFieldPrompt.changeAlpha(0.9f); 
 
  496     private void updateSelectedType() {
 
  497         for (CorrelationAttributeInstance.Type type : correlationTypes) {
 
  498             if (type.getDisplayName().equals((String) correlationTypeComboBox.getSelectedItem())) {
 
  499                 selectedCorrelationType = type;
 
  509     private void updateSearchButton() {
 
  510         searchButton.setEnabled(correlationValueTextArea.getText().isEmpty() == 
false);
 
  516     public void display() {
 
  517         this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
 
  522     private javax.swing.JLabel casesLabel;
 
  523     private javax.swing.JComboBox<String> correlationTypeComboBox;
 
  524     private javax.swing.JLabel correlationTypeLabel;
 
  525     private javax.swing.JLabel correlationValueLabel;
 
  526     private javax.swing.JScrollPane correlationValueScrollPane;
 
  527     private javax.swing.JTextArea correlationValueTextArea;
 
  528     private javax.swing.JLabel descriptionLabel;
 
  529     private javax.swing.JLabel errorLabel;
 
  530     private javax.swing.JLabel normalizedLabel;
 
  531     private javax.swing.JButton searchButton;