Autopsy  4.16.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
FileSearchPanel.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2019 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.filesearch;
20 
21 import java.awt.Component;
22 import java.awt.Cursor;
23 import java.awt.GridLayout;
24 import java.awt.event.ActionEvent;
25 import java.awt.event.ActionListener;
26 import java.beans.PropertyChangeEvent;
27 import java.beans.PropertyChangeListener;
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.List;
32 import java.util.logging.Level;
33 import javax.swing.JLabel;
34 import javax.swing.JPanel;
35 import javax.swing.border.EmptyBorder;
36 import org.openide.DialogDisplayer;
37 import org.openide.NotifyDescriptor;
38 import org.openide.nodes.Node;
39 import org.openide.util.NbBundle;
40 import org.openide.windows.TopComponent;
49 import org.sleuthkit.datamodel.AbstractFile;
50 import org.sleuthkit.datamodel.SleuthkitCase;
51 import org.sleuthkit.datamodel.TskCoreException;
52 
56 @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
57 class FileSearchPanel extends javax.swing.JPanel {
58 
59  private final List<FileSearchFilter> filters = new ArrayList<>();
60  private static int resultWindowCount = 0; //keep track of result windows so they get unique names
61  private static final String EMPTY_WHERE_CLAUSE = NbBundle.getMessage(DateSearchFilter.class, "FileSearchPanel.emptyWhereClause.text");
62 
63  enum EVENT {
64  CHECKED
65  }
66 
70  FileSearchPanel() {
71  initComponents();
72  customizeComponents();
73 
74  }
75 
79  private void customizeComponents() {
80 
81  JLabel label = new JLabel(NbBundle.getMessage(this.getClass(), "FileSearchPanel.custComp.label.text"));
82  label.setAlignmentX(Component.LEFT_ALIGNMENT);
83  label.setBorder(new EmptyBorder(0, 0, 10, 0));
84 
85  JPanel panel1 = new JPanel();
86  panel1.setLayout(new GridLayout(1,2));
87  panel1.add(new JLabel(""));
88  JPanel panel2 = new JPanel();
89  panel2.setLayout(new GridLayout(1,2, 20, 0));
90  JPanel panel3 = new JPanel();
91  panel3.setLayout(new GridLayout(1,2, 20, 0));
92  JPanel panel4 = new JPanel();
93  panel4.setLayout(new GridLayout(1,2, 20, 0));
94  JPanel panel5 = new JPanel();
95  panel5.setLayout(new GridLayout(1,2, 20, 0));
96 
97  // Create and add filter areas
98  NameSearchFilter nameFilter = new NameSearchFilter();
99  SizeSearchFilter sizeFilter = new SizeSearchFilter();
100  DateSearchFilter dateFilter = new DateSearchFilter();
101  KnownStatusSearchFilter knowStatusFilter = new KnownStatusSearchFilter();
102  HashSearchFilter hashFilter = new HashSearchFilter();
103  MimeTypeFilter mimeTypeFilter = new MimeTypeFilter();
104  DataSourceFilter dataSourceFilter = new DataSourceFilter();
105 
106  panel2.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.name"),nameFilter));
107 
108  panel3.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.metadata"),sizeFilter));
109 
110  panel2.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.metadata"), dateFilter));
111  panel3.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.knownStatus"), knowStatusFilter));
112 
113  panel5.add(new FilterArea(NbBundle.getMessage(this.getClass(), "HashSearchPanel.md5CheckBox.text"), hashFilter));
114  panel5.add(new JLabel(""));
115  panel4.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.metadata"), mimeTypeFilter));
116  panel4.add(new FilterArea(NbBundle.getMessage(this.getClass(), "DataSourcePanel.dataSourceCheckBox.text"), dataSourceFilter));
117  filterPanel.add(panel1);
118  filterPanel.add(panel2);
119  filterPanel.add(panel3);
120  filterPanel.add(panel4);
121  filterPanel.add(panel5);
122 
123  filters.add(nameFilter);
124  filters.add(sizeFilter);
125  filters.add(dateFilter);
126  filters.add(knowStatusFilter);
127  filters.add(hashFilter);
128  filters.add(mimeTypeFilter);
129  filters.add(dataSourceFilter);
130 
131  for (FileSearchFilter filter : this.getFilters()) {
132  filter.addPropertyChangeListener(new PropertyChangeListener() {
133  @Override
134  public void propertyChange(PropertyChangeEvent evt) {
135  searchButton.setEnabled(isValidSearch());
136  }
137  });
138  }
139  addListenerToAll(new ActionListener() {
140  @Override
141  public void actionPerformed(ActionEvent e) {
142  search();
143  }
144  });
145  searchButton.setEnabled(isValidSearch());
146  }
147 
151  private boolean isValidSearch() {
152  boolean enabled = false;
153  for (FileSearchFilter filter : this.getFilters()) {
154  if (filter.isEnabled()) {
155  enabled = true;
156  if (!filter.isValid()) {
157  errorLabel.setText(filter.getLastError());
158  return false;
159  }
160  }
161  }
162 
163  errorLabel.setText("");
164  return enabled;
165  }
166 
171  @NbBundle.Messages("FileSearchPanel.emptyNode.display.text=No results found.")
172  private void search() {
173  // change the cursor to "waiting cursor" for this operation
174  this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
175  try {
176  if (this.isValidSearch()) {
177  String title = NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.results.title", ++resultWindowCount);
178  String pathText = NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.results.pathText");
179 
180  // try to get the number of matches first
181  Case currentCase = Case.getCurrentCaseThrows(); // get the most updated case
182  long totalMatches = 0;
183  List<AbstractFile> contentList = null;
184  try {
185  SleuthkitCase tskDb = currentCase.getSleuthkitCase();
186  contentList = tskDb.findAllFilesWhere(this.getQuery());
187 
188  } catch (TskCoreException ex) {
189  Logger logger = Logger.getLogger(this.getClass().getName());
190  logger.log(Level.WARNING, "Error while trying to get the number of matches.", ex); //NON-NLS
191  }
192 
193  if (contentList == null) {
194  contentList = Collections.<AbstractFile>emptyList();
195  }
196 
197  SearchNode sn = new SearchNode(contentList);
198  TableFilterNode tableFilterNode = new TableFilterNode(sn, true, sn.getName());
199  final TopComponent searchResultWin;
200  if (contentList.isEmpty()) {
201  Node emptyNode = new TableFilterNode(new EmptyNode(Bundle.FileSearchPanel_emptyNode_display_text()), true);
202  searchResultWin = DataResultTopComponent.createInstance(title, pathText,
203  emptyNode, 0);
204  } else {
205  searchResultWin = DataResultTopComponent.createInstance(title, pathText,
206  tableFilterNode, contentList.size());
207  }
208  searchResultWin.requestActive(); // make it the active top component
209 
215  if (totalMatches > 10000) {
216  // show info
217  String msg = NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.results.msg", totalMatches);
218  String details = NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.results.details");
219  MessageNotifyUtil.Notify.info(msg, details);
220  }
221  } else {
222  throw new FilterValidationException(
223  NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.exception.noFilterSelected.msg"));
224  }
225  } catch (FilterValidationException | NoCurrentCaseException ex) {
226  NotifyDescriptor d = new NotifyDescriptor.Message(
227  NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.validationErr.msg", ex.getMessage()));
228  DialogDisplayer.getDefault().notify(d);
229  } finally {
230  this.setCursor(null);
231  }
232  }
233 
252  private String getQuery() throws FilterValidationException {
253 
254  //String query = "SELECT " + tempQuery + " FROM tsk_files WHERE ";
255  String query = "";
256  int i = 0;
257  for (FileSearchFilter f : this.getEnabledFilters()) {
258  String result = f.getPredicate();
259  if (!result.isEmpty()) {
260  if (i > 0) {
261  query += " AND (" + result + ")"; //NON-NLS
262  } else {
263  query += " (" + result + ")"; //NON-NLS
264  }
265  ++i;
266  }
267  }
268 
269  if (query.isEmpty()) {
270  throw new FilterValidationException(EMPTY_WHERE_CLAUSE);
271  }
272  return query;
273  }
274 
275  private Collection<FileSearchFilter> getFilters() {
276  return filters;
277  }
278 
279  private Collection<FileSearchFilter> getEnabledFilters() {
280  Collection<FileSearchFilter> enabledFilters = new ArrayList<>();
281 
282  for (FileSearchFilter f : this.getFilters()) {
283  if (f.isEnabled()) {
284  enabledFilters.add(f);
285  }
286  }
287 
288  return enabledFilters;
289  }
290 
291  void addListenerToAll(ActionListener l) {
292  searchButton.addActionListener(l);
293  for (FileSearchFilter fsf : getFilters()) {
294  fsf.addActionListener(l);
295  }
296  }
297 
303  @SuppressWarnings("unchecked")
304  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
305  private void initComponents() {
306 
307  filterPanel = new javax.swing.JPanel();
308  searchButton = new javax.swing.JButton();
309  errorLabel = new javax.swing.JLabel();
310 
311  setPreferredSize(new java.awt.Dimension(300, 300));
312 
313  filterPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10));
314  filterPanel.setPreferredSize(new java.awt.Dimension(300, 400));
315  filterPanel.setLayout(new javax.swing.BoxLayout(filterPanel, javax.swing.BoxLayout.Y_AXIS));
316 
317  searchButton.setText(org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.searchButton.text")); // NOI18N
318 
319  errorLabel.setText(org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.errorLabel.text")); // NOI18N
320  errorLabel.setForeground(new java.awt.Color(255, 51, 51));
321 
322  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
323  this.setLayout(layout);
324  layout.setHorizontalGroup(
325  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
326  .addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
327  .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
328  .addContainerGap()
329  .addComponent(errorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
330  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
331  .addComponent(searchButton)
332  .addContainerGap())
333  );
334  layout.setVerticalGroup(
335  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
336  .addGroup(layout.createSequentialGroup()
337  .addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 266, Short.MAX_VALUE)
338  .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
339  .addComponent(searchButton)
340  .addComponent(errorLabel))
341  .addContainerGap())
342  );
343  }// </editor-fold>//GEN-END:initComponents
344 
345  // Variables declaration - do not modify//GEN-BEGIN:variables
346  private javax.swing.JLabel errorLabel;
347  private javax.swing.JPanel filterPanel;
348  private javax.swing.JButton searchButton;
349  // End of variables declaration//GEN-END:variables
350 }

Copyright © 2012-2020 Basis Technology. Generated on: Tue Sep 22 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.