From 7ff02fa62a1af599cd11b1a1435abb986d9f7f74 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Mon, 8 Jan 2018 13:47:24 -0500 Subject: [PATCH 1/5] Added menu item to create live triage drive --- .../autopsy/livetriage/Bundle.properties | 11 + .../CreateLiveTriageDriveAction.java | 265 +++++++++++ .../autopsy/livetriage/SelectDriveDialog.form | 180 ++++++++ .../autopsy/livetriage/SelectDriveDialog.java | 423 ++++++++++++++++++ 4 files changed, 879 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/livetriage/Bundle.properties create mode 100644 Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java create mode 100644 Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.form create mode 100644 Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.java diff --git a/Core/src/org/sleuthkit/autopsy/livetriage/Bundle.properties b/Core/src/org/sleuthkit/autopsy/livetriage/Bundle.properties new file mode 100644 index 0000000000..49fdf032cb --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/livetriage/Bundle.properties @@ -0,0 +1,11 @@ +SelectDriveDialog.bnOk.text=Ok +SelectDriveDialog.bnRefresh.text=Refresh +SelectDriveDialog.lbSelectDrive.text=Select the drive to copy the application and script to: +SelectDriveDialog.jLabel1.text=Select drive to use for live triage (may take time to load): +SelectDriveDialog.errorLabel.text=jLabel2 +SelectDriveDialog.jLabel2.text=This feature copies the application and a batch file to a removable drive, +SelectDriveDialog.jLabel3.text=allowing systems to be analyzed without installing the software or imaging +SelectDriveDialog.jLabel4.text=the drives. +SelectDriveDialog.jLabel5.text=To analyze a system, insert the drive and run "RunFromUSB.bat" as +SelectDriveDialog.jLabel6.text=administrator. +SelectDriveDialog.bnCancel.text=Cancel diff --git a/Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java b/Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java new file mode 100644 index 0000000000..531e978618 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java @@ -0,0 +1,265 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.livetriage; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.InvalidPathException; +import java.util.logging.Level; +import javax.swing.JOptionPane; +import java.awt.Frame; +import javax.swing.SwingWorker; +import org.apache.commons.io.FileUtils; +import org.netbeans.api.progress.ProgressHandle; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.awt.ActionRegistration; +import org.openide.util.HelpCtx; +import org.openide.util.NbBundle; +import org.openide.util.actions.CallableSystemAction; +import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.core.UserPreferences; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; + +@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.livetriage.CreateLiveTriageDriveAction") +@ActionReference(path = "Menu/Tools", position = 1401) +@ActionRegistration(displayName = "#CTL_CreateLiveTriageDriveAction", lazy = false) +@NbBundle.Messages({"CTL_CreateLiveTriageDriveAction=Make Live Triage Drive"}) +public final class CreateLiveTriageDriveAction extends CallableSystemAction { + + private static final String DISPLAY_NAME = Bundle.CTL_CreateLiveTriageDriveAction(); + + @Override + public boolean isEnabled() { + return true; + } + + @NbBundle.Messages({"CreateLiveTriageDriveAction.error.title=Error creating live triage disk", + "CreateLiveTriageDriveAction.exenotfound.message=Executable could not be found", + "CreateLiveTriageDriveAction.batchFileError.message=Error creating batch file", + "CreateLiveTriageDriveAction.appPathError.message=Could not location application directory", + "CreateLiveTriageDriveAction.copyError.message=Could not copy application", + "CreateLiveTriageDriveAction.success.title=Success", + "CreateLiveTriageDriveAction.success.message=Live triage drive created. Use RunFromUSB.bat to run the application" + }) + @Override + @SuppressWarnings("fallthrough") + public void performAction() { + + Frame mainWindow = WindowManager.getDefault().getMainWindow(); + + // If this is an installed version, there should be an 64.exe file in the bin folder + String appName = UserPreferences.getAppName(); + String exeName = appName + "64.exe"; + String installPath = PlatformUtil.getInstallPath(); + + Path exePath = Paths.get(installPath, "bin", exeName); + System.out.println("Exe expected at " + exePath); + + // TEMP for testing - allows this to run from Netbeans + exePath = Paths.get("C:\\Program Files\\Autopsy-4.5.0", "bin", exeName); + + if(! exePath.toFile().exists()) { + JOptionPane.showMessageDialog(mainWindow, + Bundle.CreateLiveTriageDriveAction_exenotfound_message(), + Bundle.CreateLiveTriageDriveAction_error_title(), + JOptionPane.ERROR_MESSAGE); + return; + } + + Path applicationBasePath; + try { + applicationBasePath = exePath.getParent().getParent(); + } catch (InvalidPathException ex){ + JOptionPane.showMessageDialog(mainWindow, + Bundle.CreateLiveTriageDriveAction_appPathError_message(), + Bundle.CreateLiveTriageDriveAction_error_title(), + JOptionPane.ERROR_MESSAGE); + return; + } + + SelectDriveDialog driveDialog = new SelectDriveDialog(mainWindow, true); + driveDialog.display(); + + if(! driveDialog.getSelectedDrive().isEmpty()) { + String drivePath = driveDialog.getSelectedDrive(); + if(drivePath.startsWith("\\\\.\\")){ + drivePath = drivePath.substring(4); + } + System.out.println("Destination path: " + drivePath); + + CopyFilesWorker worker = new CopyFilesWorker(applicationBasePath, drivePath, appName); + worker.execute(); + } + + } + + private class CopyFilesWorker extends SwingWorker { + + private final Path sourceFolder; + private final String drivePath; + private final String appName; + private ProgressHandle progressHandle = null; + + CopyFilesWorker(Path sourceFolder, String drivePath, String appName){ + this.sourceFolder = sourceFolder; + this.drivePath = drivePath; + this.appName = appName; + } + + @NbBundle.Messages({"# {0} - drivePath", + "CopyFilesWorker.progressBar.text=Live Triage: Copying files to {0}"}) + @Override + protected Void doInBackground() throws Exception { + // Setup progress bar. + String displayName = NbBundle.getMessage(this.getClass(), + "CopyFilesWorker.progressBar.text", + drivePath); + + // There's no way to stop FileUtils.copyDirectory, so don't include cancellation + progressHandle = ProgressHandle.createHandle(displayName); + progressHandle.start(); + progressHandle.switchToIndeterminate(); + + copyBatchFile(drivePath, appName); + copyApplication(sourceFolder, drivePath, appName); + + return null; + } + + @NbBundle.Messages({"CopyFilesWorker.title=Create Live Triage Drive", + "CopyFilesWorker.error.text=Error copying live triage files", + "CopyFilesWorker.done.text=Finished creating live triage disk"}) + @Override + protected void done() { + try { + super.get(); + + MessageNotifyUtil.Notify.info(NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.title"), + NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.done.text")); + + } catch (Exception ex) { + Logger.getLogger(CreateLiveTriageDriveAction.class.getName()).log(Level.SEVERE, "Fatal error during live triage drive creation", ex); //NON-NLS + MessageNotifyUtil.Notify.info(NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.title"), + NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.error.text")); + } finally { + if(progressHandle != null){ + progressHandle.finish(); + } + } + } + } + + private void copyApplication(Path sourceFolder, String destBaseFolder, String appName) throws IOException { + + // Create an appName folder in the destination + Path destAppFolder = Paths.get(destBaseFolder, appName); + if(! destAppFolder.toFile().exists()) { + if(! destAppFolder.toFile().mkdirs()){ + throw new IOException("Failed to create directory " + destAppFolder.toString()); + } + } + + // Now copy the files + FileUtils.copyDirectory(sourceFolder.toFile(), destAppFolder.toFile()); + } + + private void copyBatchFile(String destPath, String appName) throws IOException, InvalidPathException { + Path batchFilePath = Paths.get(destPath, "RunFromUSB.bat"); + FileUtils.writeStringToFile(batchFilePath.toFile(), getBatchFileContents(appName), "UTF-8"); + + } + + private String getBatchFileContents(String appName){ + + String batchFile = + "@echo off\n" + + "SET appName=\"" + appName + "\"\n" + + "\n" + + "REM Create the configData directory. Exit if it does not exist after attempting to create it\n" + + "if not exist configData mkdir configData\n" + + "if not exist configData (\n" + + " echo Error creating directory configData\n" + + " goto end\n" + + ")\n" + + "\n" + + "REM Create the userdir sub directory. Exit if it does not exist after attempting to create it\n" + + "if not exist configData\\userdir mkdir configData\\userdir\n" + + "if not exist configData\\userdir (\n" + + " echo Error creating directory configData\\userdir\n" + + " goto end\n" + + ")\n" + + "\n" + + "REM Create the cachedir sub directory. Exit if it does not exist after attempting to create it\n" + + "REM If it exists to start with, delete it to clear out old data\n" + + "if exist configData\\cachedir rd /s /q configData\\cachedir\n" + + "mkdir configData\\cachedir\n" + + "if not exist configData\\cachedir (\n" + + " echo Error creating directory configData\\cachedir\n" + + " goto end\n" + + ")\n" + + "\n" + + "REM Create the temp sub directory. Exit if it does not exist after attempting to create it\n" + + "REM If it exists to start with, delete it to clear out old data\n" + + "if exist configData\\temp rd /s /q configData\\temp\n" + + "mkdir configData\\temp\n" + + "if not exist configData\\temp (\n" + + " echo Error creating directory configData\\temp\n" + + " goto end\n" + + ")\n" + + "\n" + + "REM Create the cases directory. It's ok if this fails.\n" + + "if not exist cases mkdir cases\n" + + "\n" + + "if exist %appName% (\n" + + " if not exist %appName%\\bin\\%appName%64.exe (\n" + + " echo %appName%\\bin\\%appName%64.exe does not exist\n" + + " goto end\n" + + " )\n" + + " %appName%\\bin\\%appName%64.exe --userdir ..\\configData\\userdir --cachedir ..\\configData\\cachedir -J-Djava.io.tmpdir=..\\configData\\temp\n" + + ") else (\n" + + " echo Could not find %appName% directory\n" + + " goto end\n" + + ")\n" + + "\n" + + ":end\n" + + "\n" + + "REM Keep the cmd window open in case there was an error\n" + + "@pause\n"; + return batchFile; + } + + @Override + public String getName() { + return DISPLAY_NAME; + } + + @Override + public HelpCtx getHelpCtx() { + return HelpCtx.DEFAULT_HELP; + } + + @Override + public boolean asynchronous() { + return false; // run on edt + } +} diff --git a/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.form b/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.form new file mode 100644 index 0000000000..87592836f0 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.form @@ -0,0 +1,180 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.java b/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.java new file mode 100644 index 0000000000..d50d7aee2c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.java @@ -0,0 +1,423 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.livetriage; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CancellationException; +import java.util.logging.Level; +import java.awt.Dimension; +import java.awt.Point; +import javax.swing.SwingWorker; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.TableModelListener; +import javax.swing.table.TableModel; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.coreutils.LocalDisk; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; + +/** + * + */ +class SelectDriveDialog extends javax.swing.JDialog { + + private List disks = new ArrayList<>(); + private final LocalDiskModel model = new LocalDiskModel(); + private final java.awt.Frame parent; + private String drivePath = ""; + + /** + * Creates new form SelectDriveDialog + */ + @NbBundle.Messages({"SelectDriveDialog.title=Create Live Triage Drive"}) + SelectDriveDialog(java.awt.Frame parent, boolean modal) { + super(parent, modal); + initComponents(); + this.parent = parent; + + model.loadDisks(); + bnOk.setEnabled(false); + diskTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + if (diskTable.getSelectedRow() >= 0 && diskTable.getSelectedRow() < disks.size()) { + bnOk.setEnabled(true); + } else { //The selection changed to nothing valid being selected, such as with ctrl+click + bnOk.setEnabled(false); + } + } + }); + } + + void display(){ + this.setTitle(Bundle.SelectDriveDialog_title()); + + final Dimension parentSize = parent.getSize(); + final Point parentLocationOnScreen = parent.getLocationOnScreen(); + final Dimension childSize = this.getSize(); + int x; + int y; + x = (parentSize.width - childSize.width) / 2; + y = (parentSize.height - childSize.height) / 2; + x += parentLocationOnScreen.x; + y += parentLocationOnScreen.y; + + setLocation(x, y); + setVisible(true); + } + + String getSelectedDrive(){ + return this.drivePath; + } + + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jScrollPane1 = new javax.swing.JScrollPane(); + diskTable = new javax.swing.JTable(); + jLabel1 = new javax.swing.JLabel(); + bnRefresh = new javax.swing.JButton(); + bnOk = new javax.swing.JButton(); + errorLabel = new javax.swing.JLabel(); + jLabel2 = new javax.swing.JLabel(); + jLabel3 = new javax.swing.JLabel(); + jLabel4 = new javax.swing.JLabel(); + jSeparator1 = new javax.swing.JSeparator(); + jLabel5 = new javax.swing.JLabel(); + jLabel6 = new javax.swing.JLabel(); + bnCancel = new javax.swing.JButton(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + + diskTable.setModel(model); + jScrollPane1.setViewportView(diskTable); + + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.jLabel1.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(bnRefresh, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.bnRefresh.text")); // NOI18N + bnRefresh.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnRefreshActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(bnOk, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.bnOk.text")); // NOI18N + bnOk.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnOkActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.errorLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.jLabel2.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.jLabel3.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jLabel4, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.jLabel4.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jLabel5, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.jLabel5.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jLabel6, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.jLabel6.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(bnCancel, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.bnCancel.text")); // NOI18N + bnCancel.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnCancelActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(jLabel6) + .addGroup(layout.createSequentialGroup() + .addComponent(bnRefresh, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(bnOk, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(jLabel3, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jLabel2, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(jLabel4) + .addComponent(jSeparator1) + .addComponent(jLabel5, javax.swing.GroupLayout.DEFAULT_SIZE, 368, Short.MAX_VALUE) + .addComponent(errorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel2) + .addGap(1, 1, 1) + .addComponent(jLabel3) + .addGap(1, 1, 1) + .addComponent(jLabel4, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jLabel5) + .addGap(1, 1, 1) + .addComponent(jLabel6) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 112, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(bnRefresh) + .addComponent(bnCancel) + .addComponent(bnOk)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(errorLabel) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + + private void bnRefreshActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnRefreshActionPerformed + model.loadDisks(); + }//GEN-LAST:event_bnRefreshActionPerformed + + private void bnOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOkActionPerformed + if (diskTable.getSelectedRow() >= 0 && diskTable.getSelectedRow() < disks.size()) { + LocalDisk selectedDisk = disks.get(diskTable.getSelectedRow()); + drivePath = selectedDisk.getPath(); + } else { + drivePath = ""; + } + dispose(); + }//GEN-LAST:event_bnOkActionPerformed + + private void bnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnCancelActionPerformed + dispose(); + }//GEN-LAST:event_bnCancelActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton bnCancel; + private javax.swing.JButton bnOk; + private javax.swing.JButton bnRefresh; + private javax.swing.JTable diskTable; + private javax.swing.JLabel errorLabel; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + private javax.swing.JLabel jLabel3; + private javax.swing.JLabel jLabel4; + private javax.swing.JLabel jLabel5; + private javax.swing.JLabel jLabel6; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JSeparator jSeparator1; + // End of variables declaration//GEN-END:variables + + + /** + * Table model for displaying information from LocalDisk Objects in a table. + */ + @NbBundle.Messages({"SelectDriveDialog.localDiskModel.loading.msg=", + "SelectDriveDialog.localDiskModel.nodrives.msg=Executable could not be found", + "SelectDriveDialog.diskTable.column1.title=Disk Name", + "SelectDriveDialog.diskTable.column2.title=Disk Size", + "SelectDriveDialog.errLabel.disksNotDetected.text=Disks were not detected. On some systems it requires admin privileges", + "SelectDriveDialog.errLabel.disksNotDetected.toolTipText=Disks were not detected. On some systems it requires admin privileges", + "SelectDriveDialog.errLabel.drivesNotDetected.text=Local drives were not detected. Auto-detection not supported on this OS or admin privileges required", + "SelectDriveDialog.errLabel.drivesNotDetected.toolTipText=Local drives were not detected. Auto-detection not supported on this OS or admin privileges required", + "SelectDriveDialog.errLabel.someDisksNotDetected.text=Some disks were not detected. On some systems it requires admin privileges", + "SelectDriveDialog.errLabel.someDisksNotDetected.toolTipText=Some disks were not detected. On some systems it requires admin privileges" + + }) + private class LocalDiskModel implements TableModel { + + private LocalDiskThread worker = null; + private boolean ready = false; + private volatile boolean loadingDisks = false; + + //private String SELECT = "Select a local disk:"; + private final String LOADING = NbBundle.getMessage(this.getClass(), "SelectDriveDialog.localDiskModel.loading.msg"); + private final String NO_DRIVES = NbBundle.getMessage(this.getClass(), "SelectDriveDialog.localDiskModel.nodrives.msg"); + + private void loadDisks() { + + // if there is a worker already building the lists, then cancel it first. + if (loadingDisks && worker != null) { + worker.cancel(false); + } + + // Clear the lists + errorLabel.setText(""); + diskTable.setEnabled(false); + ready = false; + loadingDisks = true; + worker = new LocalDiskThread(); + worker.execute(); + } + + @Override + public int getRowCount() { + if (disks.isEmpty()) { + return 0; + } + return disks.size(); + } + + @Override + public int getColumnCount() { + return 2; + + } + + @Override + public String getColumnName(int columnIndex) { + switch (columnIndex) { + case 0: + return NbBundle.getMessage(this.getClass(), "SelectDriveDialog.diskTable.column1.title"); + case 1: + return NbBundle.getMessage(this.getClass(), "SelectDriveDialog.diskTable.column2.title"); + default: + return "Unnamed"; //NON-NLS + } + } + + @Override + public Class getColumnClass(int columnIndex) { + return String.class; + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + if (ready) { + if (disks.isEmpty()) { + return NO_DRIVES; + } + switch (columnIndex) { + case 0: + return disks.get(rowIndex).getName(); + case 1: + return disks.get(rowIndex).getReadableSize(); + default: + return disks.get(rowIndex).getPath(); + } + } else { + return LOADING; + } + } + + @Override + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + //setter does nothing they should not be able to modify table + } + + @Override + public void addTableModelListener(TableModelListener l) { + + } + + @Override + public void removeTableModelListener(TableModelListener l) { + + } + + /** + * Gets the lists of physical drives and partitions and combines them + * into a list of disks. + */ + class LocalDiskThread extends SwingWorker { + + private final Logger logger = Logger.getLogger(LocalDiskThread.class.getName()); + private List physicalDrives = new ArrayList<>(); + private List partitions = new ArrayList<>(); + + @Override + protected Object doInBackground() throws Exception { + // Populate the lists + //physicalDrives = new ArrayList<>(); + partitions = new ArrayList<>(); + //physicalDrives = PlatformUtil.getPhysicalDrives(); + partitions = PlatformUtil.getPartitions(); + return null; + } + + /** + * Display any error messages that might of occurred when getting + * the lists of physical drives or partitions. + */ + private void displayErrors() { + if (physicalDrives.isEmpty() && partitions.isEmpty()) { + if (PlatformUtil.isWindowsOS()) { + errorLabel.setText( + NbBundle.getMessage(this.getClass(), "SelectDriveDialog.errLabel.disksNotDetected.text")); + errorLabel.setToolTipText(NbBundle.getMessage(this.getClass(), + "SelectDriveDialog.errLabel.disksNotDetected.toolTipText")); + } else { + errorLabel.setText( + NbBundle.getMessage(this.getClass(), "SelectDriveDialog.errLabel.drivesNotDetected.text")); + errorLabel.setToolTipText(NbBundle.getMessage(this.getClass(), + "SelectDriveDialog.errLabel.drivesNotDetected.toolTipText")); + } + errorLabel.setVisible(true); + diskTable.setEnabled(false); + }/* else if (physicalDrives.isEmpty()) { + errorLabel.setText( + NbBundle.getMessage(this.getClass(), "SelectDriveDialog.errLabel.someDisksNotDetected.text")); + errorLabel.setToolTipText(NbBundle.getMessage(this.getClass(), + "SelectDriveDialog.errLabel.someDisksNotDetected.toolTipText")); + errorLabel.setVisible(true); + }*/ + } + + @Override + protected void done() { + try { + super.get(); //block and get all exceptions thrown while doInBackground() + } catch (CancellationException ex) { + logger.log(Level.INFO, "Loading local disks was canceled."); //NON-NLS + } catch (InterruptedException ex) { + logger.log(Level.INFO, "Loading local disks was interrupted."); //NON-NLS + } catch (Exception ex) { + logger.log(Level.SEVERE, "Fatal error when loading local disks", ex); //NON-NLS + } finally { + if (!this.isCancelled()) { + displayErrors(); + worker = null; + loadingDisks = false; + disks = new ArrayList<>(); + //disks.addAll(physicalDrives); + disks.addAll(partitions); + if (disks.size() > 0) { + diskTable.setEnabled(true); + diskTable.clearSelection(); + } + ready = true; + } + } + diskTable.revalidate(); + } + } + } +} From a055757c64dd0d2eb59474b068fdd658daf806d2 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Mon, 8 Jan 2018 13:48:35 -0500 Subject: [PATCH 2/5] Formatting --- .../CreateLiveTriageDriveAction.java | 218 +++++++++--------- .../autopsy/livetriage/SelectDriveDialog.java | 18 +- 2 files changed, 117 insertions(+), 119 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java b/Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java index 531e978618..a90993bb73 100644 --- a/Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java +++ b/Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java @@ -45,14 +45,14 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil; @ActionRegistration(displayName = "#CTL_CreateLiveTriageDriveAction", lazy = false) @NbBundle.Messages({"CTL_CreateLiveTriageDriveAction=Make Live Triage Drive"}) public final class CreateLiveTriageDriveAction extends CallableSystemAction { - + private static final String DISPLAY_NAME = Bundle.CTL_CreateLiveTriageDriveAction(); - + @Override public boolean isEnabled() { return true; } - + @NbBundle.Messages({"CreateLiveTriageDriveAction.error.title=Error creating live triage disk", "CreateLiveTriageDriveAction.exenotfound.message=Executable could not be found", "CreateLiveTriageDriveAction.batchFileError.message=Error creating batch file", @@ -64,45 +64,45 @@ public final class CreateLiveTriageDriveAction extends CallableSystemAction { @Override @SuppressWarnings("fallthrough") public void performAction() { - + Frame mainWindow = WindowManager.getDefault().getMainWindow(); - + // If this is an installed version, there should be an 64.exe file in the bin folder String appName = UserPreferences.getAppName(); String exeName = appName + "64.exe"; String installPath = PlatformUtil.getInstallPath(); - + Path exePath = Paths.get(installPath, "bin", exeName); System.out.println("Exe expected at " + exePath); - + // TEMP for testing - allows this to run from Netbeans exePath = Paths.get("C:\\Program Files\\Autopsy-4.5.0", "bin", exeName); - - if(! exePath.toFile().exists()) { + + if (!exePath.toFile().exists()) { JOptionPane.showMessageDialog(mainWindow, - Bundle.CreateLiveTriageDriveAction_exenotfound_message(), - Bundle.CreateLiveTriageDriveAction_error_title(), - JOptionPane.ERROR_MESSAGE); + Bundle.CreateLiveTriageDriveAction_exenotfound_message(), + Bundle.CreateLiveTriageDriveAction_error_title(), + JOptionPane.ERROR_MESSAGE); return; - } - + } + Path applicationBasePath; try { applicationBasePath = exePath.getParent().getParent(); - } catch (InvalidPathException ex){ + } catch (InvalidPathException ex) { JOptionPane.showMessageDialog(mainWindow, - Bundle.CreateLiveTriageDriveAction_appPathError_message(), - Bundle.CreateLiveTriageDriveAction_error_title(), - JOptionPane.ERROR_MESSAGE); + Bundle.CreateLiveTriageDriveAction_appPathError_message(), + Bundle.CreateLiveTriageDriveAction_error_title(), + JOptionPane.ERROR_MESSAGE); return; } - + SelectDriveDialog driveDialog = new SelectDriveDialog(mainWindow, true); driveDialog.display(); - - if(! driveDialog.getSelectedDrive().isEmpty()) { + + if (!driveDialog.getSelectedDrive().isEmpty()) { String drivePath = driveDialog.getSelectedDrive(); - if(drivePath.startsWith("\\\\.\\")){ + if (drivePath.startsWith("\\\\.\\")) { drivePath = drivePath.substring(4); } System.out.println("Destination path: " + drivePath); @@ -110,154 +110,154 @@ public final class CreateLiveTriageDriveAction extends CallableSystemAction { CopyFilesWorker worker = new CopyFilesWorker(applicationBasePath, drivePath, appName); worker.execute(); } - + } - + private class CopyFilesWorker extends SwingWorker { private final Path sourceFolder; private final String drivePath; private final String appName; private ProgressHandle progressHandle = null; - - CopyFilesWorker(Path sourceFolder, String drivePath, String appName){ + + CopyFilesWorker(Path sourceFolder, String drivePath, String appName) { this.sourceFolder = sourceFolder; this.drivePath = drivePath; this.appName = appName; } - + @NbBundle.Messages({"# {0} - drivePath", "CopyFilesWorker.progressBar.text=Live Triage: Copying files to {0}"}) @Override protected Void doInBackground() throws Exception { // Setup progress bar. String displayName = NbBundle.getMessage(this.getClass(), - "CopyFilesWorker.progressBar.text", - drivePath); - + "CopyFilesWorker.progressBar.text", + drivePath); + // There's no way to stop FileUtils.copyDirectory, so don't include cancellation progressHandle = ProgressHandle.createHandle(displayName); progressHandle.start(); progressHandle.switchToIndeterminate(); - + copyBatchFile(drivePath, appName); copyApplication(sourceFolder, drivePath, appName); - + return null; } - + @NbBundle.Messages({"CopyFilesWorker.title=Create Live Triage Drive", - "CopyFilesWorker.error.text=Error copying live triage files", - "CopyFilesWorker.done.text=Finished creating live triage disk"}) + "CopyFilesWorker.error.text=Error copying live triage files", + "CopyFilesWorker.done.text=Finished creating live triage disk"}) @Override protected void done() { try { super.get(); - + MessageNotifyUtil.Notify.info(NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.title"), - NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.done.text")); - + NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.done.text")); + } catch (Exception ex) { Logger.getLogger(CreateLiveTriageDriveAction.class.getName()).log(Level.SEVERE, "Fatal error during live triage drive creation", ex); //NON-NLS MessageNotifyUtil.Notify.info(NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.title"), - NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.error.text")); + NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.error.text")); } finally { - if(progressHandle != null){ + if (progressHandle != null) { progressHandle.finish(); } - } + } } } - + private void copyApplication(Path sourceFolder, String destBaseFolder, String appName) throws IOException { - + // Create an appName folder in the destination Path destAppFolder = Paths.get(destBaseFolder, appName); - if(! destAppFolder.toFile().exists()) { - if(! destAppFolder.toFile().mkdirs()){ + if (!destAppFolder.toFile().exists()) { + if (!destAppFolder.toFile().mkdirs()) { throw new IOException("Failed to create directory " + destAppFolder.toString()); } } - + // Now copy the files FileUtils.copyDirectory(sourceFolder.toFile(), destAppFolder.toFile()); } - + private void copyBatchFile(String destPath, String appName) throws IOException, InvalidPathException { Path batchFilePath = Paths.get(destPath, "RunFromUSB.bat"); FileUtils.writeStringToFile(batchFilePath.toFile(), getBatchFileContents(appName), "UTF-8"); - + } - - private String getBatchFileContents(String appName){ - - String batchFile = - "@echo off\n" + - "SET appName=\"" + appName + "\"\n" + - "\n" + - "REM Create the configData directory. Exit if it does not exist after attempting to create it\n" + - "if not exist configData mkdir configData\n" + - "if not exist configData (\n" + - " echo Error creating directory configData\n" + - " goto end\n" + - ")\n" + - "\n" + - "REM Create the userdir sub directory. Exit if it does not exist after attempting to create it\n" + - "if not exist configData\\userdir mkdir configData\\userdir\n" + - "if not exist configData\\userdir (\n" + - " echo Error creating directory configData\\userdir\n" + - " goto end\n" + - ")\n" + - "\n" + - "REM Create the cachedir sub directory. Exit if it does not exist after attempting to create it\n" + - "REM If it exists to start with, delete it to clear out old data\n" + - "if exist configData\\cachedir rd /s /q configData\\cachedir\n" + - "mkdir configData\\cachedir\n" + - "if not exist configData\\cachedir (\n" + - " echo Error creating directory configData\\cachedir\n" + - " goto end\n" + - ")\n" + - "\n" + - "REM Create the temp sub directory. Exit if it does not exist after attempting to create it\n" + - "REM If it exists to start with, delete it to clear out old data\n" + - "if exist configData\\temp rd /s /q configData\\temp\n" + - "mkdir configData\\temp\n" + - "if not exist configData\\temp (\n" + - " echo Error creating directory configData\\temp\n" + - " goto end\n" + - ")\n" + - "\n" + - "REM Create the cases directory. It's ok if this fails.\n" + - "if not exist cases mkdir cases\n" + - "\n" + - "if exist %appName% (\n" + - " if not exist %appName%\\bin\\%appName%64.exe (\n" + - " echo %appName%\\bin\\%appName%64.exe does not exist\n" + - " goto end\n" + - " )\n" + - " %appName%\\bin\\%appName%64.exe --userdir ..\\configData\\userdir --cachedir ..\\configData\\cachedir -J-Djava.io.tmpdir=..\\configData\\temp\n" + - ") else (\n" + - " echo Could not find %appName% directory\n" + - " goto end\n" + - ")\n" + - "\n" + - ":end\n" + - "\n" + - "REM Keep the cmd window open in case there was an error\n" + - "@pause\n"; - return batchFile; + + private String getBatchFileContents(String appName) { + + String batchFile + = "@echo off\n" + + "SET appName=\"" + appName + "\"\n" + + "\n" + + "REM Create the configData directory. Exit if it does not exist after attempting to create it\n" + + "if not exist configData mkdir configData\n" + + "if not exist configData (\n" + + " echo Error creating directory configData\n" + + " goto end\n" + + ")\n" + + "\n" + + "REM Create the userdir sub directory. Exit if it does not exist after attempting to create it\n" + + "if not exist configData\\userdir mkdir configData\\userdir\n" + + "if not exist configData\\userdir (\n" + + " echo Error creating directory configData\\userdir\n" + + " goto end\n" + + ")\n" + + "\n" + + "REM Create the cachedir sub directory. Exit if it does not exist after attempting to create it\n" + + "REM If it exists to start with, delete it to clear out old data\n" + + "if exist configData\\cachedir rd /s /q configData\\cachedir\n" + + "mkdir configData\\cachedir\n" + + "if not exist configData\\cachedir (\n" + + " echo Error creating directory configData\\cachedir\n" + + " goto end\n" + + ")\n" + + "\n" + + "REM Create the temp sub directory. Exit if it does not exist after attempting to create it\n" + + "REM If it exists to start with, delete it to clear out old data\n" + + "if exist configData\\temp rd /s /q configData\\temp\n" + + "mkdir configData\\temp\n" + + "if not exist configData\\temp (\n" + + " echo Error creating directory configData\\temp\n" + + " goto end\n" + + ")\n" + + "\n" + + "REM Create the cases directory. It's ok if this fails.\n" + + "if not exist cases mkdir cases\n" + + "\n" + + "if exist %appName% (\n" + + " if not exist %appName%\\bin\\%appName%64.exe (\n" + + " echo %appName%\\bin\\%appName%64.exe does not exist\n" + + " goto end\n" + + " )\n" + + " %appName%\\bin\\%appName%64.exe --userdir ..\\configData\\userdir --cachedir ..\\configData\\cachedir -J-Djava.io.tmpdir=..\\configData\\temp\n" + + ") else (\n" + + " echo Could not find %appName% directory\n" + + " goto end\n" + + ")\n" + + "\n" + + ":end\n" + + "\n" + + "REM Keep the cmd window open in case there was an error\n" + + "@pause\n"; + return batchFile; } - + @Override public String getName() { return DISPLAY_NAME; } - + @Override public HelpCtx getHelpCtx() { return HelpCtx.DEFAULT_HELP; } - + @Override public boolean asynchronous() { return false; // run on edt diff --git a/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.java b/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.java index d50d7aee2c..1ca506d323 100644 --- a/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.java +++ b/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.java @@ -30,7 +30,7 @@ class SelectDriveDialog extends javax.swing.JDialog { private final LocalDiskModel model = new LocalDiskModel(); private final java.awt.Frame parent; private String drivePath = ""; - + /** * Creates new form SelectDriveDialog */ @@ -39,7 +39,7 @@ class SelectDriveDialog extends javax.swing.JDialog { super(parent, modal); initComponents(); this.parent = parent; - + model.loadDisks(); bnOk.setEnabled(false); diskTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { @@ -53,10 +53,10 @@ class SelectDriveDialog extends javax.swing.JDialog { } }); } - - void display(){ + + void display() { this.setTitle(Bundle.SelectDriveDialog_title()); - + final Dimension parentSize = parent.getSize(); final Point parentLocationOnScreen = parent.getLocationOnScreen(); final Dimension childSize = this.getSize(); @@ -70,12 +70,11 @@ class SelectDriveDialog extends javax.swing.JDialog { setLocation(x, y); setVisible(true); } - - String getSelectedDrive(){ + + String getSelectedDrive() { return this.drivePath; } - /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -231,7 +230,6 @@ class SelectDriveDialog extends javax.swing.JDialog { private javax.swing.JSeparator jSeparator1; // End of variables declaration//GEN-END:variables - /** * Table model for displaying information from LocalDisk Objects in a table. */ @@ -245,7 +243,7 @@ class SelectDriveDialog extends javax.swing.JDialog { "SelectDriveDialog.errLabel.drivesNotDetected.toolTipText=Local drives were not detected. Auto-detection not supported on this OS or admin privileges required", "SelectDriveDialog.errLabel.someDisksNotDetected.text=Some disks were not detected. On some systems it requires admin privileges", "SelectDriveDialog.errLabel.someDisksNotDetected.toolTipText=Some disks were not detected. On some systems it requires admin privileges" - + }) private class LocalDiskModel implements TableModel { From 00e68c44aa6e14bb80d237068a98c0e7cd35246f Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Tue, 9 Jan 2018 09:44:27 -0500 Subject: [PATCH 3/5] Add fix to restore directory when running as admin --- .../autopsy/livetriage/CreateLiveTriageDriveAction.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java b/Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java index a90993bb73..5f10b4f9df 100644 --- a/Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java +++ b/Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java @@ -73,10 +73,6 @@ public final class CreateLiveTriageDriveAction extends CallableSystemAction { String installPath = PlatformUtil.getInstallPath(); Path exePath = Paths.get(installPath, "bin", exeName); - System.out.println("Exe expected at " + exePath); - - // TEMP for testing - allows this to run from Netbeans - exePath = Paths.get("C:\\Program Files\\Autopsy-4.5.0", "bin", exeName); if (!exePath.toFile().exists()) { JOptionPane.showMessageDialog(mainWindow, @@ -193,6 +189,11 @@ public final class CreateLiveTriageDriveAction extends CallableSystemAction { String batchFile = "@echo off\n" + + "\n" + + "REM This restores the working directory when using 'Run as administrator'" + + "@setlocal enableextensions\n" + + "@cd /d \"%~dp0\"" + + "\n" + "SET appName=\"" + appName + "\"\n" + "\n" + "REM Create the configData directory. Exit if it does not exist after attempting to create it\n" From 43d32eb1c809377eb1aa05f966d5ad47ebc5b432 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Wed, 10 Jan 2018 09:31:24 -0500 Subject: [PATCH 4/5] Changed progress bar --- .../autopsy/livetriage/Bundle.properties | 6 +- .../CreateLiveTriageDriveAction.java | 86 ++++++++++------- .../autopsy/livetriage/SelectDriveDialog.form | 93 ++++++++----------- .../autopsy/livetriage/SelectDriveDialog.java | 79 +++++----------- 4 files changed, 114 insertions(+), 150 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/livetriage/Bundle.properties b/Core/src/org/sleuthkit/autopsy/livetriage/Bundle.properties index 49fdf032cb..61f522a6b4 100644 --- a/Core/src/org/sleuthkit/autopsy/livetriage/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/livetriage/Bundle.properties @@ -3,9 +3,5 @@ SelectDriveDialog.bnRefresh.text=Refresh SelectDriveDialog.lbSelectDrive.text=Select the drive to copy the application and script to: SelectDriveDialog.jLabel1.text=Select drive to use for live triage (may take time to load): SelectDriveDialog.errorLabel.text=jLabel2 -SelectDriveDialog.jLabel2.text=This feature copies the application and a batch file to a removable drive, -SelectDriveDialog.jLabel3.text=allowing systems to be analyzed without installing the software or imaging -SelectDriveDialog.jLabel4.text=the drives. -SelectDriveDialog.jLabel5.text=To analyze a system, insert the drive and run "RunFromUSB.bat" as -SelectDriveDialog.jLabel6.text=administrator. SelectDriveDialog.bnCancel.text=Cancel +SelectDriveDialog.jTextArea1.text=This feature copies the application and a batch file to a removable drive,\nallowing systems to be analyzed without installing the software or\nimaging the drives.\n\nTo analyze a system, insert the drive and run "RunFromUSB.bat" as\nadministrator, then select the "Local Disk" option on the Add Data Source\npanel. diff --git a/Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java b/Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java index 5f10b4f9df..1c54ee633b 100644 --- a/Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java +++ b/Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java @@ -23,11 +23,12 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.InvalidPathException; import java.util.logging.Level; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeEvent; import javax.swing.JOptionPane; import java.awt.Frame; import javax.swing.SwingWorker; import org.apache.commons.io.FileUtils; -import org.netbeans.api.progress.ProgressHandle; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; import org.openide.awt.ActionRegistration; @@ -39,14 +40,18 @@ import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.sleuthkit.autopsy.progress.ModalDialogProgressIndicator; @ActionID(category = "Tools", id = "org.sleuthkit.autopsy.livetriage.CreateLiveTriageDriveAction") @ActionReference(path = "Menu/Tools", position = 1401) @ActionRegistration(displayName = "#CTL_CreateLiveTriageDriveAction", lazy = false) @NbBundle.Messages({"CTL_CreateLiveTriageDriveAction=Make Live Triage Drive"}) -public final class CreateLiveTriageDriveAction extends CallableSystemAction { +public final class CreateLiveTriageDriveAction extends CallableSystemAction implements PropertyChangeListener { private static final String DISPLAY_NAME = Bundle.CTL_CreateLiveTriageDriveAction(); + private ModalDialogProgressIndicator progressIndicator = null; + private String drivePath = ""; + private CopyFilesWorker worker; @Override public boolean isEnabled() { @@ -57,7 +62,7 @@ public final class CreateLiveTriageDriveAction extends CallableSystemAction { "CreateLiveTriageDriveAction.exenotfound.message=Executable could not be found", "CreateLiveTriageDriveAction.batchFileError.message=Error creating batch file", "CreateLiveTriageDriveAction.appPathError.message=Could not location application directory", - "CreateLiveTriageDriveAction.copyError.message=Could not copy application", + "CreateLiveTriageDriveAction.copyError.message=Could not copy application. Only works on installed version.", "CreateLiveTriageDriveAction.success.title=Success", "CreateLiveTriageDriveAction.success.message=Live triage drive created. Use RunFromUSB.bat to run the application" }) @@ -97,16 +102,46 @@ public final class CreateLiveTriageDriveAction extends CallableSystemAction { driveDialog.display(); if (!driveDialog.getSelectedDrive().isEmpty()) { - String drivePath = driveDialog.getSelectedDrive(); + drivePath = driveDialog.getSelectedDrive(); if (drivePath.startsWith("\\\\.\\")) { drivePath = drivePath.substring(4); } - System.out.println("Destination path: " + drivePath); - - CopyFilesWorker worker = new CopyFilesWorker(applicationBasePath, drivePath, appName); + + worker = new CopyFilesWorker(applicationBasePath, drivePath, appName); + worker.addPropertyChangeListener(this); worker.execute(); } - + } + + @NbBundle.Messages({"# {0} - drivePath", + "CreateLiveTriageDriveAction.progressBar.text=Copying live triage files to {0}", + "CreateLiveTriageDriveAction.progressBar.title=Please wait"}) + @Override + public void propertyChange(PropertyChangeEvent evt) { + + if ("state".equals(evt.getPropertyName()) + && (SwingWorker.StateValue.STARTED.equals(evt.getNewValue()))) { + + // Setup progress bar. + String displayStr = NbBundle.getMessage(this.getClass(), "CreateLiveTriageDriveAction.progressBar.text", + drivePath); + + progressIndicator = new ModalDialogProgressIndicator(WindowManager.getDefault().getMainWindow(), + NbBundle.getMessage(this.getClass(), "CreateLiveTriageDriveAction.progressBar.title")); + progressIndicator.start(displayStr); + + } else if ("state".equals(evt.getPropertyName()) + && (SwingWorker.StateValue.DONE.equals(evt.getNewValue()))) { + if(progressIndicator != null){ + progressIndicator.finish(); + } + + if(worker.hadError()){ + MessageNotifyUtil.Message.error(NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.error.text")); + } else { + MessageNotifyUtil.Message.info(NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.done.text")); + } + } } private class CopyFilesWorker extends SwingWorker { @@ -114,27 +149,20 @@ public final class CreateLiveTriageDriveAction extends CallableSystemAction { private final Path sourceFolder; private final String drivePath; private final String appName; - private ProgressHandle progressHandle = null; + private boolean error = false; CopyFilesWorker(Path sourceFolder, String drivePath, String appName) { this.sourceFolder = sourceFolder; this.drivePath = drivePath; this.appName = appName; } - - @NbBundle.Messages({"# {0} - drivePath", - "CopyFilesWorker.progressBar.text=Live Triage: Copying files to {0}"}) + + boolean hadError(){ + return error; + } + @Override protected Void doInBackground() throws Exception { - // Setup progress bar. - String displayName = NbBundle.getMessage(this.getClass(), - "CopyFilesWorker.progressBar.text", - drivePath); - - // There's no way to stop FileUtils.copyDirectory, so don't include cancellation - progressHandle = ProgressHandle.createHandle(displayName); - progressHandle.start(); - progressHandle.switchToIndeterminate(); copyBatchFile(drivePath, appName); copyApplication(sourceFolder, drivePath, appName); @@ -142,25 +170,15 @@ public final class CreateLiveTriageDriveAction extends CallableSystemAction { return null; } - @NbBundle.Messages({"CopyFilesWorker.title=Create Live Triage Drive", - "CopyFilesWorker.error.text=Error copying live triage files", + @NbBundle.Messages({"CopyFilesWorker.error.text=Error copying live triage files", "CopyFilesWorker.done.text=Finished creating live triage disk"}) @Override protected void done() { try { super.get(); - - MessageNotifyUtil.Notify.info(NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.title"), - NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.done.text")); - } catch (Exception ex) { - Logger.getLogger(CreateLiveTriageDriveAction.class.getName()).log(Level.SEVERE, "Fatal error during live triage drive creation", ex); //NON-NLS - MessageNotifyUtil.Notify.info(NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.title"), - NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.error.text")); - } finally { - if (progressHandle != null) { - progressHandle.finish(); - } + error = true; + Logger.getLogger(CreateLiveTriageDriveAction.class.getName()).log(Level.SEVERE, "Fatal error during live triage drive creation", ex); //NON-NLS } } } diff --git a/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.form b/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.form index 87592836f0..ee776348dc 100644 --- a/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.form +++ b/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.form @@ -23,27 +23,21 @@ - + - - - + + - - - - - - + @@ -53,16 +47,8 @@ - - - - - - - - - - + + @@ -129,43 +115,8 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -176,5 +127,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.java b/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.java index 1ca506d323..c13d82d324 100644 --- a/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.java +++ b/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.java @@ -90,13 +90,10 @@ class SelectDriveDialog extends javax.swing.JDialog { bnRefresh = new javax.swing.JButton(); bnOk = new javax.swing.JButton(); errorLabel = new javax.swing.JLabel(); - jLabel2 = new javax.swing.JLabel(); - jLabel3 = new javax.swing.JLabel(); - jLabel4 = new javax.swing.JLabel(); jSeparator1 = new javax.swing.JSeparator(); - jLabel5 = new javax.swing.JLabel(); - jLabel6 = new javax.swing.JLabel(); bnCancel = new javax.swing.JButton(); + jScrollPane2 = new javax.swing.JScrollPane(); + jTextArea1 = new javax.swing.JTextArea(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); @@ -121,16 +118,6 @@ class SelectDriveDialog extends javax.swing.JDialog { org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.errorLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.jLabel2.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.jLabel3.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(jLabel4, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.jLabel4.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(jLabel5, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.jLabel5.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(jLabel6, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.jLabel6.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(bnCancel, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.bnCancel.text")); // NOI18N bnCancel.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -138,6 +125,16 @@ class SelectDriveDialog extends javax.swing.JDialog { } }); + jScrollPane2.setBorder(null); + + jTextArea1.setBackground(new java.awt.Color(240, 240, 240)); + jTextArea1.setColumns(20); + jTextArea1.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N + jTextArea1.setRows(5); + jTextArea1.setText(org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.jTextArea1.text")); // NOI18N + jTextArea1.setBorder(null); + jScrollPane2.setViewportView(jTextArea1); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( @@ -145,38 +142,25 @@ class SelectDriveDialog extends javax.swing.JDialog { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(jLabel6) .addGroup(layout.createSequentialGroup() - .addComponent(bnRefresh, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(bnRefresh, javax.swing.GroupLayout.DEFAULT_SIZE, 112, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 48, Short.MAX_VALUE) .addComponent(bnOk, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(bnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addComponent(jLabel3, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jLabel2, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addComponent(jLabel4) .addComponent(jSeparator1) - .addComponent(jLabel5, javax.swing.GroupLayout.DEFAULT_SIZE, 368, Short.MAX_VALUE) - .addComponent(errorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(errorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jScrollPane2)) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addComponent(jLabel2) - .addGap(1, 1, 1) - .addComponent(jLabel3) - .addGap(1, 1, 1) - .addComponent(jLabel4, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jLabel5) - .addGap(1, 1, 1) - .addComponent(jLabel6) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 107, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jLabel1) @@ -221,13 +205,10 @@ class SelectDriveDialog extends javax.swing.JDialog { private javax.swing.JTable diskTable; private javax.swing.JLabel errorLabel; private javax.swing.JLabel jLabel1; - private javax.swing.JLabel jLabel2; - private javax.swing.JLabel jLabel3; - private javax.swing.JLabel jLabel4; - private javax.swing.JLabel jLabel5; - private javax.swing.JLabel jLabel6; private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JScrollPane jScrollPane2; private javax.swing.JSeparator jSeparator1; + private javax.swing.JTextArea jTextArea1; // End of variables declaration//GEN-END:variables /** @@ -238,11 +219,7 @@ class SelectDriveDialog extends javax.swing.JDialog { "SelectDriveDialog.diskTable.column1.title=Disk Name", "SelectDriveDialog.diskTable.column2.title=Disk Size", "SelectDriveDialog.errLabel.disksNotDetected.text=Disks were not detected. On some systems it requires admin privileges", - "SelectDriveDialog.errLabel.disksNotDetected.toolTipText=Disks were not detected. On some systems it requires admin privileges", - "SelectDriveDialog.errLabel.drivesNotDetected.text=Local drives were not detected. Auto-detection not supported on this OS or admin privileges required", - "SelectDriveDialog.errLabel.drivesNotDetected.toolTipText=Local drives were not detected. Auto-detection not supported on this OS or admin privileges required", - "SelectDriveDialog.errLabel.someDisksNotDetected.text=Some disks were not detected. On some systems it requires admin privileges", - "SelectDriveDialog.errLabel.someDisksNotDetected.toolTipText=Some disks were not detected. On some systems it requires admin privileges" + "SelectDriveDialog.errLabel.disksNotDetected.toolTipText=Disks were not detected." }) private class LocalDiskModel implements TableModel { @@ -348,15 +325,12 @@ class SelectDriveDialog extends javax.swing.JDialog { class LocalDiskThread extends SwingWorker { private final Logger logger = Logger.getLogger(LocalDiskThread.class.getName()); - private List physicalDrives = new ArrayList<>(); private List partitions = new ArrayList<>(); @Override protected Object doInBackground() throws Exception { // Populate the lists - //physicalDrives = new ArrayList<>(); partitions = new ArrayList<>(); - //physicalDrives = PlatformUtil.getPhysicalDrives(); partitions = PlatformUtil.getPartitions(); return null; } @@ -366,7 +340,7 @@ class SelectDriveDialog extends javax.swing.JDialog { * the lists of physical drives or partitions. */ private void displayErrors() { - if (physicalDrives.isEmpty() && partitions.isEmpty()) { + if (partitions.isEmpty()) { if (PlatformUtil.isWindowsOS()) { errorLabel.setText( NbBundle.getMessage(this.getClass(), "SelectDriveDialog.errLabel.disksNotDetected.text")); @@ -380,13 +354,7 @@ class SelectDriveDialog extends javax.swing.JDialog { } errorLabel.setVisible(true); diskTable.setEnabled(false); - }/* else if (physicalDrives.isEmpty()) { - errorLabel.setText( - NbBundle.getMessage(this.getClass(), "SelectDriveDialog.errLabel.someDisksNotDetected.text")); - errorLabel.setToolTipText(NbBundle.getMessage(this.getClass(), - "SelectDriveDialog.errLabel.someDisksNotDetected.toolTipText")); - errorLabel.setVisible(true); - }*/ + } } @Override @@ -405,7 +373,6 @@ class SelectDriveDialog extends javax.swing.JDialog { worker = null; loadingDisks = false; disks = new ArrayList<>(); - //disks.addAll(physicalDrives); disks.addAll(partitions); if (disks.size() > 0) { diskTable.setEnabled(true); From 6c973af0b6e1e163b03b8d59275fee063763d6c6 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Wed, 10 Jan 2018 09:31:58 -0500 Subject: [PATCH 5/5] Formatting --- .../CreateLiveTriageDriveAction.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java b/Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java index 1c54ee633b..846632a092 100644 --- a/Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java +++ b/Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java @@ -106,40 +106,40 @@ public final class CreateLiveTriageDriveAction extends CallableSystemAction impl if (drivePath.startsWith("\\\\.\\")) { drivePath = drivePath.substring(4); } - + worker = new CopyFilesWorker(applicationBasePath, drivePath, appName); worker.addPropertyChangeListener(this); worker.execute(); } } - + @NbBundle.Messages({"# {0} - drivePath", - "CreateLiveTriageDriveAction.progressBar.text=Copying live triage files to {0}", - "CreateLiveTriageDriveAction.progressBar.title=Please wait"}) + "CreateLiveTriageDriveAction.progressBar.text=Copying live triage files to {0}", + "CreateLiveTriageDriveAction.progressBar.title=Please wait"}) @Override public void propertyChange(PropertyChangeEvent evt) { - + if ("state".equals(evt.getPropertyName()) - && (SwingWorker.StateValue.STARTED.equals(evt.getNewValue()))) { - + && (SwingWorker.StateValue.STARTED.equals(evt.getNewValue()))) { + // Setup progress bar. String displayStr = NbBundle.getMessage(this.getClass(), "CreateLiveTriageDriveAction.progressBar.text", drivePath); - + progressIndicator = new ModalDialogProgressIndicator(WindowManager.getDefault().getMainWindow(), NbBundle.getMessage(this.getClass(), "CreateLiveTriageDriveAction.progressBar.title")); progressIndicator.start(displayStr); - + } else if ("state".equals(evt.getPropertyName()) - && (SwingWorker.StateValue.DONE.equals(evt.getNewValue()))) { - if(progressIndicator != null){ + && (SwingWorker.StateValue.DONE.equals(evt.getNewValue()))) { + if (progressIndicator != null) { progressIndicator.finish(); } - - if(worker.hadError()){ + + if (worker.hadError()) { MessageNotifyUtil.Message.error(NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.error.text")); } else { - MessageNotifyUtil.Message.info(NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.done.text")); + MessageNotifyUtil.Message.info(NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.done.text")); } } } @@ -156,11 +156,11 @@ public final class CreateLiveTriageDriveAction extends CallableSystemAction impl this.drivePath = drivePath; this.appName = appName; } - - boolean hadError(){ + + boolean hadError() { return error; } - + @Override protected Void doInBackground() throws Exception {