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

Copyright © 2012-2022 Basis Technology. Generated on: Tue Aug 1 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.