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

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