Autopsy 4.22.1
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 */
19package org.sleuthkit.autopsy.logicalimager.configuration;
20
21import com.google.gson.Gson;
22import com.google.gson.GsonBuilder;
23import com.google.gson.JsonIOException;
24import com.google.gson.JsonSyntaxException;
25import java.io.File;
26import java.io.FileInputStream;
27import java.io.FileNotFoundException;
28import java.io.IOException;
29import java.io.InputStreamReader;
30import java.nio.charset.StandardCharsets;
31import java.nio.file.FileStore;
32import java.nio.file.FileSystem;
33import java.nio.file.FileSystems;
34import java.nio.file.Files;
35import java.nio.file.Paths;
36import java.nio.file.spi.FileSystemProvider;
37import java.util.ArrayList;
38import java.util.List;
39import java.util.logging.Level;
40import javax.swing.JFileChooser;
41import javax.swing.JOptionPane;
42import javax.swing.JPanel;
43import javax.swing.SwingUtilities;
44import javax.swing.event.DocumentEvent;
45import javax.swing.event.DocumentListener;
46import javax.swing.filechooser.FileFilter;
47import javax.swing.filechooser.FileNameExtensionFilter;
48import javax.swing.filechooser.FileSystemView;
49import org.apache.commons.lang.StringUtils;
50import org.openide.util.NbBundle;
51import org.openide.util.NbBundle.Messages;
52import org.sleuthkit.autopsy.coreutils.Logger;
53import org.sleuthkit.autopsy.guiutils.JFileChooserFactory;
54import org.sleuthkit.autopsy.logicalimager.dsp.DriveListUtils;
55
59@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
60final 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}
synchronized static Logger getLogger(String name)
Definition Logger.java:124

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