Autopsy  4.21.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
ImageFilePanel.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2021 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.casemodule;
20 
21 import com.google.common.util.concurrent.ThreadFactoryBuilder;
22 import java.io.File;
23 import java.util.Calendar;
24 import java.util.List;
25 import java.util.concurrent.Future;
26 import java.util.concurrent.ScheduledThreadPoolExecutor;
27 import java.util.concurrent.TimeUnit;
28 import java.util.concurrent.locks.ReentrantLock;
29 import java.util.function.Supplier;
30 import java.util.logging.Level;
31 import javax.swing.JFileChooser;
32 import javax.swing.JOptionPane;
33 import javax.swing.JPanel;
34 import javax.swing.JTextField;
35 import javax.swing.event.DocumentEvent;
36 import javax.swing.event.DocumentListener;
37 import javax.swing.filechooser.FileFilter;
38 import org.apache.commons.lang3.StringUtils;
39 import org.openide.util.NbBundle;
50 
56 @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
57 public class ImageFilePanel extends JPanel {
58 
59  private static final Logger logger = Logger.getLogger(AddImageTask.class.getName());
60 
61  private static final long serialVersionUID = 1L;
62  private static final String PROP_LASTIMAGE_PATH = "LBL_LastImage_PATH"; //NON-NLS
63  private static final String[] SECTOR_SIZE_CHOICES = {"Auto Detect", "512", "1024", "2048", "4096"};
64  private final JFileChooserFactory fileChooserHelper = new JFileChooserFactory();
65  private JFileChooser fileChooser;
66  private final String contextName;
67  private final List<FileFilter> fileChooserFilters;
68 
69  private static int VALIDATE_TIMEOUT_MILLIS = 1000;
70  static ScheduledThreadPoolExecutor delayedValidationService = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("ImageFilePanel delayed validation").build());
71 
72  private final ReentrantLock validationWaitingLock = new ReentrantLock();
73  private final ReentrantLock validationLock = new ReentrantLock();
74 
75  private Runnable validateAction = null;
76  private Future<?> validateFuture = null;
77 
86  private ImageFilePanel(String context, List<FileFilter> fileChooserFilters) {
87  this.contextName = context;
88  initComponents();
89 
90  // Populate the drop down list of time zones
91  createTimeZoneList();
92 
93  // Populate the drop down list of sector size options
94  for (String choice : SECTOR_SIZE_CHOICES) {
95  sectorSizeComboBox.addItem(choice);
96  }
97  sectorSizeComboBox.setSelectedIndex(0);
98 
99  errorLabel.setVisible(false);
100  loadingLabel.setVisible(false);
101  this.fileChooserFilters = fileChooserFilters;
102  }
103 
108  private void createTimeZoneList() {
109  List<String> timeZoneList = TimeZoneUtils.createTimeZoneList();
110  for (String timeZone : timeZoneList) {
111  timeZoneComboBox.addItem(timeZone);
112  }
113 
114  // set the selected timezone
115  timeZoneComboBox.setSelectedItem(TimeZoneUtils.createTimeZoneString(Calendar.getInstance().getTimeZone()));
116  }
117 
128  public static synchronized ImageFilePanel createInstance(String context, List<FileFilter> fileChooserFilters) {
129  ImageFilePanel instance = new ImageFilePanel(context, fileChooserFilters);
130  DocumentListener delayedValidationListener = instance.new DelayedValidationDocListener();
131 
132  // post-constructor initialization of listener support without leaking references of uninitialized objects
133  for (JTextField textField: List.of(
134  instance.getPathTextField(),
135  instance.getMd5TextFieldField(),
136  instance.getSha1TextField(),
137  instance.getSha256TextField(),
138  instance.getPasswordTextField())) {
139  textField.getDocument().addDocumentListener(delayedValidationListener);
140  }
141  return instance;
142  }
143 
144  private JTextField getPathTextField() {
145  return pathTextField;
146  }
147 
148  private JTextField getMd5TextFieldField() {
149  return md5HashTextField;
150  }
151 
152  private JTextField getSha1TextField() {
153  return sha1HashTextField;
154  }
155 
156  private JTextField getSha256TextField() {
157  return sha256HashTextField;
158  }
159 
160  private JTextField getPasswordTextField() {
161  return passwordTextField;
162  }
163 
164  private JFileChooser getChooser() {
165  if(fileChooser == null) {
166  fileChooser = fileChooserHelper.getChooser();
167  fileChooser.setDragEnabled(false);
168  fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
169  fileChooser.setMultiSelectionEnabled(false);
170  fileChooserFilters.forEach(fileChooser::addChoosableFileFilter);
171  if (fileChooserFilters.isEmpty() == false) {
172  fileChooser.setFileFilter(fileChooserFilters.get(0));
173  }
174  }
175 
176  return fileChooser;
177  }
178 
184  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
185  private void initComponents() {
186  java.awt.GridBagConstraints gridBagConstraints;
187 
188  pathLabel = new javax.swing.JLabel();
189  browseButton = new javax.swing.JButton();
190  pathTextField = new javax.swing.JTextField();
191  timeZoneLabel = new javax.swing.JLabel();
192  timeZoneComboBox = new javax.swing.JComboBox<>();
193  noFatOrphansCheckbox = new javax.swing.JCheckBox();
194  errorLabel = new javax.swing.JLabel();
195  sectorSizeLabel = new javax.swing.JLabel();
196  sectorSizeComboBox = new javax.swing.JComboBox<>();
197  sha256HashLabel = new javax.swing.JLabel();
198  sha256HashTextField = new javax.swing.JTextField();
199  sha1HashTextField = new javax.swing.JTextField();
200  md5HashTextField = new javax.swing.JTextField();
201  sha1HashLabel = new javax.swing.JLabel();
202  md5HashLabel = new javax.swing.JLabel();
203  hashValuesLabel = new javax.swing.JLabel();
204  hashValuesNoteLabel = new javax.swing.JLabel();
205  passwordLabel = new javax.swing.JLabel();
206  passwordTextField = new javax.swing.JTextField();
207  javax.swing.JPanel spacer = new javax.swing.JPanel();
208  loadingLabel = new javax.swing.JLabel();
209 
210  setMinimumSize(new java.awt.Dimension(0, 65));
211  setPreferredSize(new java.awt.Dimension(403, 65));
212  setLayout(new java.awt.GridBagLayout());
213 
214  org.openide.awt.Mnemonics.setLocalizedText(pathLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.pathLabel.text")); // NOI18N
215  gridBagConstraints = new java.awt.GridBagConstraints();
216  gridBagConstraints.gridx = 0;
217  gridBagConstraints.gridy = 0;
218  gridBagConstraints.gridwidth = 3;
219  gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
220  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
221  gridBagConstraints.weightx = 1.0;
222  gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
223  add(pathLabel, gridBagConstraints);
224 
225  org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.browseButton.text")); // NOI18N
226  browseButton.addActionListener(new java.awt.event.ActionListener() {
227  public void actionPerformed(java.awt.event.ActionEvent evt) {
228  browseButtonActionPerformed(evt);
229  }
230  });
231  gridBagConstraints = new java.awt.GridBagConstraints();
232  gridBagConstraints.gridx = 2;
233  gridBagConstraints.gridy = 1;
234  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
235  gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5);
236  add(browseButton, gridBagConstraints);
237 
238  pathTextField.setText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.pathTextField.text")); // NOI18N
239  gridBagConstraints = new java.awt.GridBagConstraints();
240  gridBagConstraints.gridx = 0;
241  gridBagConstraints.gridy = 1;
242  gridBagConstraints.gridwidth = 2;
243  gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
244  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
245  gridBagConstraints.weightx = 1.0;
246  gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
247  add(pathTextField, gridBagConstraints);
248 
249  org.openide.awt.Mnemonics.setLocalizedText(timeZoneLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.timeZoneLabel.text")); // NOI18N
250  gridBagConstraints = new java.awt.GridBagConstraints();
251  gridBagConstraints.gridx = 0;
252  gridBagConstraints.gridy = 3;
253  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
254  gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
255  add(timeZoneLabel, gridBagConstraints);
256 
257  timeZoneComboBox.setMaximumRowCount(30);
258  gridBagConstraints = new java.awt.GridBagConstraints();
259  gridBagConstraints.gridx = 1;
260  gridBagConstraints.gridy = 3;
261  gridBagConstraints.gridwidth = 2;
262  gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
263  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
264  gridBagConstraints.weightx = 1.0;
265  gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5);
266  add(timeZoneComboBox, gridBagConstraints);
267 
268  org.openide.awt.Mnemonics.setLocalizedText(noFatOrphansCheckbox, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.noFatOrphansCheckbox.text")); // NOI18N
269  noFatOrphansCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.noFatOrphansCheckbox.toolTipText")); // NOI18N
270  gridBagConstraints = new java.awt.GridBagConstraints();
271  gridBagConstraints.gridx = 0;
272  gridBagConstraints.gridy = 2;
273  gridBagConstraints.gridwidth = 3;
274  gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
275  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
276  gridBagConstraints.weightx = 1.0;
277  gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
278  add(noFatOrphansCheckbox, gridBagConstraints);
279 
280  errorLabel.setForeground(new java.awt.Color(255, 0, 0));
281  org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.errorLabel.text")); // NOI18N
282  errorLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP);
283  errorLabel.setMaximumSize(new java.awt.Dimension(500, 60));
284  errorLabel.setMinimumSize(new java.awt.Dimension(200, 20));
285  errorLabel.setPreferredSize(new java.awt.Dimension(200, 60));
286  gridBagConstraints = new java.awt.GridBagConstraints();
287  gridBagConstraints.gridx = 0;
288  gridBagConstraints.gridy = 11;
289  gridBagConstraints.gridwidth = 3;
290  gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
291  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
292  gridBagConstraints.weightx = 1.0;
293  gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
294  add(errorLabel, gridBagConstraints);
295 
296  org.openide.awt.Mnemonics.setLocalizedText(sectorSizeLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.sectorSizeLabel.text")); // NOI18N
297  gridBagConstraints = new java.awt.GridBagConstraints();
298  gridBagConstraints.gridx = 0;
299  gridBagConstraints.gridy = 4;
300  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
301  gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
302  add(sectorSizeLabel, gridBagConstraints);
303 
304  gridBagConstraints = new java.awt.GridBagConstraints();
305  gridBagConstraints.gridx = 1;
306  gridBagConstraints.gridy = 4;
307  gridBagConstraints.gridwidth = 2;
308  gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
309  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
310  gridBagConstraints.weightx = 1.0;
311  gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5);
312  add(sectorSizeComboBox, gridBagConstraints);
313 
314  org.openide.awt.Mnemonics.setLocalizedText(sha256HashLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.sha256HashLabel.text")); // NOI18N
315  sha256HashLabel.setEnabled(false);
316  gridBagConstraints = new java.awt.GridBagConstraints();
317  gridBagConstraints.gridx = 0;
318  gridBagConstraints.gridy = 9;
319  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
320  gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
321  add(sha256HashLabel, gridBagConstraints);
322 
323  sha256HashTextField.setText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.sha256HashTextField.text")); // NOI18N
324  sha256HashTextField.setEnabled(false);
325  gridBagConstraints = new java.awt.GridBagConstraints();
326  gridBagConstraints.gridx = 1;
327  gridBagConstraints.gridy = 9;
328  gridBagConstraints.gridwidth = 2;
329  gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
330  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
331  gridBagConstraints.weightx = 1.0;
332  gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5);
333  add(sha256HashTextField, gridBagConstraints);
334 
335  sha1HashTextField.setText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.sha1HashTextField.text")); // NOI18N
336  sha1HashTextField.setEnabled(false);
337  gridBagConstraints = new java.awt.GridBagConstraints();
338  gridBagConstraints.gridx = 1;
339  gridBagConstraints.gridy = 8;
340  gridBagConstraints.gridwidth = 2;
341  gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
342  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
343  gridBagConstraints.weightx = 1.0;
344  gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5);
345  add(sha1HashTextField, gridBagConstraints);
346 
347  md5HashTextField.setText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.md5HashTextField.text")); // NOI18N
348  md5HashTextField.setEnabled(false);
349  gridBagConstraints = new java.awt.GridBagConstraints();
350  gridBagConstraints.gridx = 1;
351  gridBagConstraints.gridy = 7;
352  gridBagConstraints.gridwidth = 2;
353  gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
354  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
355  gridBagConstraints.weightx = 1.0;
356  gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5);
357  add(md5HashTextField, gridBagConstraints);
358 
359  org.openide.awt.Mnemonics.setLocalizedText(sha1HashLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.sha1HashLabel.text")); // NOI18N
360  sha1HashLabel.setEnabled(false);
361  gridBagConstraints = new java.awt.GridBagConstraints();
362  gridBagConstraints.gridx = 0;
363  gridBagConstraints.gridy = 8;
364  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
365  gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
366  add(sha1HashLabel, gridBagConstraints);
367 
368  org.openide.awt.Mnemonics.setLocalizedText(md5HashLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.md5HashLabel.text")); // NOI18N
369  md5HashLabel.setEnabled(false);
370  gridBagConstraints = new java.awt.GridBagConstraints();
371  gridBagConstraints.gridx = 0;
372  gridBagConstraints.gridy = 7;
373  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
374  gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
375  add(md5HashLabel, gridBagConstraints);
376 
377  org.openide.awt.Mnemonics.setLocalizedText(hashValuesLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.hashValuesLabel.text")); // NOI18N
378  hashValuesLabel.setEnabled(false);
379  gridBagConstraints = new java.awt.GridBagConstraints();
380  gridBagConstraints.gridx = 0;
381  gridBagConstraints.gridy = 6;
382  gridBagConstraints.gridwidth = 3;
383  gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
384  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
385  gridBagConstraints.weightx = 1.0;
386  gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
387  add(hashValuesLabel, gridBagConstraints);
388 
389  org.openide.awt.Mnemonics.setLocalizedText(hashValuesNoteLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.hashValuesNoteLabel.text")); // NOI18N
390  hashValuesNoteLabel.setEnabled(false);
391  gridBagConstraints = new java.awt.GridBagConstraints();
392  gridBagConstraints.gridx = 0;
393  gridBagConstraints.gridy = 10;
394  gridBagConstraints.gridwidth = 3;
395  gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
396  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
397  gridBagConstraints.weightx = 1.0;
398  gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
399  add(hashValuesNoteLabel, gridBagConstraints);
400 
401  org.openide.awt.Mnemonics.setLocalizedText(passwordLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.passwordLabel.text")); // NOI18N
402  gridBagConstraints = new java.awt.GridBagConstraints();
403  gridBagConstraints.gridx = 0;
404  gridBagConstraints.gridy = 5;
405  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
406  gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
407  add(passwordLabel, gridBagConstraints);
408 
409  passwordTextField.setText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.passwordTextField.text")); // NOI18N
410  gridBagConstraints = new java.awt.GridBagConstraints();
411  gridBagConstraints.gridx = 1;
412  gridBagConstraints.gridy = 5;
413  gridBagConstraints.gridwidth = 2;
414  gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
415  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
416  gridBagConstraints.weightx = 1.0;
417  gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5);
418  add(passwordTextField, gridBagConstraints);
419 
420  javax.swing.GroupLayout spacerLayout = new javax.swing.GroupLayout(spacer);
421  spacer.setLayout(spacerLayout);
422  spacerLayout.setHorizontalGroup(
423  spacerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
424  .addGap(0, 0, Short.MAX_VALUE)
425  );
426  spacerLayout.setVerticalGroup(
427  spacerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
428  .addGap(0, 0, Short.MAX_VALUE)
429  );
430 
431  gridBagConstraints = new java.awt.GridBagConstraints();
432  gridBagConstraints.gridx = 0;
433  gridBagConstraints.gridy = 12;
434  gridBagConstraints.weighty = 1.0;
435  add(spacer, gridBagConstraints);
436 
437  loadingLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/working_spinner.gif"))); // NOI18N
438  org.openide.awt.Mnemonics.setLocalizedText(loadingLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.loadingLabel.text")); // NOI18N
439  loadingLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP);
440  loadingLabel.setMaximumSize(new java.awt.Dimension(500, 60));
441  loadingLabel.setMinimumSize(new java.awt.Dimension(200, 20));
442  loadingLabel.setPreferredSize(new java.awt.Dimension(200, 60));
443  gridBagConstraints = new java.awt.GridBagConstraints();
444  gridBagConstraints.gridx = 0;
445  gridBagConstraints.gridy = 11;
446  gridBagConstraints.gridwidth = 3;
447  gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
448  gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
449  gridBagConstraints.weightx = 1.0;
450  gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
451  add(loadingLabel, gridBagConstraints);
452  }// </editor-fold>//GEN-END:initComponents
453 
454  @NbBundle.Messages({"ImageFilePanel.000.confirmationMessage=The selected file"
455  + " has extenson .001 but there is a .000 file in the sequence of raw images."
456  + "\nShould the .000 file be used as the start, instead of the selected .001 file?\n"})
457  private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
458  String oldText = getContentPaths();
459  // set the current directory of the FileChooser if the ImagePath Field is valid
460  File currentDir = new File(oldText);
461  JFileChooser chooser = getChooser();
462  if (currentDir.exists()) {
463  chooser.setCurrentDirectory(currentDir);
464  }
465 
466  if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
467  String path = chooser.getSelectedFile().getPath();
468  if (path.endsWith(".001")) {
469  String zeroX3_path = StringUtils.removeEnd(path, ".001") + ".000";
470  if (new File(zeroX3_path).exists()) {
471  int showConfirmDialog = JOptionPane.showConfirmDialog(this,
472  Bundle.ImageFilePanel_000_confirmationMessage(),
473  "Choose .001 file?", JOptionPane.YES_NO_OPTION);
474  if (showConfirmDialog == JOptionPane.YES_OPTION) {
475  path = zeroX3_path;
476  }
477  }
478  }
479 
480  setContentPath(path);
481 
486  if (!oldText.equals(getContentPaths())) {
487  md5HashTextField.setText(null);
488  sha1HashTextField.setText(null);
489  sha256HashTextField.setText(null);
490  }
491  }
492 
493  updateHelper();
494  }//GEN-LAST:event_browseButtonActionPerformed
495 
496  // Variables declaration - do not modify//GEN-BEGIN:variables
497  private javax.swing.JButton browseButton;
498  private javax.swing.JLabel errorLabel;
499  private javax.swing.JLabel hashValuesLabel;
500  private javax.swing.JLabel hashValuesNoteLabel;
501  private javax.swing.JLabel loadingLabel;
502  private javax.swing.JLabel md5HashLabel;
503  private javax.swing.JTextField md5HashTextField;
504  private javax.swing.JCheckBox noFatOrphansCheckbox;
505  private javax.swing.JLabel passwordLabel;
506  private javax.swing.JTextField passwordTextField;
507  private javax.swing.JLabel pathLabel;
508  private javax.swing.JTextField pathTextField;
509  private javax.swing.JComboBox<String> sectorSizeComboBox;
510  private javax.swing.JLabel sectorSizeLabel;
511  private javax.swing.JLabel sha1HashLabel;
512  private javax.swing.JTextField sha1HashTextField;
513  private javax.swing.JLabel sha256HashLabel;
514  private javax.swing.JTextField sha256HashTextField;
515  private javax.swing.JComboBox<String> timeZoneComboBox;
516  private javax.swing.JLabel timeZoneLabel;
517  // End of variables declaration//GEN-END:variables
518 
524  private void setHashValuesComponentsEnabled(boolean enabled) {
525  hashValuesLabel.setEnabled(enabled);
526  hashValuesNoteLabel.setEnabled(enabled);
527 
528  md5HashLabel.setEnabled(enabled);
529  md5HashTextField.setEnabled(enabled);
530 
531  sha1HashLabel.setEnabled(enabled);
532  sha1HashTextField.setEnabled(enabled);
533 
534  sha256HashLabel.setEnabled(enabled);
535  sha256HashTextField.setEnabled(enabled);
536  }
537 
543  public String getContentPaths() {
544  return pathTextField.getText();
545  }
546 
552  public void setContentPath(String s) {
553  pathTextField.setText(s);
554  }
555 
561  public int getSectorSize() {
562  int sectorSizeSelectionIndex = sectorSizeComboBox.getSelectedIndex();
563 
564  if (sectorSizeSelectionIndex == 0) {
565  return 0;
566  }
567 
568  return Integer.valueOf((String) sectorSizeComboBox.getSelectedItem());
569  }
570 
571  public String getTimeZone() {
572  String tz = timeZoneComboBox.getSelectedItem().toString();
573  return tz.substring(tz.indexOf(')') + 2).trim();
574  }
575 
576  public boolean getNoFatOrphans() {
577  return noFatOrphansCheckbox.isSelected();
578  }
579 
580  String getMd5() {
581  return this.md5HashTextField.getText();
582  }
583 
584  String getSha1() {
585  return this.sha1HashTextField.getText();
586  }
587 
588  String getSha256() {
589  return this.sha256HashTextField.getText();
590  }
591 
592  String getPassword() {
593  return this.passwordTextField.getText();
594  }
595 
596  public void reset() {
597  //reset the UI elements to default
598  pathTextField.setText(null);
599  this.md5HashTextField.setText(null);
600  this.sha1HashTextField.setText(null);
601  this.sha256HashTextField.setText(null);
602  this.passwordTextField.setText(null);
603  }
604 
610  private void setUIEnabled(boolean enabled, boolean validNonE01) {
611  this.browseButton.setEnabled(enabled);
612  this.noFatOrphansCheckbox.setEnabled(enabled);
613  this.passwordTextField.setEnabled(enabled);
614  this.pathTextField.setEnabled(enabled);
615  this.sectorSizeComboBox.setEnabled(enabled);
616  this.md5HashTextField.setEnabled(enabled && validNonE01);
617  this.sha1HashTextField.setEnabled(enabled && validNonE01);
618  this.sha256HashTextField.setEnabled(enabled && validNonE01);
619  this.timeZoneComboBox.setEnabled(enabled);
620  }
621 
627  @NbBundle.Messages({
628  "ImageFilePanel.validatePanel.dataSourceOnCDriveError=Warning: Path to multi-user data source is on \"C:\" drive",
629  "ImageFilePanel.validatePanel.invalidMD5=Invalid MD5 hash",
630  "ImageFilePanel.validatePanel.invalidSHA1=Invalid SHA1 hash",
631  "ImageFilePanel.validatePanel.invalidSHA256=Invalid SHA256 hash",
632  "# {0} - imageOpenError",
633  "ImageFilePanel_validatePanel_imageOpenError=<html><body><p>An error occurred while opening the image:{0}</p></body></html>",
634  "ImageFilePanel_validatePanel_unknownErrorMsg=<unknown>",
635  "ImageFilePanel_validatePanel_unknownError=<html><body><p>An unknown error occurred while attempting to validate the image</p></body></html>"
636  })
637  public boolean validatePanel() {
638  return runWithLock(this.validationLock, () -> {
639  boolean validNonE01 = true;
640  try {
641 
642  // acquire field values at the beginning to minimize chance of changing while validating.
643  String path = getContentPaths();
644 
645  validNonE01 = isValidNonE01(path);
646  setUIEnabled(false, validNonE01);
647 
648  String md5 = getMd5();
649  String sha1 = getSha1();
650  String sha256 = getSha256();
651  String password = getPassword();
652 
653  if (!isImagePathValid(path)) {
654  showError(null);
655  return false;
656  }
657 
658  if (!StringUtils.isBlank(md5) && !HashUtility.isValidMd5Hash(md5)) {
659  showError(Bundle.ImageFilePanel_validatePanel_invalidMD5());
660  return false;
661  }
662 
663  if (!StringUtils.isBlank(sha1) && !HashUtility.isValidSha1Hash(sha1)) {
664  showError(Bundle.ImageFilePanel_validatePanel_invalidSHA1());
665  return false;
666  }
667 
668  if (!StringUtils.isBlank(sha256) && !HashUtility.isValidSha256Hash(sha256)) {
669  showError(Bundle.ImageFilePanel_validatePanel_invalidSHA256());
670  return false;
671  }
672 
673  try {
674  TestOpenImageResult testResult = SleuthkitJNI.testOpenImage(path, password);
675  if (!testResult.wasSuccessful()) {
676  showError(Bundle.ImageFilePanel_validatePanel_imageOpenError(
677  StringUtils.defaultIfBlank(
678  testResult.getMessage(),
679  Bundle.ImageFilePanel_validatePanel_unknownErrorMsg())));
680  return false;
681  }
682  } catch (Throwable t) {
683  logger.log(Level.SEVERE, "An unknown error occurred test opening image: " + path, t);
684  showError(Bundle.ImageFilePanel_validatePanel_unknownError());
685  return false;
686  }
687 
689  showError(Bundle.ImageFilePanel_validatePanel_dataSourceOnCDriveError());
690  } else {
691  showError(null);
692  }
693  return true;
694  } finally {
695  setUIEnabled(true, validNonE01);
696  }
697  });
698  }
699 
706  private void showError(String errorMessage) {
707  loadingLabel.setVisible(false);
708  if (StringUtils.isNotBlank(errorMessage)) {
709  errorLabel.setVisible(true);
710  errorLabel.setText(errorMessage);
711  } else {
712  errorLabel.setVisible(false);
713  errorLabel.setText("");
714  }
715  }
716 
723  private boolean isImagePathValid(String path) {
724  if (StringUtils.isBlank(path) || (!(new File(path).isFile() || DriveUtils.isPhysicalDrive(path) || DriveUtils.isPartition(path)))) {
725  return false;
726  }
727 
728  return true;
729  }
730 
736  private boolean isValidNonE01(String path) {
737  return StringUtils.isNotBlank(path) && isImagePathValid(path) && !path.toLowerCase().endsWith(".e01");
738  }
739 
740  public void storeSettings() {
741  String imagePathName = getContentPaths();
742  if (null != imagePathName) {
743  String imagePath = imagePathName.substring(0, imagePathName.lastIndexOf(File.separator) + 1);
744  ModuleSettings.setConfigSetting(contextName, PROP_LASTIMAGE_PATH, imagePath);
745  }
746  }
747 
748  public void readSettings() {
749  String lastImagePath = ModuleSettings.getConfigSetting(contextName, PROP_LASTIMAGE_PATH);
750  if (StringUtils.isNotBlank(lastImagePath)) {
751  setContentPath(lastImagePath);
752  }
753  }
754 
761  @NbBundle.Messages({"ImageFilePanel.moduleErr=Module Error",
762  "ImageFilePanel.moduleErr.msg=A module caused an error listening to ImageFilePanel updates."
763  + " See log to determine which module. Some data could be incomplete.\n"})
764  private void updateHelper() {
765  String path = getContentPaths();
766  if (isValidNonE01(path)) {
767  setHashValuesComponentsEnabled(true);
768  } else {
769  setHashValuesComponentsEnabled(false);
770  }
771 
772  firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
773  }
774 
778  public void select() {
779  pathTextField.requestFocusInWindow();
780  }
781 
791  private <T> T runWithLock(ReentrantLock lock, Supplier<T> action) {
792  try {
793  lock.lock();
794  return action.get();
795  } finally {
796  lock.unlock();
797  }
798  }
799 
804  public boolean isValidationLoading() {
805  return runWithLock(this.validationWaitingLock, () -> this.validateFuture != null
806  && !this.validateFuture.isCancelled()
807  && !this.validateFuture.isDone());
808  }
809 
814  private class DelayedValidationDocListener implements DocumentListener {
815 
816  @Override
817  public void insertUpdate(DocumentEvent e) {
818  delayValidate();
819  }
820 
821  @Override
822  public void removeUpdate(DocumentEvent e) {
823  delayValidate();
824  }
825 
826  @Override
827  public void changedUpdate(DocumentEvent e) {
828  delayValidate();
829  }
830 
835  private void delayValidate() {
836 
837  boolean triggerUpdate = runWithLock(validationWaitingLock, () -> {
838 
839  boolean toRetTriggerUpdate = false;
840  if (isValidationLoading()) {
841  validateFuture.cancel(true);
842  toRetTriggerUpdate = true;
843  }
844 
845  validateAction = new ValidationRunnable();
846 
847  validateFuture = delayedValidationService.schedule(
848  validateAction,
849  VALIDATE_TIMEOUT_MILLIS,
850  TimeUnit.MILLISECONDS);
851 
852  return toRetTriggerUpdate;
853  });
854 
855  errorLabel.setVisible(false);
856  loadingLabel.setVisible(true);
857 
858  // trigger invalidation after setting up new runnable if not already triggered
859  if (triggerUpdate) {
860  firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
861  }
862  }
863 
868  private class ValidationRunnable implements Runnable {
869 
870  @Override
871  public void run() {
872 
873  boolean isRunningAction = runWithLock(validationWaitingLock, () -> {
874  if (validateAction != this) {
875  return false;
876  }
877 
878  // set the validation action to null to indicate that this is done running and can be validated.
879  validateAction = null;
880  validateFuture = null;
881 
882  return true;
883  });
884 
885  if (!isRunningAction) {
886  return;
887  } else if (Thread.interrupted()) {
888  return;
889  }
890 
892  }
893 
894  }
895  }
896 }
static synchronized String getConfigSetting(String moduleName, String settingName)
static boolean isPhysicalDrive(String path)
Definition: DriveUtils.java:43
javax.swing.JComboBox< String > sectorSizeComboBox
static synchronized ImageFilePanel createInstance(String context, List< FileFilter > fileChooserFilters)
static boolean isValidForCaseType(String path, Case.CaseType caseType)
static String createTimeZoneString(TimeZone timeZone)
void browseButtonActionPerformed(java.awt.event.ActionEvent evt)
static TestOpenImageResult testOpenImage(String imagePath, String password)
static synchronized void setConfigSetting(String moduleName, String settingName, String settingVal)
ImageFilePanel(String context, List< FileFilter > fileChooserFilters)
javax.swing.JComboBox< String > timeZoneComboBox
static boolean isValidSha256Hash(String sha256Hash)
void setUIEnabled(boolean enabled, boolean validNonE01)
static boolean isPartition(String path)
Definition: DriveUtils.java:54
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static boolean isValidSha1Hash(String sha1Hash)
static boolean isValidMd5Hash(String md5Hash)

Copyright © 2012-2024 Sleuth Kit Labs. Generated on: Mon Feb 17 2025
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.