Autopsy  4.21.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
UnpackagePortableCaseProgressDialog.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
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.casemodule;
20 
21 import java.awt.Color;
22 import java.beans.PropertyChangeEvent;
23 import java.beans.PropertyChangeListener;
24 import java.io.BufferedReader;
25 import java.io.File;
26 import java.io.IOException;
27 import java.io.InputStreamReader;
28 import java.nio.file.Paths;
29 import java.util.Map;
30 import java.util.concurrent.atomic.AtomicBoolean;
31 import java.util.logging.Level;
32 import javax.swing.JFrame;
33 import javax.swing.SwingWorker;
34 import org.apache.commons.io.FilenameUtils;
35 import org.apache.commons.lang3.StringUtils;
36 import org.openide.modules.InstalledFileLocator;
37 import org.openide.util.NbBundle;
38 import org.openide.windows.WindowManager;
44 import org.sleuthkit.datamodel.TskCoreException;
45 
49 @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
50 class UnpackagePortableCaseProgressDialog extends javax.swing.JDialog implements PropertyChangeListener {
51 
52  private UnpackageWorker worker;
53  private final static String CASES_OPENED_LOG_FILE = "portable_cases_opened"; //NON-NLS
54  private final static String PORTABLE_CASE_NAME = "portable_case_name"; //NON-NLS
55  private final static String PORTABLE_CASE_DIR = "portable_case_dir_opened"; //NON-NLS
56 
60  @NbBundle.Messages({"UnpackagePortableCaseProgressDialog.title.text=Unpackage Portable Case Progress",})
61  UnpackagePortableCaseProgressDialog() {
62  super((JFrame) WindowManager.getDefault().getMainWindow(),
63  Bundle.UnpackagePortableCaseProgressDialog_title_text(),
64  true);
65  initComponents();
66  customizeComponents();
67  }
68 
69  private void customizeComponents() {
70  cancelButton.setEnabled(true);
71  okButton.setEnabled(false);
72  progressBar.setIndeterminate(true);
73  resultLabel.setText(""); // NON-NLS
74  }
75 
82  void unpackageCase(String packagedCase, String outputFolder) {
83 
84  worker = new UnpackageWorker(packagedCase, outputFolder);
85  worker.addPropertyChangeListener(this);
86  worker.execute();
87 
88  setLocationRelativeTo((JFrame) WindowManager.getDefault().getMainWindow());
89  this.setVisible(true);
90 
91  }
92 
98  boolean isSuccess() {
99  if (worker == null) {
100  return false;
101  } else {
102  return worker.isSuccess();
103  }
104  }
105 
106  @NbBundle.Messages({"UnpackagePortableCaseProgressDialog.propertyChange.success=Successfully unpacked case",})
107  @Override
108  public void propertyChange(PropertyChangeEvent evt) {
109 
110  if ("state".equals(evt.getPropertyName())
111  && (SwingWorker.StateValue.DONE.equals(evt.getNewValue()))) { // NON-NLS
112 
113  // The worker is done processing
114  // Disable cancel button and enable ok
115  cancelButton.setEnabled(false);
116  okButton.setEnabled(true);
117 
118  if (worker.isSuccess()) {
119  progressBar.setIndeterminate(false);
120  progressBar.setValue(progressBar.getMaximum());
121  resultLabel.setText(Bundle.UnpackagePortableCaseProgressDialog_propertyChange_success());
122  } else {
123  // If there was an error, reset the progress bar and display an error message
124  progressBar.setIndeterminate(false);
125  progressBar.setValue(0);
126  resultLabel.setForeground(Color.red);
127  resultLabel.setText(worker.getDisplayError());
128  }
129  }
130  }
131 
135  private class UnpackageWorker extends SwingWorker<Void, Void> {
136 
137  private final String packagedCase;
138  private final String outputFolder;
139 
140  private final AtomicBoolean success = new AtomicBoolean();
141  private String lastError = "";
142 
143  UnpackageWorker(String packagedCase, String outputFolder) {
144  this.packagedCase = packagedCase;
145  this.outputFolder = outputFolder;
146  this.success.set(false);
147  }
148 
149  @NbBundle.Messages({
150  "UnpackageWorker.doInBackground.errorFinding7zip=Could not locate 7-Zip executable",
151  "UnpackageWorker.doInBackground.errorCompressingCase=Error unpackaging case",
152  "UnpackageWorker.doInBackground.canceled=Unpackaging canceled by user",
153  "UnpackageWorker.doInBackground.previouslySeenCase=Case has been previously opened. Open it again?",})
154  @Override
155  protected Void doInBackground() throws Exception {
156 
157  // Check to see if this case has been already opened before
158  String caseUnpackedBefore = getCaseIfUnpackedBefore(packagedCase);
159  if ((!caseUnpackedBefore.isEmpty())
160  && (MessageNotifyUtil.Message.confirm(Bundle.UnpackageWorker_doInBackground_previouslySeenCase()))) {
161  try {
162  Case.openAsCurrentCase(caseUnpackedBefore);
163  success.set(true);
164  return null;
165  } catch (CaseActionException ex) {
166  throw new TskCoreException("Error opening case after unpacking it.", ex); // NON-NLS
167  }
168  }
169  // Find 7-Zip
170  File sevenZipExe = locate7ZipExecutable();
171  if (sevenZipExe == null) {
172  setDisplayError(Bundle.UnpackageWorker_doInBackground_errorFinding7zip());
173  throw new TskCoreException("Error finding 7-Zip executable"); // NON-NLS
174  }
175 
176  String outputFolderSwitch = "-o" + outputFolder; // NON-NLS
177  ProcessBuilder procBuilder = new ProcessBuilder();
178  procBuilder.command(
179  sevenZipExe.getAbsolutePath(),
180  "x", // Extract
181  packagedCase,
182  outputFolderSwitch
183  );
184 
185  try {
186  Process process = procBuilder.start();
187 
188  while (process.isAlive()) {
189  if (this.isCancelled()) {
190  setDisplayError(Bundle.UnpackageWorker_doInBackground_canceled());
191  return null;
192  }
193  Thread.sleep(200);
194  }
195 
196  int exitCode = process.exitValue();
197  if (exitCode != 0) {
198  // Save any errors so they can be logged
199  StringBuilder sb = new StringBuilder();
200  try (BufferedReader br = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
201  String line;
202  while ((line = br.readLine()) != null) {
203  sb.append(line).append(System.getProperty("line.separator")); // NON-NLS
204  }
205  }
206 
207  setDisplayError(Bundle.UnpackageWorker_doInBackground_errorCompressingCase());
208  throw new TskCoreException("Error unpackaging case. 7-Zip output: " + sb.toString()); // NON-NLS
209  }
210  } catch (IOException | InterruptedException ex) {
211  setDisplayError(Bundle.UnpackageWorker_doInBackground_errorCompressingCase());
212  throw new TskCoreException("Error unpackaging case", ex); // NON-NLS
213  }
214 
215  try {
216  String caseFileDirectory = FilenameUtils.getBaseName(packagedCase);
217  String caseDirectory = StringUtils.substringBefore(caseFileDirectory, ".zip");
218  String caseFileToOpen = outputFolder + File.separator + caseDirectory + File.separator + caseDirectory + ".aut";
219  Case.openAsCurrentCase(caseFileToOpen); // NON-NLS
220  String timestampFileOpened = TimeStampUtils.createTimeStamp();
221  if (ModuleSettings.configExists(CASES_OPENED_LOG_FILE)) {
222  ModuleSettings.setConfigSetting(CASES_OPENED_LOG_FILE, timestampFileOpened + "-" + PORTABLE_CASE_NAME, packagedCase);
223  ModuleSettings.setConfigSetting(CASES_OPENED_LOG_FILE, timestampFileOpened + "-" + PORTABLE_CASE_DIR, caseFileToOpen);
224  } else {
225  ModuleSettings.makeConfigFile(CASES_OPENED_LOG_FILE);
226  ModuleSettings.setConfigSetting(CASES_OPENED_LOG_FILE, timestampFileOpened + "-" + PORTABLE_CASE_NAME, packagedCase);
227  ModuleSettings.setConfigSetting(CASES_OPENED_LOG_FILE, timestampFileOpened + "-" + PORTABLE_CASE_DIR, caseFileToOpen);
228  }
229  } catch (CaseActionException ex) {
230  throw new TskCoreException("Error opening case after unpacking it.", ex); // NON-NLS
231  }
232 
233  success.set(true);
234 
235  return null;
236  }
237 
238  @Override
239  synchronized protected void done() {
240  if (this.isCancelled()) {
241  return;
242  }
243 
244  try {
245  get();
246  } catch (Exception ex) {
247  Logger.getLogger(UnpackagePortableCaseProgressDialog.class.getName()).log(Level.SEVERE, "Error unpackaging portable case", ex); // NON-NLS
248  }
249  }
250 
256  private synchronized void setDisplayError(String errorStr) {
257  lastError = errorStr;
258  }
259 
265  private synchronized String getDisplayError() {
266  return lastError;
267  }
268 
269  protected boolean isSuccess() {
270  return success.get();
271  }
272 
278  private File locate7ZipExecutable() {
279  if (!PlatformUtil.isWindowsOS()) {
280  return null;
281  }
282 
283  String executableToFindName = Paths.get("7-Zip", "7z.exe").toString(); // NON-NLS
284  File exeFile = InstalledFileLocator.getDefault().locate(executableToFindName, UnpackagePortableCaseProgressDialog.class.getPackage().getName(), false);
285  if (null == exeFile) {
286  return null;
287  }
288 
289  if (!exeFile.canExecute()) {
290  return null;
291  }
292 
293  return exeFile;
294  }
295 
299  private String getCaseIfUnpackedBefore(String packedCaseName) {
300  if (!ModuleSettings.configExists(CASES_OPENED_LOG_FILE)) {
301  return "";
302  }
303 
304  Map<String, String> configEntries = ModuleSettings.getConfigSettings(CASES_OPENED_LOG_FILE);
305 
306  for (Map.Entry<String, String> entries : configEntries.entrySet()) {
307  if (entries.getValue().contains(packedCaseName)) {
308  String entryFound = entries.getKey().substring(0, entries.getKey().indexOf('-'));
309  String caseFileName = ModuleSettings.getConfigSetting(CASES_OPENED_LOG_FILE, entryFound + "-" + PORTABLE_CASE_DIR);
310  File caseFile = new File(caseFileName);
311  if (caseFile.exists()) {
312  return caseFileName;
313  } else {
314  return "";
315  }
316  }
317  }
318 
319  return "";
320  }
321 
322  }
323 
329  @SuppressWarnings("unchecked")
330  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
331  private void initComponents() {
332 
333  progressBar = new javax.swing.JProgressBar();
334  cancelButton = new javax.swing.JButton();
335  okButton = new javax.swing.JButton();
336  resultLabel = new javax.swing.JLabel();
337 
338  setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
339 
340  org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(UnpackagePortableCaseProgressDialog.class, "UnpackagePortableCaseProgressDialog.cancelButton.text")); // NOI18N
341  cancelButton.addActionListener(new java.awt.event.ActionListener() {
342  public void actionPerformed(java.awt.event.ActionEvent evt) {
343  cancelButtonActionPerformed(evt);
344  }
345  });
346 
347  org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(UnpackagePortableCaseProgressDialog.class, "UnpackagePortableCaseProgressDialog.okButton.text")); // NOI18N
348  okButton.addActionListener(new java.awt.event.ActionListener() {
349  public void actionPerformed(java.awt.event.ActionEvent evt) {
350  okButtonActionPerformed(evt);
351  }
352  });
353 
354  org.openide.awt.Mnemonics.setLocalizedText(resultLabel, org.openide.util.NbBundle.getMessage(UnpackagePortableCaseProgressDialog.class, "UnpackagePortableCaseProgressDialog.resultLabel.text")); // NOI18N
355 
356  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
357  getContentPane().setLayout(layout);
358  layout.setHorizontalGroup(
359  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
360  .addGroup(layout.createSequentialGroup()
361  .addContainerGap()
362  .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
363  .addComponent(progressBar, javax.swing.GroupLayout.DEFAULT_SIZE, 409, Short.MAX_VALUE)
364  .addGroup(layout.createSequentialGroup()
365  .addComponent(resultLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
366  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
367  .addComponent(okButton, javax.swing.GroupLayout.PREFERRED_SIZE, 65, javax.swing.GroupLayout.PREFERRED_SIZE)
368  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
369  .addComponent(cancelButton)))
370  .addContainerGap())
371  );
372  layout.setVerticalGroup(
373  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
374  .addGroup(layout.createSequentialGroup()
375  .addContainerGap()
376  .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
377  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
378  .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
379  .addComponent(cancelButton)
380  .addComponent(okButton)
381  .addComponent(resultLabel))
382  .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
383  );
384 
385  pack();
386  }// </editor-fold>//GEN-END:initComponents
387 
388  private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
389  worker.cancel(true);
390  dispose();
391  }//GEN-LAST:event_cancelButtonActionPerformed
392 
393  private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
394  dispose();
395  }//GEN-LAST:event_okButtonActionPerformed
396 
397  // Variables declaration - do not modify//GEN-BEGIN:variables
398  private javax.swing.JButton cancelButton;
399  private javax.swing.JButton okButton;
400  private javax.swing.JProgressBar progressBar;
401  private javax.swing.JLabel resultLabel;
402  // End of variables declaration//GEN-END:variables
403 }
static synchronized String getConfigSetting(String moduleName, String settingName)
static synchronized boolean makeConfigFile(String moduleName)
static synchronized void setConfigSetting(String moduleName, String settingName, String settingVal)
static void openAsCurrentCase(String caseMetadataFilePath)
Definition: Case.java:852
static synchronized boolean configExists(String moduleName)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static synchronized Map< String, String > getConfigSettings(String moduleName)

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