Autopsy  4.12.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
ConfigVisualPanel1.java
Go to the documentation of this file.
1 /*
2  * Autopsy
3  *
4  * Copyright 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.logicalimager.configuration;
20 
21 import com.google.gson.Gson;
22 import com.google.gson.GsonBuilder;
23 import com.google.gson.JsonIOException;
24 import com.google.gson.JsonSyntaxException;
25 import java.io.File;
26 import java.io.FileInputStream;
27 import java.io.FileNotFoundException;
28 import java.io.IOException;
29 import java.io.InputStreamReader;
30 import java.nio.charset.StandardCharsets;
31 import java.nio.file.FileStore;
32 import java.nio.file.FileSystem;
33 import java.nio.file.FileSystems;
34 import java.nio.file.Files;
35 import java.nio.file.Paths;
36 import java.nio.file.spi.FileSystemProvider;
37 import java.util.ArrayList;
38 import java.util.List;
39 import java.util.logging.Level;
40 import javax.swing.JFileChooser;
41 import javax.swing.JOptionPane;
42 import javax.swing.JPanel;
43 import javax.swing.SwingUtilities;
44 import javax.swing.event.DocumentEvent;
45 import javax.swing.event.DocumentListener;
46 import javax.swing.filechooser.FileFilter;
47 import javax.swing.filechooser.FileNameExtensionFilter;
48 import javax.swing.filechooser.FileSystemView;
49 import org.apache.commons.lang.StringUtils;
50 import org.openide.util.NbBundle;
51 import org.openide.util.NbBundle.Messages;
54 
58 @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
59 final class ConfigVisualPanel1 extends JPanel {
60 
61  private static final Logger logger = Logger.getLogger(ConfigVisualPanel1.class.getName());
62  private static final long serialVersionUID = 1L;
63  private static final String DEFAULT_CONFIG_FILE_NAME = "logical-imager-config.json";
64  private static final String UPDATE_UI_EVENT_NAME = "UPDATE_UI";
65  private String configFilename;
66 
70  ConfigVisualPanel1() {
71  initComponents();
72  configFileTextField.getDocument().addDocumentListener(new MyDocumentListener(this));
73  refreshDriveList();
74  SwingUtilities.invokeLater(() -> {
75  updateControls();
76  });
77  }
78 
79  @NbBundle.Messages({
80  "ConfigVisualPanel1.selectConfigurationFile=Select location"
81  })
82  @Override
83  public String getName() {
84  return Bundle.ConfigVisualPanel1_selectConfigurationFile();
85  }
86 
92  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
93  private void initComponents() {
94 
95  configurationLocationButtonGroup = new javax.swing.ButtonGroup();
96  configFileTextField = new javax.swing.JTextField();
97  browseButton = new javax.swing.JButton();
98  descriptionScrollPane = new javax.swing.JScrollPane();
99  descriptionTextArea = new javax.swing.JTextArea();
100  configureDriveRadioButton = new javax.swing.JRadioButton();
101  configureFolderRadioButton = new javax.swing.JRadioButton();
102  driveListScrollPane = new javax.swing.JScrollPane();
103  driveList = new javax.swing.JList<>();
104  refreshButton = new javax.swing.JButton();
105  warningLabel = new javax.swing.JLabel();
106 
107  configFileTextField.setEditable(false);
108  configFileTextField.setEnabled(false);
109 
110  org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(ConfigVisualPanel1.class, "ConfigVisualPanel1.browseButton.text")); // NOI18N
111  browseButton.setToolTipText(org.openide.util.NbBundle.getMessage(ConfigVisualPanel1.class, "ConfigVisualPanel1.browseButton.toolTipText")); // NOI18N
112  browseButton.setEnabled(false);
113  browseButton.addActionListener(new java.awt.event.ActionListener() {
114  public void actionPerformed(java.awt.event.ActionEvent evt) {
115  browseButtonActionPerformed(evt);
116  }
117  });
118 
119  descriptionTextArea.setEditable(false);
120  descriptionTextArea.setBackground(new java.awt.Color(240, 240, 240));
121  descriptionTextArea.setColumns(20);
122  descriptionTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N
123  descriptionTextArea.setLineWrap(true);
124  descriptionTextArea.setRows(4);
125  descriptionTextArea.setText(org.openide.util.NbBundle.getMessage(ConfigVisualPanel1.class, "ConfigVisualPanel1.descriptionTextArea.text")); // NOI18N
126  descriptionTextArea.setWrapStyleWord(true);
127  descriptionTextArea.setEnabled(false);
128  descriptionScrollPane.setViewportView(descriptionTextArea);
129 
130  configurationLocationButtonGroup.add(configureDriveRadioButton);
131  configureDriveRadioButton.setSelected(true);
132  org.openide.awt.Mnemonics.setLocalizedText(configureDriveRadioButton, org.openide.util.NbBundle.getMessage(ConfigVisualPanel1.class, "ConfigVisualPanel1.configureDriveRadioButton.text_1")); // NOI18N
133  configureDriveRadioButton.addActionListener(new java.awt.event.ActionListener() {
134  public void actionPerformed(java.awt.event.ActionEvent evt) {
135  configureDriveRadioButtonActionPerformed(evt);
136  }
137  });
138 
139  configurationLocationButtonGroup.add(configureFolderRadioButton);
140  org.openide.awt.Mnemonics.setLocalizedText(configureFolderRadioButton, org.openide.util.NbBundle.getMessage(ConfigVisualPanel1.class, "ConfigVisualPanel1.configureFolderRadioButton.text_1")); // NOI18N
141  configureFolderRadioButton.addActionListener(new java.awt.event.ActionListener() {
142  public void actionPerformed(java.awt.event.ActionEvent evt) {
143  configureFolderRadioButtonActionPerformed(evt);
144  }
145  });
146 
147  driveList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
148  driveList.setEnabled(false);
149  driveList.addMouseListener(new java.awt.event.MouseAdapter() {
150  public void mouseReleased(java.awt.event.MouseEvent evt) {
151  driveListMouseReleasedSelection(evt);
152  }
153  });
154  driveList.addKeyListener(new java.awt.event.KeyAdapter() {
155  public void keyReleased(java.awt.event.KeyEvent evt) {
156  driveListKeyReleasedSelection(evt);
157  }
158  });
159  driveListScrollPane.setViewportView(driveList);
160 
161  org.openide.awt.Mnemonics.setLocalizedText(refreshButton, org.openide.util.NbBundle.getMessage(ConfigVisualPanel1.class, "ConfigVisualPanel1.refreshButton.text")); // NOI18N
162  refreshButton.setEnabled(false);
163  refreshButton.addActionListener(new java.awt.event.ActionListener() {
164  public void actionPerformed(java.awt.event.ActionEvent evt) {
165  refreshButtonActionPerformed(evt);
166  }
167  });
168 
169  warningLabel.setForeground(new java.awt.Color(255, 0, 0));
170 
171  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
172  this.setLayout(layout);
173  layout.setHorizontalGroup(
174  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
175  .addGroup(layout.createSequentialGroup()
176  .addContainerGap()
177  .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
178  .addComponent(warningLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
179  .addComponent(descriptionScrollPane)
180  .addGroup(layout.createSequentialGroup()
181  .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
182  .addGroup(layout.createSequentialGroup()
183  .addGap(21, 21, 21)
184  .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
185  .addComponent(driveListScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 437, javax.swing.GroupLayout.PREFERRED_SIZE)
186  .addComponent(configFileTextField, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 437, javax.swing.GroupLayout.PREFERRED_SIZE))
187  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
188  .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
189  .addComponent(refreshButton, javax.swing.GroupLayout.PREFERRED_SIZE, 87, javax.swing.GroupLayout.PREFERRED_SIZE)
190  .addComponent(browseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 87, javax.swing.GroupLayout.PREFERRED_SIZE)))
191  .addComponent(configureDriveRadioButton)
192  .addComponent(configureFolderRadioButton))
193  .addGap(0, 0, Short.MAX_VALUE)))
194  .addContainerGap())
195  );
196  layout.setVerticalGroup(
197  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
198  .addGroup(layout.createSequentialGroup()
199  .addContainerGap()
200  .addComponent(descriptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
201  .addGap(13, 13, 13)
202  .addComponent(configureDriveRadioButton)
203  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
204  .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
205  .addComponent(driveListScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
206  .addGroup(layout.createSequentialGroup()
207  .addComponent(refreshButton)
208  .addGap(0, 95, Short.MAX_VALUE)))
209  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
210  .addComponent(configureFolderRadioButton)
211  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
212  .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
213  .addComponent(configFileTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
214  .addComponent(browseButton))
215  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
216  .addComponent(warningLabel)
217  .addContainerGap(60, Short.MAX_VALUE))
218  );
219  }// </editor-fold>//GEN-END:initComponents
220 
221  @NbBundle.Messages({
222  "ConfigVisualPanel1.chooseFileTitle=Select a Logical Imager configuration"
223  })
224  private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
225  chooseFile(Bundle.ConfigVisualPanel1_chooseFileTitle());
226  }//GEN-LAST:event_browseButtonActionPerformed
227 
228  private void configureFolderRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_configureFolderRadioButtonActionPerformed
229  updateControls();
230  }//GEN-LAST:event_configureFolderRadioButtonActionPerformed
231 
232  private void configureDriveRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_configureDriveRadioButtonActionPerformed
233  updateControls();
234  }//GEN-LAST:event_configureDriveRadioButtonActionPerformed
235 
236  private void refreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshButtonActionPerformed
237  refreshDriveList();
238  }//GEN-LAST:event_refreshButtonActionPerformed
239 
240  private void driveListKeyReleasedSelection(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_driveListKeyReleasedSelection
241  firePropertyChange(UPDATE_UI_EVENT_NAME, false, true); // NON-NLS
242  }//GEN-LAST:event_driveListKeyReleasedSelection
243 
244  private void driveListMouseReleasedSelection(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_driveListMouseReleasedSelection
245  firePropertyChange(UPDATE_UI_EVENT_NAME, false, true); // NON-NLS
246  }//GEN-LAST:event_driveListMouseReleasedSelection
247 
248  /*
249  * Return the Windows file system name of the drive
250  * @param drive File system drive, should be of the form "C:\"
251  *
252  */
253  @Messages({"ConfigVisualPanel1.unknown=Unknown"})
254  private String getFileSystemName(String drive) {
255  FileSystem fileSystem = FileSystems.getDefault();
256  FileSystemProvider provider = fileSystem.provider();
257  try {
258  FileStore fileStore = provider.getFileStore(Paths.get(drive));
259  return fileStore.type();
260  } catch (IOException ex) {
261  return Bundle.ConfigVisualPanel1_unknown();
262  }
263  }
264 
268  @NbBundle.Messages({
269  "ConfigVisualPanel1.messageLabel.noExternalDriveFound=No drive found",
270  "# {0} - root", "# {1} - description", "# {2} - size with unit", "# {3} - file system",
271  "ConfigVisualPanel1.driveListItem={0} ({1}) ({2}) - File system: {3}"
272  })
273  private void refreshDriveList() {
274  List<String> listData = new ArrayList<>();
275  File[] roots = File.listRoots();
276  int firstRemovableDrive = -1;
277  int i = 0;
278  for (File root : roots) {
279  if (DriveListUtils.isNetworkDrive(root.toString().replace(":\\", ""))) {
280  continue;
281  }
282  String description = FileSystemView.getFileSystemView().getSystemTypeDescription(root);
283  long spaceInBytes = root.getTotalSpace();
284  String sizeWithUnit = DriveListUtils.humanReadableByteCount(spaceInBytes, false);
285  String fileSystem = getFileSystemName(root.toString());
286  listData.add(Bundle.ConfigVisualPanel1_driveListItem(root, description, sizeWithUnit, fileSystem));
287  if (firstRemovableDrive == -1) {
288  try {
289  FileStore fileStore = Files.getFileStore(root.toPath());
290  if ((boolean) fileStore.getAttribute("volume:isRemovable")) { //NON-NLS
291  firstRemovableDrive = i;
292  }
293  } catch (IOException ignored) {
294  //unable to get this removable drive for default selection will try and select next removable drive by default
295  logger.log(Level.INFO, String.format("Unable to select first removable drive found %s", root.toString())); // NON-NLS
296  }
297  }
298  i++;
299  }
300  driveList.setListData(listData.toArray(new String[listData.size()]));
301  if (!listData.isEmpty()) {
302  // auto-select the first external drive, if any
303  driveList.setSelectedIndex(firstRemovableDrive == -1 ? 0 : firstRemovableDrive);
304  firePropertyChange(UPDATE_UI_EVENT_NAME, false, true); // NON-NLS
305  driveList.requestFocusInWindow();
306  warningLabel.setText("");
307  } else {
308  warningLabel.setText(Bundle.ConfigVisualPanel1_messageLabel_noExternalDriveFound());
309  }
310  }
311 
316  private void updateControls() {
317  browseButton.setEnabled(configureFolderRadioButton.isSelected());
318  refreshButton.setEnabled(configureDriveRadioButton.isSelected());
319  driveList.setEnabled(configureDriveRadioButton.isSelected());
320  driveListScrollPane.setEnabled(configureDriveRadioButton.isSelected());
321  firePropertyChange(UPDATE_UI_EVENT_NAME, false, true); // NON-NLS
322  }
323 
330  @NbBundle.Messages({
331  "ConfigVisualPanel1.fileNameExtensionFilter=Configuration JSON File",
332  "ConfigVisualPanel1.invalidConfigJson=Invalid config JSON: ",
333  "ConfigVisualPanel1.configurationError=Configuration error",})
334  private void chooseFile(String title) {
335  final String jsonExt = ".json"; // NON-NLS
336  JFileChooser fileChooser = new JFileChooser();
337  fileChooser.setDialogTitle(title);
338  fileChooser.setDragEnabled(false);
339  fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
340  FileFilter filter = new FileNameExtensionFilter(Bundle.ConfigVisualPanel1_fileNameExtensionFilter(), new String[]{"json"}); // NON-NLS
341  fileChooser.setFileFilter(filter);
342  fileChooser.setSelectedFile(new File(DEFAULT_CONFIG_FILE_NAME)); // default
343  fileChooser.setMultiSelectionEnabled(false);
344  if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
345  String path = fileChooser.getSelectedFile().getPath();
346  if (new File(path).exists()) {
347  try {
348  loadConfigFile(path);
349  configFilename = path;
350  configFileTextField.setText(path);
351  } catch (JsonIOException | JsonSyntaxException | IOException ex) {
352  JOptionPane.showMessageDialog(this,
353  Bundle.ConfigVisualPanel1_invalidConfigJson() + ex.getMessage(),
354  Bundle.ConfigVisualPanel1_configurationError(),
355  JOptionPane.ERROR_MESSAGE);
356  }
357  } else {
358  if (!path.endsWith(jsonExt)) {
359  path += jsonExt;
360  }
361  configFilename = path;
362  configFileTextField.setText(path);
363  }
364  }
365  }
366 
367  // Variables declaration - do not modify//GEN-BEGIN:variables
368  private javax.swing.JButton browseButton;
369  private javax.swing.JTextField configFileTextField;
370  private javax.swing.ButtonGroup configurationLocationButtonGroup;
371  private javax.swing.JRadioButton configureDriveRadioButton;
372  private javax.swing.JRadioButton configureFolderRadioButton;
373  private javax.swing.JScrollPane descriptionScrollPane;
374  private javax.swing.JTextArea descriptionTextArea;
375  private javax.swing.JList<String> driveList;
376  private javax.swing.JScrollPane driveListScrollPane;
377  private javax.swing.JButton refreshButton;
378  private javax.swing.JLabel warningLabel;
379  // End of variables declaration//GEN-END:variables
380 
395  @NbBundle.Messages({
396  "# {0} - filename",
397  "ConfigVisualPanel1.configFileIsEmpty=Configuration file {0} is empty",})
398  private LogicalImagerConfig loadConfigFile(String path) throws FileNotFoundException, JsonIOException, JsonSyntaxException, IOException {
399  try (FileInputStream is = new FileInputStream(path)) {
400  InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8);
401  GsonBuilder gsonBuilder = new GsonBuilder().setPrettyPrinting();
402  gsonBuilder.registerTypeAdapter(LogicalImagerConfig.class, new LogicalImagerConfigDeserializer());
403  Gson gson = gsonBuilder.create();
404  LogicalImagerConfig loadedConfig = gson.fromJson(reader, LogicalImagerConfig.class);
405  if (loadedConfig == null) {
406  // This happens if the file is empty. Gson doesn't call the deserializer and doesn't throw any exception.
407  throw new IOException(Bundle.ConfigVisualPanel1_configFileIsEmpty(path));
408  }
409  return loadedConfig;
410  }
411  }
412 
419  LogicalImagerConfig getConfig() {
420  String configFileName = getConfigPath();
421  if (configFileName != null && new File(configFileName).exists()) {
422  try {
423  return loadConfigFile(configFileName);
424  } catch (JsonIOException | JsonSyntaxException | IOException ex) {
425  return new LogicalImagerConfig();
426  }
427  } else {
428  return new LogicalImagerConfig();
429  }
430  }
431 
438  String getConfigPath() {
439  if (configureFolderRadioButton.isSelected()) {
440  return configFilename;
441  } else {
442  String selectedStr = driveList.getSelectedValue();
443  if (selectedStr == null) {
444  return null;
445  }
446  return selectedStr.substring(0, 3) + DEFAULT_CONFIG_FILE_NAME;
447  }
448  }
449 
456  static String getUpdateEventName() {
457  return UPDATE_UI_EVENT_NAME;
458  }
459 
460  void setConfigFilename(String filename) {
461  configFileTextField.setText(filename);
462  }
463 
469  boolean isPanelValid() {
470  return !StringUtils.isBlank(getConfigPath())
471  && !(getFileSystemName(getConfigPath().substring(0, 3)).equals("FAT") // NON-NLS
472  || getFileSystemName(getConfigPath().substring(0, 3)).equals("FAT32")) // NON-NLS
473  && ((configureDriveRadioButton.isSelected() && !StringUtils.isBlank(driveList.getSelectedValue()))
474  || (configureFolderRadioButton.isSelected() && (!configFileTextField.getText().isEmpty())));
475  }
476 
480  private static class MyDocumentListener implements DocumentListener {
481 
482  private final ConfigVisualPanel1 panel;
483 
484  MyDocumentListener(ConfigVisualPanel1 aThis) {
485  this.panel = aThis;
486  }
487 
488  @Override
489  public void insertUpdate(DocumentEvent e) {
490  fireChange();
491  }
492 
493  @Override
494  public void removeUpdate(DocumentEvent e) {
495  fireChange();
496  }
497 
498  @Override
499  public void changedUpdate(DocumentEvent e) {
500  fireChange();
501  }
502 
503  private void fireChange() {
504  panel.firePropertyChange(UPDATE_UI_EVENT_NAME, false, true); // NON-NLS
505  }
506  }
507 
508 }
static boolean isNetworkDrive(String driveLetter)
static String humanReadableByteCount(long bytes, boolean si)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124

Copyright © 2012-2018 Basis Technology. Generated on: Wed Sep 18 2019
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.