From bf3e68fc53dfe31fb5e2c6055c6c573e1ed7a1de Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 18 Oct 2017 16:06:30 -0400 Subject: [PATCH 001/115] Removed examiner mode. --- .../AutoIngestCasePanelInterface.java | 29 -- .../autopsy/casemodule/Bundle.properties | 32 +- .../autopsy/casemodule/Bundle_ja.properties | 9 +- .../autopsy/casemodule/CaseOpenAction.java | 2 +- .../casemodule/CaseOpenMultiUserAction.java | 124 ++++++ .../autopsy/casemodule/CueBannerPanel.form | 20 +- .../autopsy/casemodule/CueBannerPanel.java | 89 ++--- .../autopsy/casemodule/MultiUserCase.java | 53 ++- .../casemodule/MultiUserCaseManager.java | 132 +++++++ .../casemodule/MultiUserCasePanel.form | 20 +- .../casemodule/MultiUserCasePanel.java | 359 ++++++------------ .../actions/EamEditCaseInfoAction.java | 2 +- Core/src/org/sleuthkit/autopsy/core/layer.xml | 8 +- .../CaseStatusIconCellRenderer.java | 11 +- .../coreutils}/GrayableCellRenderer.java | 8 +- .../coreutils}/LongDateCellRenderer.java | 6 +- .../autopsy/coreutils}/TimeStampUtils.java | 2 +- .../autoingest/AutoIngestCaseManager.java | 162 -------- .../autoingest/AutoIngestCaseOpenAction.java | 21 +- .../autoingest/AutoIngestControlPanel.java | 2 + .../autoingest/AutoIngestDashboard.java | 2 + .../AutoIngestDashboardOpenAction.java | 3 +- .../experimental/autoingest/Bundle.properties | 22 +- .../CenteredGrayableCellRenderer.java | 1 + .../autoingest/DurationCellRenderer.java | 24 ++ .../experimental/autoingest/PathUtils.java | 1 + .../autoingest/ShortDateCellRenderer.java | 24 ++ .../autoingest/SingleUserCaseImporter.java | 1 + .../configuration/Bundle.properties | 29 +- 29 files changed, 594 insertions(+), 604 deletions(-) delete mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/AutoIngestCasePanelInterface.java create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java rename Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCase.java => Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java (74%) create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java rename Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.form => Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasePanel.form (84%) rename Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java => Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasePanel.java (67%) rename {Experimental/src/org/sleuthkit/autopsy/experimental/autoingest => Core/src/org/sleuthkit/autopsy/coreutils}/CaseStatusIconCellRenderer.java (82%) rename {Experimental/src/org/sleuthkit/autopsy/experimental/autoingest => Core/src/org/sleuthkit/autopsy/coreutils}/GrayableCellRenderer.java (91%) rename {Experimental/src/org/sleuthkit/autopsy/experimental/autoingest => Core/src/org/sleuthkit/autopsy/coreutils}/LongDateCellRenderer.java (91%) rename {Experimental/src/org/sleuthkit/autopsy/experimental/autoingest => Core/src/org/sleuthkit/autopsy/coreutils}/TimeStampUtils.java (98%) delete mode 100755 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseManager.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AutoIngestCasePanelInterface.java b/Core/src/org/sleuthkit/autopsy/casemodule/AutoIngestCasePanelInterface.java deleted file mode 100755 index 795b636b35..0000000000 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AutoIngestCasePanelInterface.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2017 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.casemodule; - -import javax.swing.JDialog; - -/** - * Interface for startup window implementations - */ -public interface AutoIngestCasePanelInterface { - - public void addWindowStateListener(JDialog parent); -} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 1fc2209750..6ce0c76f3d 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -1,10 +1,10 @@ -CTL_AddImage=Add Data Source... +CTL_AddImage=Add Data Source CTL_AddImageButton=Add Data Source CTL_CaseCloseAct=Close Case -CTL_CaseNewAction=New Case... -CTL_CasePropertiesAction=Case Properties... +CTL_CaseNewAction=New Case +CTL_CasePropertiesAction=Case Properties CTL_CaseDeleteAction=Delete Case -CTL_OpenAction=Open Case... +CTL_CaseOpenAction=Open Case Menu/Case/OpenRecentCase=Open Recent Case CTL_CaseDeleteAction=Delete Case OpenIDE-Module-Name=Case @@ -219,11 +219,31 @@ CasePropertiesPanel.lbDbType.text=Case Type: CasePropertiesPanel.examinerLabel.text=Examiner: CasePropertiesPanel.caseNumberLabel.text=Case Number: LocalDiskPanel.changeDatabasePathCheckbox.text=Update case to use VHD file upon completion -CueBannerPanel.openAutoIngestCaseButton.text= +CueBannerPanel.openMultiUserCaseButton.text= CueBannerPanel.openExistingCaseButton.text= CueBannerPanel.openRecentCaseButton.text= CueBannerPanel.createNewCaseButton.text= CueBannerPanel.createNewCaseLabel.text=Create New Case CueBannerPanel.openRecentCaseLabel.text=Open Recent Case CueBannerPanel.openExistingCaseLabel.text=Open Existing Case -CueBannerPanel.openAutoIngestCaseLabel.text=Open Auto Ingest Case +CueBannerPanel.openMultiUserCaseLabel.text=Open Multi-User Case +ReviewModeCasePanel.cannotOpenCase=Cannot Open Case +ReviewModeCasePanel.casePathNotFound=Case path not found +ReviewModeCasePanel.caseIsLocked=Single-user case is locked. +ReviewModeCasePanel.CaseHeaderText=Case +ReviewModeCasePanel.CreatedTimeHeaderText=Created Time +ReviewModeCasePanel.StatusIconHeaderText=Status +ReviewModeCasePanel.OutputFolderHeaderText=Output Folder +ReviewModeCasePanel.LastAccessedTimeHeaderText=Last Accessed Time +MultiUserCasePanel.rbDays.text=Days +MultiUserCasePanel.rbWeeks.text=Weeks +MultiUserCasePanel.rbMonths.text=Months +MultiUserCasePanel.rbAllCases.text=Everything +MultiUserCasePanel.bnRefresh.text=&Refresh +MultiUserCasePanel.bnOpen.text=&Open +MultiUserCasePanel.bnShowLog.toolTipText=Display case log file for selected case +MultiUserCasePanel.bnShowLog.text=&Show Auto Ingest Case Log +MultiUserCasePanel.rbGroupLabel.text=Show cases accessed in the last 10: +OpenMultiUserCasePanel.jLabel1.text=Recent Cases +OpenMultiUserCasePanel.openButton.text=Open +OpenMultiUserCasePanel.cancelButton.text=Cancel diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties index fd00f725e5..3b2b380ffc 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties @@ -1,9 +1,9 @@ CTL_AddImageButton=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u3092\u8ffd\u52a0 CTL_CaseCloseAct=\u30b1\u30fc\u30b9\u3092\u9589\u3058\u308b -CTL_CaseNewAction=\u65b0\u898f\u30b1\u30fc\u30b9... -CTL_CasePropertiesAction=\u30b1\u30fc\u30b9\u30d7\u30ed\u30d1\u30c6\u30a3... +CTL_CaseNewAction=\u65b0\u898f\u30b1\u30fc\u30b9 +CTL_CasePropertiesAction=\u30b1\u30fc\u30b9\u30d7\u30ed\u30d1\u30c6\u30a3 CTL_CaseDeleteAction=\u30b1\u30fc\u30b9\u3092\u524a\u9664 -CTL_OpenAction=\u30b1\u30fc\u30b9\u3092\u958b\u304f... +CTL_CaseOpenAction=\u30b1\u30fc\u30b9\u3092\u958b\u304f Menu/Case/OpenRecentCase=\u6700\u8fd1\u958b\u3044\u305f\u30b1\u30fc\u30b9\u3092\u958b\u304f CTL_CaseDeleteAction=\u30b1\u30fc\u30b9\u3092\u524a\u9664 OpenIDE-Module-Name=\u30b1\u30fc\u30b9 @@ -197,3 +197,6 @@ CueBannerPanel.createNewCaseLabel.text=\u65b0\u898f\u30b1\u30fc\u30b9\u3092\u4f5 CueBannerPanel.openRecentCaseLabel.text=\u6700\u8fd1\u958b\u3044\u305f\u30b1\u30fc\u30b9\u3092\u958b\u304f CueBannerPanel.openExistingCaseLabel.text=\u65e2\u5b58\u30b1\u30fc\u30b9\u3092\u958b\u304f CueBannerPanel.openAutoIngestCaseLabel.text=\u65e2\u5b58\u30b1\u30fc\u30b9\u3092\u958b\u304f +OpenMultiUserCasePanel.openButton.text=\u958b\u304f +OpenMultiUserCasePanel.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb +OpenMultiUserCasePanel.jLabel1.text=\u6700\u8fd1\u958b\u3044\u305f\u30d5\u30a1\u30a4\u30eb diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java index 533cab58c5..e4ed92d897 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java @@ -141,7 +141,7 @@ public final class CaseOpenAction extends CallableSystemAction implements Action @Override public String getName() { - return NbBundle.getMessage(CaseOpenAction.class, "CTL_OpenAction"); + return NbBundle.getMessage(CaseOpenAction.class, "CTL_CaseOpenAction"); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java new file mode 100755 index 0000000000..aa9b0eac6a --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java @@ -0,0 +1,124 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.casemodule; + +import java.awt.Dialog; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.KeyStroke; +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.util.lookup.ServiceProvider; +import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.core.UserPreferences; +import static org.sleuthkit.autopsy.core.UserPreferences.SelectedMode.REVIEW; +import org.sleuthkit.autopsy.coreutils.NetworkUtils; + +/** + * The action associated with the Case/Open Case menu item via the layer.xml + * file, a toolbar button, and the Create New Case button of the start up window + * that allows a user to open a case. It opens an existing case. + * + * This action should only be invoked in the event dispatch thread (EDT). + */ +@ActionID(category = "Case", id = "org.sleuthkit.autopsy.casemodule.CaseOpenMultiUserAction") +@ActionReference(path = "Menu/Case", position = 102) +@ActionRegistration(displayName = "#CTL_CaseOpenMultiUserAction", lazy = false) +@NbBundle.Messages({"CTL_CaseOpenMultiUserAction=Open Multi-User Case"}) +public final class CaseOpenMultiUserAction extends CallableSystemAction implements ActionListener { + + private static final long serialVersionUID = 1L; + private static JDialog multiUserCaseWindow; + + private static final String DISPLAY_NAME = Bundle.CTL_CaseOpenMultiUserAction(); + private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName(); + private static final String REVIEW_MODE_TITLE = "Open Multi-User Case (" + LOCAL_HOST_NAME + ")"; + + /** + * Constructs the action associated with the Case/Open Case menu item via + * the layer.xml file, a toolbar button, and the Create New Case button of + * the start up window that allows a user to open a case. It opens an + * existing case. + * + */ + public CaseOpenMultiUserAction() { + multiUserCaseWindow = new JDialog( + WindowManager.getDefault().getMainWindow(), + REVIEW_MODE_TITLE, + Dialog.ModalityType.APPLICATION_MODAL); + multiUserCaseWindow.getRootPane().registerKeyboardAction( + e -> { + multiUserCaseWindow.setVisible(false); + }, + KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); + multiUserCaseWindow.add(new MultiUserCasePanel()); + multiUserCaseWindow.pack(); + multiUserCaseWindow.setResizable(false); + } + + public static void closeMultiUserCasesWindow() { + if (null != multiUserCaseWindow) { + multiUserCaseWindow.setVisible(false); + } + } + + @Override + public boolean isEnabled() { + return UserPreferences.getIsMultiUserModeEnabled(); + } + + /** + * Pops up a file chooser to allow the user to select a case metadata file + * (.aut file) and attempts to open the case described by the file. + * + * @param e The action event. + */ + @Override + public void actionPerformed(ActionEvent event) { + multiUserCaseWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); + multiUserCaseWindow.setVisible(true); + } + + @Override + public void performAction() { + actionPerformed(null); + } + + @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/casemodule/CueBannerPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.form index 75819e41d0..0d6525db8b 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.form @@ -28,14 +28,14 @@ - + - + @@ -66,9 +66,9 @@ - + - + @@ -216,13 +216,13 @@ - + - + @@ -237,18 +237,18 @@ - + - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java index 2d7b17458e..48e54a3f9f 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java @@ -26,12 +26,10 @@ import java.awt.event.KeyEvent; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JDialog; -import javax.swing.JPanel; import javax.swing.KeyStroke; import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.casemodule.AutoIngestCasePanelInterface; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.NetworkUtils; @@ -42,13 +40,13 @@ public class CueBannerPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName(); - private static final String REVIEW_MODE_TITLE = "Cases" + " (" + LOCAL_HOST_NAME + ")"; + private static final String REVIEW_MODE_TITLE = "Open Multi-User Case (" + LOCAL_HOST_NAME + ")"; /* * This is field is static for the sake of the closeOpenRecentCasesWindow * method. */ private static JDialog recentCasesWindow; - private static JDialog autoIngestCasePanelWindow; + private static JDialog multiUserCaseWindow; public static void closeOpenRecentCasesWindow() { if (null != recentCasesWindow) { @@ -56,9 +54,9 @@ public class CueBannerPanel extends javax.swing.JPanel { } } - public static void closeAutoIngestCasesWindow() { - if (null != autoIngestCasePanelWindow) { - autoIngestCasePanelWindow.setVisible(false); + public static void closeMultiUserCasesWindow() { + if (null != multiUserCaseWindow) { + multiUserCaseWindow.setVisible(false); } } @@ -93,7 +91,7 @@ public class CueBannerPanel extends javax.swing.JPanel { private void customizeComponents() { initRecentCasesWindow(); - initAutoIngestCasesWindow(); + initMultiUserCasesWindow(); } private void initRecentCasesWindow() { @@ -119,28 +117,19 @@ public class CueBannerPanel extends javax.swing.JPanel { recentCasesWindow.setResizable(false); } - private void initAutoIngestCasesWindow() { - autoIngestCasePanelWindow = new JDialog( + private void initMultiUserCasesWindow() { + multiUserCaseWindow = new JDialog( WindowManager.getDefault().getMainWindow(), REVIEW_MODE_TITLE, Dialog.ModalityType.APPLICATION_MODAL); - autoIngestCasePanelWindow.getRootPane().registerKeyboardAction( + multiUserCaseWindow.getRootPane().registerKeyboardAction( e -> { - autoIngestCasePanelWindow.setVisible(false); + multiUserCaseWindow.setVisible(false); }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); - OpenRecentCasePanel recentCasesPanel = OpenRecentCasePanel.getInstance(); - recentCasesPanel.setCloseButtonActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - autoIngestCasePanelWindow.setVisible(false); - } - }); - AutoIngestCasePanelInterface autoIngestCasePanel = Lookup.getDefault().lookup(AutoIngestCasePanelInterface.class); - autoIngestCasePanel.addWindowStateListener(autoIngestCasePanelWindow); - autoIngestCasePanelWindow.add((JPanel)autoIngestCasePanel); - autoIngestCasePanelWindow.pack(); - autoIngestCasePanelWindow.setResizable(false); + multiUserCaseWindow.add(new MultiUserCasePanel()); + multiUserCaseWindow.pack(); + multiUserCaseWindow.setResizable(false); } private void enableComponents() { @@ -148,9 +137,9 @@ public class CueBannerPanel extends javax.swing.JPanel { openRecentCaseButton.setEnabled(enableOpenRecentCaseButton); openRecentCaseLabel.setEnabled(enableOpenRecentCaseButton); - boolean showOpenAutoIngestCaseButton = (UserPreferences.getMode() == UserPreferences.SelectedMode.REVIEW); - openAutoIngestCaseButton.setVisible(showOpenAutoIngestCaseButton); - openAutoIngestCaseLabel.setVisible(showOpenAutoIngestCaseButton); + boolean enableOpenMultiUserCaseButton = UserPreferences.getIsMultiUserModeEnabled(); + openMultiUserCaseButton.setEnabled(enableOpenMultiUserCaseButton); + openMultiUserCaseLabel.setEnabled(enableOpenMultiUserCaseButton); } /** @@ -172,8 +161,8 @@ public class CueBannerPanel extends javax.swing.JPanel { openExistingCaseLabel = new javax.swing.JLabel(); closeButton = new javax.swing.JButton(); jSeparator1 = new javax.swing.JSeparator(); - openAutoIngestCaseButton = new javax.swing.JButton(); - openAutoIngestCaseLabel = new javax.swing.JLabel(); + openMultiUserCaseButton = new javax.swing.JButton(); + openMultiUserCaseLabel = new javax.swing.JLabel(); autopsyLogo.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/welcome_logo.png"))); // NOI18N autopsyLogo.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.autopsyLogo.text")); // NOI18N @@ -229,21 +218,21 @@ public class CueBannerPanel extends javax.swing.JPanel { jSeparator1.setOrientation(javax.swing.SwingConstants.VERTICAL); - openAutoIngestCaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/btn_icon_open_existing.png"))); // NOI18N - openAutoIngestCaseButton.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openAutoIngestCaseButton.text")); // NOI18N - openAutoIngestCaseButton.setBorder(null); - openAutoIngestCaseButton.setBorderPainted(false); - openAutoIngestCaseButton.setContentAreaFilled(false); - openAutoIngestCaseButton.setMargin(new java.awt.Insets(1, 1, 1, 1)); - openAutoIngestCaseButton.setPreferredSize(new java.awt.Dimension(64, 64)); - openAutoIngestCaseButton.addActionListener(new java.awt.event.ActionListener() { + openMultiUserCaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/btn_icon_open_existing.png"))); // NOI18N + openMultiUserCaseButton.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openMultiUserCaseButton.text")); // NOI18N + openMultiUserCaseButton.setBorder(null); + openMultiUserCaseButton.setBorderPainted(false); + openMultiUserCaseButton.setContentAreaFilled(false); + openMultiUserCaseButton.setMargin(new java.awt.Insets(1, 1, 1, 1)); + openMultiUserCaseButton.setPreferredSize(new java.awt.Dimension(64, 64)); + openMultiUserCaseButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - openAutoIngestCaseButtonActionPerformed(evt); + openMultiUserCaseButtonActionPerformed(evt); } }); - openAutoIngestCaseLabel.setFont(openAutoIngestCaseLabel.getFont().deriveFont(openAutoIngestCaseLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 13)); - openAutoIngestCaseLabel.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openAutoIngestCaseLabel.text")); // NOI18N + openMultiUserCaseLabel.setFont(openMultiUserCaseLabel.getFont().deriveFont(openMultiUserCaseLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 13)); + openMultiUserCaseLabel.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openMultiUserCaseLabel.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -261,13 +250,13 @@ public class CueBannerPanel extends javax.swing.JPanel { .addComponent(createNewCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(openRecentCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(openExistingCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(openAutoIngestCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(openMultiUserCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(createNewCaseLabel) .addComponent(openRecentCaseLabel) .addComponent(openExistingCaseLabel) - .addComponent(openAutoIngestCaseLabel))) + .addComponent(openMultiUserCaseLabel))) .addComponent(closeButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 73, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap()) ); @@ -290,9 +279,9 @@ public class CueBannerPanel extends javax.swing.JPanel { .addComponent(openExistingCaseLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(openAutoIngestCaseButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 58, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(openMultiUserCaseButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 58, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(openAutoIngestCaseLabel) + .addComponent(openMultiUserCaseLabel) .addGap(20, 20, 20)))) .addComponent(jSeparator1) .addComponent(autopsyLogo, javax.swing.GroupLayout.PREFERRED_SIZE, 257, javax.swing.GroupLayout.PREFERRED_SIZE)) @@ -316,10 +305,10 @@ public class CueBannerPanel extends javax.swing.JPanel { recentCasesWindow.setVisible(true); }//GEN-LAST:event_openRecentCaseButtonActionPerformed - private void openAutoIngestCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openAutoIngestCaseButtonActionPerformed - autoIngestCasePanelWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); - autoIngestCasePanelWindow.setVisible(true); - }//GEN-LAST:event_openAutoIngestCaseButtonActionPerformed + private void openMultiUserCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openMultiUserCaseButtonActionPerformed + multiUserCaseWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); + multiUserCaseWindow.setVisible(true); + }//GEN-LAST:event_openMultiUserCaseButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel autopsyLogo; @@ -327,8 +316,8 @@ public class CueBannerPanel extends javax.swing.JPanel { private javax.swing.JButton createNewCaseButton; private javax.swing.JLabel createNewCaseLabel; private javax.swing.JSeparator jSeparator1; - private javax.swing.JButton openAutoIngestCaseButton; - private javax.swing.JLabel openAutoIngestCaseLabel; + private javax.swing.JButton openMultiUserCaseButton; + private javax.swing.JLabel openMultiUserCaseLabel; private javax.swing.JButton openExistingCaseButton; private javax.swing.JLabel openExistingCaseLabel; private javax.swing.JButton openRecentCaseButton; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCase.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java similarity index 74% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCase.java rename to Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java index ff47423030..d1a2bc65da 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCase.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.casemodule; import java.io.IOException; import java.nio.file.Files; @@ -28,13 +28,14 @@ import java.util.Objects; import java.util.logging.Level; import org.sleuthkit.autopsy.casemodule.CaseMetadata; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.TimeStampUtils; /** * A representation of a case created by automated ingest. */ -class AutoIngestCase implements Comparable { +class MultiUserCase implements Comparable { - private static final Logger logger = Logger.getLogger(AutoIngestCase.class.getName()); + private static final Logger logger = Logger.getLogger(MultiUserCase.class.getName()); private final Path caseDirectoryPath; private final String caseName; private final Path metadataFilePath; @@ -46,9 +47,9 @@ class AutoIngestCase implements Comparable { * * @param caseDirectoryPath The case directory path. */ - AutoIngestCase(Path caseDirectoryPath) { + MultiUserCase(Path caseDirectoryPath) { this.caseDirectoryPath = caseDirectoryPath; - caseName = PathUtils.caseNameFromCaseDirectoryPath(caseDirectoryPath); + caseName = getCaseNameFromCaseDirectoryPath(caseDirectoryPath); metadataFilePath = caseDirectoryPath.resolve(caseName + CaseMetadata.getFileExtension()); BasicFileAttributes fileAttrs = null; try { @@ -110,16 +111,32 @@ class AutoIngestCase implements Comparable { * @return See CaseStatus enum definition. */ CaseStatus getStatus() { - if (AutoIngestAlertFile.exists(caseDirectoryPath)) { + if(caseDirectoryPath.resolve("autoingest.alert").toFile().exists()) { return CaseStatus.ALERT; } else { return CaseStatus.OK; } } + /** + * Extracts the case name from a case folder path. + * + * @param caseFolderPath A case folder path. + * + * @return A case name, with the time stamp suffix removed. + */ + static String getCaseNameFromCaseDirectoryPath(Path caseFolderPath) { + String caseName = caseFolderPath.getFileName().toString(); + if (caseName.length() > TimeStampUtils.getTimeStampLength()) { + return caseName.substring(0, caseName.length() - TimeStampUtils.getTimeStampLength()); + } else { + return caseName; + } + } + /** * Indicates whether or not some other object is "equal to" this - * AutoIngestCase object. + * MultiUserCase object. * * @param other The other object. * @@ -127,17 +144,17 @@ class AutoIngestCase implements Comparable { */ @Override public boolean equals(Object other) { - if (!(other instanceof AutoIngestCase)) { + if (!(other instanceof MultiUserCase)) { return false; } if (other == this) { return true; } - return this.caseDirectoryPath.toString().equals(((AutoIngestCase) other).caseDirectoryPath.toString()); + return this.caseDirectoryPath.toString().equals(((MultiUserCase) other).caseDirectoryPath.toString()); } /** - * Returns a hash code value for this AutoIngestCase object. + * Returns a hash code value for this MultiUserCase object. * * @return The has code. */ @@ -151,31 +168,31 @@ class AutoIngestCase implements Comparable { } /** - * Compares this AutopIngestCase object with abnother AutoIngestCase object - * for order. + * Compares this AutopIngestCase object with abnother MultiUserCase object + for order. */ @Override - public int compareTo(AutoIngestCase other) { + public int compareTo(MultiUserCase other) { return -this.lastAccessedDate.compareTo(other.getLastAccessedDate()); } /** * Comparator for a descending order sort on date created. */ - static class LastAccessedDateDescendingComparator implements Comparator { + static class LastAccessedDateDescendingComparator implements Comparator { /** - * Compares two AutoIngestCase objects for order based on last accessed - * date (descending). + * Compares two MultiUserCase objects for order based on last accessed + date (descending). * - * @param object The first AutoIngestCase object + * @param object The first MultiUserCase object * @param otherObject The second AuotIngestCase object. * * @return A negative integer, zero, or a positive integer as the first * argument is less than, equal to, or greater than the second. */ @Override - public int compare(AutoIngestCase object, AutoIngestCase otherObject) { + public int compare(MultiUserCase object, MultiUserCase otherObject) { return -object.getLastAccessedDate().compareTo(otherObject.getLastAccessedDate()); } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java new file mode 100755 index 0000000000..b1a0141a4f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java @@ -0,0 +1,132 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.casemodule; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import org.sleuthkit.autopsy.coordinationservice.CoordinationService; +import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; + +/** + * Handles locating and opening multi-user cases. + */ +final class MultiUserCaseManager { + + private static MultiUserCaseManager instance; + + private CoordinationService coordinationService; + + /** + * Gets the multi-user case manager. + * + * @return The multi-user case manager singleton. + * + * @throws MultiUserCaseManagerException + */ + synchronized static MultiUserCaseManager getInstance() throws MultiUserCaseManager.MultiUserCaseManagerException { + if (null == instance) { + instance = new MultiUserCaseManager(); + } + return instance; + } + + /** + * Constructs an object that handles locating and opening multi-user cases. + * + * @throws MultiUserCaseManagerException + */ + private MultiUserCaseManager() throws MultiUserCaseManagerException { + try { + coordinationService = CoordinationService.getInstance(); + } catch (CoordinationServiceException ex) { + throw new MultiUserCaseManager.MultiUserCaseManagerException("Failed to get the coordination service.", ex); + } + } + + /** + * Gets a list of the cases in the top level case folder + * + * @return List of cases. + * + * @throws MultiUserCaseManagerException + */ + List getCases() { + List cases = new ArrayList<>(); + List nodeList = coordinationService.getNodeList(CoordinationService.CategoryNode.CASES); + for (String node : nodeList) { + Path casePath = Paths.get(node); + File caseFolder = casePath.toFile(); + if(caseFolder.exists()) { + File[] autFiles = caseFolder.listFiles((dir, name) -> name.toLowerCase().endsWith(".aut")); + if(autFiles != null && autFiles.length > 0) { + cases.add(new MultiUserCase(casePath)); + } + } + } + return cases; + } + + /** + * Opens a multi-user case. + * + * @param caseMetadataFilePath Path to the case metadata file. + * + * @throws CaseActionException + */ + synchronized void openCase(Path caseMetadataFilePath) throws CaseActionException { + /* + * Open the case. + */ + Case.openAsCurrentCase(caseMetadataFilePath.toString()); + } + + /** + * Exception type thrown when there is an error completing a multi-user case + * manager operation. + */ + static final class MultiUserCaseManagerException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructs an instance of the exception type thrown when there is an + * error completing a multi-user case manager operation. + * + * @param message The exception message. + */ + private MultiUserCaseManagerException(String message) { + super(message); + } + + /** + * Constructs an instance of the exception type thrown when there is an + * error completing a multi-user case manager operation. + * + * @param message The exception message. + * @param cause A Throwable cause for the error. + */ + private MultiUserCaseManagerException(String message, Throwable cause) { + super(message, cause); + } + + } +} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasePanel.form similarity index 84% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.form rename to Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasePanel.form index cb0f275809..a54439c4d3 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasePanel.form @@ -45,7 +45,7 @@ - + @@ -82,7 +82,7 @@ - + @@ -118,7 +118,7 @@ - + @@ -153,7 +153,7 @@ - + @@ -165,10 +165,10 @@ - + - + @@ -182,7 +182,7 @@ - + @@ -196,7 +196,7 @@ - + @@ -209,7 +209,7 @@ - + @@ -222,7 +222,7 @@ - + diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasePanel.java similarity index 67% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java rename to Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasePanel.java index 2bcd335916..5f3365e8b1 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasePanel.java @@ -16,52 +16,35 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.casemodule; import java.awt.Cursor; import java.awt.Desktop; -import java.awt.EventQueue; -import java.awt.event.ActionEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Date; import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; import java.util.logging.Level; -import javax.swing.JDialog; import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.SwingWorker; import javax.swing.event.ListSelectionEvent; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableColumn; -import org.openide.util.NbBundle; -import org.openide.util.lookup.ServiceProvider; -import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.casemodule.CaseActionCancelledException; -import org.sleuthkit.autopsy.casemodule.CaseMetadata; -import org.sleuthkit.autopsy.casemodule.StartupWindowProvider; +import org.sleuthkit.autopsy.coreutils.CaseStatusIconCellRenderer; +import org.sleuthkit.autopsy.coreutils.GrayableCellRenderer; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.LongDateCellRenderer; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.casemodule.AutoIngestCasePanelInterface; -import org.sleuthkit.autopsy.casemodule.CueBannerPanel; -import org.sleuthkit.autopsy.coreutils.NetworkUtils; -import org.sleuthkit.autopsy.experimental.configuration.StartupWindow; /** * A panel that allows a user to open cases created by auto ingest. */ -@ServiceProvider(service = AutoIngestCasePanelInterface.class) -public final class AutoIngestCasePanel extends JPanel implements AutoIngestCasePanelInterface { +public class MultiUserCasePanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; - private static final Logger logger = Logger.getLogger(AutoIngestCasePanel.class.getName()); - private static final AutoIngestCase.LastAccessedDateDescendingComparator reverseDateModifiedComparator = new AutoIngestCase.LastAccessedDateDescendingComparator(); + private static final Logger LOGGER = Logger.getLogger(MultiUserCasePanel.class.getName()); + private static final String LOG_FILE_NAME = "auto_ingest_log.txt"; + private static final MultiUserCase.LastAccessedDateDescendingComparator REVERSE_DATE_MODIFIED_COMPARATOR = new MultiUserCase.LastAccessedDateDescendingComparator(); private static final int CASE_COL_MIN_WIDTH = 30; private static final int CASE_COL_MAX_WIDTH = 2000; private static final int CASE_COL_PREFERRED_WIDTH = 300; @@ -71,9 +54,6 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP private static final int STATUS_COL_MIN_WIDTH = 55; private static final int STATUS_COL_MAX_WIDTH = 250; private static final int STATUS_COL_PREFERRED_WIDTH = 60; - private static final int MILLIS_TO_WAIT_BEFORE_STARTING = 500; - private static final int MILLIS_TO_WAIT_BETWEEN_UPDATES = 300000; - private ScheduledThreadPoolExecutor casesTableRefreshExecutor; /* * The JTable table model for the cases table presented by this view is @@ -82,11 +62,11 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP * TODO (RC): Consider unifying this stuff in an enum as in * AutoIngestDashboard to make it less error prone. */ - private static final String CASE_HEADER = org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "ReviewModeCasePanel.CaseHeaderText"); - private static final String CREATEDTIME_HEADER = org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "ReviewModeCasePanel.CreatedTimeHeaderText"); - private static final String COMPLETEDTIME_HEADER = org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "ReviewModeCasePanel.LastAccessedTimeHeaderText"); - private static final String STATUS_ICON_HEADER = org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "ReviewModeCasePanel.StatusIconHeaderText"); - private static final String OUTPUT_FOLDER_HEADER = org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "ReviewModeCasePanel.OutputFolderHeaderText"); + private static final String CASE_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "ReviewModeCasePanel.CaseHeaderText"); + private static final String CREATEDTIME_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "ReviewModeCasePanel.CreatedTimeHeaderText"); + private static final String COMPLETEDTIME_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "ReviewModeCasePanel.LastAccessedTimeHeaderText"); + private static final String STATUS_ICON_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "ReviewModeCasePanel.StatusIconHeaderText"); + private static final String OUTPUT_FOLDER_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "ReviewModeCasePanel.OutputFolderHeaderText"); enum COLUMN_HEADERS { @@ -99,34 +79,6 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP private final String[] columnNames = {CASE_HEADER, CREATEDTIME_HEADER, COMPLETEDTIME_HEADER, STATUS_ICON_HEADER, OUTPUT_FOLDER_HEADER}; private DefaultTableModel caseTableModel; private Path currentlySelectedCase = null; - - public AutoIngestCasePanel() { - init(null); - } - - @Override - public void addWindowStateListener(JDialog parent) { - /* - * Add a window state listener that starts and stops refreshing of the - * cases table. - */ - parent.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - stopCasesTableRefreshes(); - } - - @Override - public void windowActivated(WindowEvent e) { - startCasesTableRefreshes(); - } - - @Override - public void windowClosed(WindowEvent e) { - stopCasesTableRefreshes(); - } - }); - } /** * Constructs a panel that allows a user to open cases created by automated @@ -134,11 +86,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP * * @param parent The parent dialog for this panel. */ - public AutoIngestCasePanel(JDialog parent) { - init(parent); - } - - public void init(JDialog parent) { + MultiUserCasePanel() { caseTableModel = new DefaultTableModel(columnNames, 0) { private static final long serialVersionUID = 1L; @@ -146,6 +94,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP public boolean isCellEditable(int row, int column) { return false; } + @Override public Class getColumnClass(int col) { if (this.getColumnName(col).equals(CREATEDTIME_HEADER) || this.getColumnName(col).equals(COMPLETEDTIME_HEADER)) { @@ -203,61 +152,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP } setButtons(); }); - - /* - * Add a window state listener that starts and stops refreshing of the - * cases table. - */ - if (parent != null) { - parent.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - stopCasesTableRefreshes(); - } - - @Override - public void windowActivated(WindowEvent e) { - startCasesTableRefreshes(); - } - - @Override - public void windowClosed(WindowEvent e) { - stopCasesTableRefreshes(); - } - }); - } - } - - /** - * Start doing periodic refreshes of the cases table. - */ - private void startCasesTableRefreshes() { - if (null == casesTableRefreshExecutor) { - casesTableRefreshExecutor = new ScheduledThreadPoolExecutor(1); - this.casesTableRefreshExecutor.scheduleAtFixedRate(() -> { - refreshCasesTable(); - }, MILLIS_TO_WAIT_BEFORE_STARTING, MILLIS_TO_WAIT_BETWEEN_UPDATES, TimeUnit.MILLISECONDS); - } - } - - /** - * Stop doing periodic refreshes of the cases table. - */ - private void stopCasesTableRefreshes() { - if (null != casesTableRefreshExecutor) { - casesTableRefreshExecutor.shutdown(); - } - this.casesTableRefreshExecutor = null; - } - - /* - * Updates the view presented by the panel. - */ - public void updateView() { - Thread thread = new Thread(() -> { - refreshCasesTable(); - }); - thread.start(); + refreshCasesTable(); } /** @@ -267,11 +162,25 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP private void refreshCasesTable() { try { currentlySelectedCase = getSelectedCase(); - AutoIngestCaseManager manager = AutoIngestCaseManager.getInstance(); - List theModel = manager.getCases(); - EventQueue.invokeLater(new CaseTableRefreshTask(theModel)); + MultiUserCaseManager manager = MultiUserCaseManager.getInstance(); + List cases = manager.getCases(); + cases.sort(REVERSE_DATE_MODIFIED_COMPARATOR); + caseTableModel.setRowCount(0); + long now = new Date().getTime(); + for (MultiUserCase autoIngestCase : cases) { + if (passesTimeFilter(now, autoIngestCase.getLastAccessedDate().getTime())) { + caseTableModel.addRow(new Object[]{ + autoIngestCase.getCaseName(), + autoIngestCase.getCreationDate(), + autoIngestCase.getLastAccessedDate(), + (MultiUserCase.CaseStatus.OK != autoIngestCase.getStatus()), + autoIngestCase.getCaseDirectoryPath().toString()}); + } + } + setSelectedCase(currentlySelectedCase); + setButtons(); } catch (Exception ex) { - logger.log(Level.SEVERE, "Unexpected exception in refreshCasesTable", ex); //NON-NLS + LOGGER.log(Level.SEVERE, "Unexpected exception in refreshCasesTable", ex); //NON-NLS } } @@ -320,9 +229,30 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP * in the cases table. */ private void setButtons() { - boolean enabled = casesTable.getSelectedRow() >= 0 && casesTable.getSelectedRow() < casesTable.getRowCount(); - bnOpen.setEnabled(enabled); - bnShowLog.setEnabled(enabled); + boolean openEnabled = casesTable.getSelectedRow() >= 0 && casesTable.getSelectedRow() < casesTable.getRowCount(); + bnOpen.setEnabled(openEnabled); + + Path pathToLog = getSelectedCaseLogFilePath(); + boolean showLogEnabled = openEnabled && pathToLog != null && pathToLog.toFile().exists(); + bnShowLog.setEnabled(showLogEnabled); + } + + /** + * Retrieves the log file path for the selected case in the cases table. + * + * @return The case log path. + */ + private Path getSelectedCaseLogFilePath() { + Path retValue = null; + + int selectedRow = casesTable.getSelectedRow(); + int rowCount = casesTable.getRowCount(); + if (selectedRow >= 0 && selectedRow < rowCount) { + String thePath = (String) caseTableModel.getValueAt(casesTable.convertRowIndexToModel(selectedRow), COLUMN_HEADERS.OUTPUTFOLDER.ordinal()); + retValue = Paths.get(thePath, LOG_FILE_NAME); + } + + return retValue; } /** @@ -332,91 +262,44 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP */ private void openCase(Path caseMetadataFilePath) { setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - new SwingWorker() { - - @Override - protected Void doInBackground() throws Exception { - AutoIngestCaseManager.getInstance().openCase(caseMetadataFilePath); - stopCasesTableRefreshes(); - StartupWindowProvider.getInstance().close(); - CueBannerPanel.closeAutoIngestCasesWindow(); - return null; + try { + StartupWindowProvider.getInstance().close(); + CueBannerPanel.closeMultiUserCasesWindow(); + CaseOpenMultiUserAction.closeMultiUserCasesWindow(); + MultiUserCaseManager.getInstance().openCase(caseMetadataFilePath); + } catch (CaseActionException | MultiUserCaseManager.MultiUserCaseManagerException ex) { + if (null != ex.getCause() && !(ex.getCause() instanceof CaseActionCancelledException)) { + LOGGER.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", caseMetadataFilePath), ex); //NON-NLS + MessageNotifyUtil.Message.error(ex.getCause().getLocalizedMessage()); } - - @Override - protected void done() { - try { - get(); - } catch (InterruptedException | ExecutionException ex) { - if (null != ex.getCause() && !(ex.getCause() instanceof CaseActionCancelledException)) { - logger.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", caseMetadataFilePath), ex); //NON-NLS - MessageNotifyUtil.Message.error(ex.getCause().getLocalizedMessage()); - } - StartupWindowProvider.getInstance().open(); - } finally { - setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - } - } - }.execute(); + StartupWindowProvider.getInstance().open(); + } finally { + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } } /** - * A task that refreshes the cases table using a list of auto ingest cases. + * Indicates whether or not a time satisfies a time filter defined by this + * panel's time filter radio buttons. + * + * @param currentTime The current date and time in milliseconds from the + * Unix epoch. + * @param inputTime The date and time to be tested as milliseconds from + * the Unix epoch. */ - private class CaseTableRefreshTask implements Runnable { - - private final List cases; - - CaseTableRefreshTask(List cases) { - setButtons(); - this.cases = cases; + private boolean passesTimeFilter(long currentTime, long inputTime) { + long numberOfUnits = 10; + long multiplier = 1; + if (rbAllCases.isSelected()) { + return true; + } else if (rbMonths.isSelected()) { + multiplier = 31; + } else if (rbWeeks.isSelected()) { + multiplier = 7; + } else if (rbDays.isSelected()) { + multiplier = 1; } - - /** - * @inheritDoc - */ - @Override - public void run() { - cases.sort(reverseDateModifiedComparator); - caseTableModel.setRowCount(0); - long now = new Date().getTime(); - for (AutoIngestCase autoIngestCase : cases) { - if (passesTimeFilter(now, autoIngestCase.getLastAccessedDate().getTime())) { - caseTableModel.addRow(new Object[]{ - autoIngestCase.getCaseName(), - autoIngestCase.getCreationDate(), - autoIngestCase.getLastAccessedDate(), - (AutoIngestCase.CaseStatus.OK != autoIngestCase.getStatus()), - autoIngestCase.getCaseDirectoryPath().toString()}); - } - } - setSelectedCase(currentlySelectedCase); - } - - /** - * Indicates whether or not a time satisfies a time filter defined by - * this panel's time filter radio buttons. - * - * @param currentTime The current date and time in milliseconds from the - * Unix epoch. - * @param inputTime The date and time to be tested as milliseconds - * from the Unix epoch. - */ - private boolean passesTimeFilter(long currentTime, long inputTime) { - long numberOfUnits = 10; - long multiplier = 1; - if (rbAllCases.isSelected()) { - return true; - } else if (rbMonths.isSelected()) { - multiplier = 31; - } else if (rbWeeks.isSelected()) { - multiplier = 7; - } else if (rbDays.isSelected()) { - multiplier = 1; - } - return ((currentTime - inputTime) / (1000 * 60 * 60 * 24)) < (numberOfUnits * multiplier); - } - + return ((currentTime - inputTime) / (1000 * 60 * 60 * 24)) < (numberOfUnits * multiplier); } /** @@ -443,7 +326,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP setName("Completed Cases"); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(bnOpen, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.bnOpen.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(bnOpen, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.bnOpen.text")); // NOI18N bnOpen.setEnabled(false); bnOpen.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -463,7 +346,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP }); scrollPaneTable.setViewportView(casesTable); - org.openide.awt.Mnemonics.setLocalizedText(bnRefresh, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.bnRefresh.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(bnRefresh, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.bnRefresh.text")); // NOI18N bnRefresh.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnRefreshActionPerformed(evt); @@ -472,7 +355,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP rbGroupHistoryLength.add(rbAllCases); rbAllCases.setSelected(true); - org.openide.awt.Mnemonics.setLocalizedText(rbAllCases, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbAllCases.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbAllCases, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.rbAllCases.text")); // NOI18N rbAllCases.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { rbAllCasesItemStateChanged(evt); @@ -494,8 +377,8 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP .addComponent(rbAllCases)) ); - org.openide.awt.Mnemonics.setLocalizedText(bnShowLog, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.bnShowLog.text")); // NOI18N - bnShowLog.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.bnShowLog.toolTipText")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(bnShowLog, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.bnShowLog.text")); // NOI18N + bnShowLog.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.bnShowLog.toolTipText")); // NOI18N bnShowLog.setEnabled(false); bnShowLog.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -504,7 +387,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP }); rbGroupHistoryLength.add(rbDays); - org.openide.awt.Mnemonics.setLocalizedText(rbDays, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbDays.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbDays, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.rbDays.text")); // NOI18N rbDays.setName(""); // NOI18N rbDays.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { @@ -513,7 +396,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP }); rbGroupHistoryLength.add(rbWeeks); - org.openide.awt.Mnemonics.setLocalizedText(rbWeeks, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbWeeks.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbWeeks, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.rbWeeks.text")); // NOI18N rbWeeks.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { rbWeeksItemStateChanged(evt); @@ -521,7 +404,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP }); rbGroupHistoryLength.add(rbMonths); - org.openide.awt.Mnemonics.setLocalizedText(rbMonths, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbMonths.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbMonths, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.rbMonths.text")); // NOI18N rbMonths.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { rbMonthsItemStateChanged(evt); @@ -529,7 +412,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP }); rbGroupLabel.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(rbGroupLabel, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbGroupLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbGroupLabel, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.rbGroupLabel.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -556,7 +439,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(bnRefresh) .addGap(4, 4, 4)) - .addComponent(scrollPaneTable, javax.swing.GroupLayout.DEFAULT_SIZE, 1007, Short.MAX_VALUE)) + .addComponent(scrollPaneTable)) .addContainerGap()) ); layout.setVerticalGroup( @@ -591,7 +474,10 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP Path caseMetadataFilePath = Paths.get((String) caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.OUTPUTFOLDER.ordinal()), caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.CASE.ordinal()) + CaseMetadata.getFileExtension()); - openCase(caseMetadataFilePath); + + new Thread(() -> { + openCase(caseMetadataFilePath); + }).start(); }//GEN-LAST:event_bnOpenActionPerformed /** @@ -599,53 +485,50 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP * * @param evt -- The event that caused this to be called */ - private void bnRefreshActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bnRefreshActionPerformed - {//GEN-HEADEREND:event_bnRefreshActionPerformed - updateView(); - }//GEN-LAST:event_bnRefreshActionPerformed + private void bnRefreshActionPerformed(java.awt.event.ActionEvent evt) { + refreshCasesTable(); + } - private void rbDaysItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbDaysItemStateChanged + private void rbDaysItemStateChanged(java.awt.event.ItemEvent evt) { if (rbDays.isSelected()) { - updateView(); + refreshCasesTable(); } - }//GEN-LAST:event_rbDaysItemStateChanged + } private void rbAllCasesItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbAllCasesItemStateChanged if (rbAllCases.isSelected()) { - updateView(); + refreshCasesTable(); } }//GEN-LAST:event_rbAllCasesItemStateChanged private void rbMonthsItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbMonthsItemStateChanged if (rbMonths.isSelected()) { - updateView(); + refreshCasesTable(); } }//GEN-LAST:event_rbMonthsItemStateChanged private void rbWeeksItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbWeeksItemStateChanged if (rbWeeks.isSelected()) { - updateView(); + refreshCasesTable(); } }//GEN-LAST:event_rbWeeksItemStateChanged private void bnShowLogActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnShowLogActionPerformed - int selectedRow = casesTable.convertRowIndexToModel(casesTable.getSelectedRow()); - int rowCount = casesTable.getRowCount(); - if (selectedRow >= 0 && selectedRow < rowCount) { - String thePath = (String) caseTableModel.getValueAt(selectedRow, COLUMN_HEADERS.OUTPUTFOLDER.ordinal()); - Path pathToLog = AutoIngestJobLogger.getLogPath(Paths.get(thePath)); + Path pathToLog = getSelectedCaseLogFilePath(); + if (pathToLog != null) { try { if (pathToLog.toFile().exists()) { Desktop.getDesktop().edit(pathToLog.toFile()); + } else { - JOptionPane.showMessageDialog(this, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "DisplayLogDialog.cannotFindLog"), - org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "DisplayLogDialog.unableToShowLogFile"), JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(this, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "DisplayLogDialog.cannotFindLog"), + org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "DisplayLogDialog.unableToShowLogFile"), JOptionPane.ERROR_MESSAGE); } } catch (IOException ex) { - logger.log(Level.SEVERE, String.format("Error attempting to open case auto ingest log file %s", pathToLog), ex); + LOGGER.log(Level.SEVERE, String.format("Error attempting to open case auto ingest log file %s", pathToLog), ex); JOptionPane.showMessageDialog(this, - org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "DisplayLogDialog.cannotOpenLog"), - org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "DisplayLogDialog.unableToShowLogFile"), + org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "DisplayLogDialog.cannotOpenLog"), + org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "DisplayLogDialog.unableToShowLogFile"), JOptionPane.PLAIN_MESSAGE); } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/actions/EamEditCaseInfoAction.java b/Core/src/org/sleuthkit/autopsy/centralrepository/actions/EamEditCaseInfoAction.java index 4123e382ff..060ca11ae6 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/actions/EamEditCaseInfoAction.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/actions/EamEditCaseInfoAction.java @@ -42,7 +42,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; lazy = false ) @ActionReference(path = "Menu/Case", position = 650, separatorAfter = 824) -@Messages("CTL_CentralRepositoryCaseProperties=Central Repository Case Properties...") +@Messages("CTL_CentralRepositoryCaseProperties=Central Repository Case Properties") public final class EamEditCaseInfoAction extends CallableSystemAction implements ActionListener { EamEditCaseInfoAction() { diff --git a/Core/src/org/sleuthkit/autopsy/core/layer.xml b/Core/src/org/sleuthkit/autopsy/core/layer.xml index 95cfcd481e..fb5618c6e6 100755 --- a/Core/src/org/sleuthkit/autopsy/core/layer.xml +++ b/Core/src/org/sleuthkit/autopsy/core/layer.xml @@ -51,7 +51,7 @@ - + @@ -157,7 +157,7 @@ - + @@ -165,11 +165,11 @@ - + - + diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseStatusIconCellRenderer.java b/Core/src/org/sleuthkit/autopsy/coreutils/CaseStatusIconCellRenderer.java similarity index 82% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseStatusIconCellRenderer.java rename to Core/src/org/sleuthkit/autopsy/coreutils/CaseStatusIconCellRenderer.java index 0010cc90ee..4d782a6f57 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseStatusIconCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/CaseStatusIconCellRenderer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,24 +16,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.coreutils; import java.awt.Component; import javax.swing.ImageIcon; import javax.swing.JTable; import static javax.swing.SwingConstants.CENTER; import org.openide.util.ImageUtilities; +import org.openide.util.NbBundle.Messages; /** * A JTable cell renderer that represents an auto ingest alert file exists flag * as a center-aligned icon, and grays out the cell if the table is disabled. */ -class CaseStatusIconCellRenderer extends GrayableCellRenderer { +public class CaseStatusIconCellRenderer extends GrayableCellRenderer { private static final long serialVersionUID = 1L; static final ImageIcon checkedIcon = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/experimental/images/tick.png", false)); static final ImageIcon warningIcon = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/experimental/images/warning16.png", false)); + @Messages({ + "CaseStatusIconCellRenderer.tooltiptext.ok=Images processed successfully", + "CaseStatusIconCellRenderer.tooltiptext.warning=An error occurred or processing was canceled for at least one image - please check the log" + }) @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { setHorizontalAlignment(CENTER); diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/GrayableCellRenderer.java b/Core/src/org/sleuthkit/autopsy/coreutils/GrayableCellRenderer.java similarity index 91% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/GrayableCellRenderer.java rename to Core/src/org/sleuthkit/autopsy/coreutils/GrayableCellRenderer.java index 60d3b77ccd..479f30bee2 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/GrayableCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/GrayableCellRenderer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.coreutils; import java.awt.Color; import java.awt.Component; @@ -28,11 +28,11 @@ import javax.swing.table.DefaultTableCellRenderer; * A JTable cell renderer that left-aligns cell content and grays out the cell * if the table is disabled. */ -class GrayableCellRenderer extends DefaultTableCellRenderer { +public class GrayableCellRenderer extends DefaultTableCellRenderer { private static final long serialVersionUID = 1L; - GrayableCellRenderer() { + public GrayableCellRenderer() { setHorizontalAlignment(LEFT); } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/LongDateCellRenderer.java b/Core/src/org/sleuthkit/autopsy/coreutils/LongDateCellRenderer.java similarity index 91% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/LongDateCellRenderer.java rename to Core/src/org/sleuthkit/autopsy/coreutils/LongDateCellRenderer.java index cfa2cedb14..e347b2d28a 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/LongDateCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/LongDateCellRenderer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.coreutils; import java.awt.Component; import java.text.SimpleDateFormat; @@ -28,7 +28,7 @@ import static javax.swing.SwingConstants.CENTER; * center-aligned, long-format date string. It also grays out the cell if the * table is disabled. */ -class LongDateCellRenderer extends GrayableCellRenderer { +public class LongDateCellRenderer extends GrayableCellRenderer { private static final long serialVersionUID = 1L; private static final String FORMAT_STRING = "yyyy/MM/dd HH:mm:ss"; //NON-NLS diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/TimeStampUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/TimeStampUtils.java similarity index 98% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/TimeStampUtils.java rename to Core/src/org/sleuthkit/autopsy/coreutils/TimeStampUtils.java index fe53871dd5..01a72e775b 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/TimeStampUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/TimeStampUtils.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.coreutils; import java.text.SimpleDateFormat; import java.util.Calendar; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseManager.java deleted file mode 100755 index 8469ff2315..0000000000 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseManager.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2017 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.experimental.autoingest; - -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.CaseActionException; -import org.sleuthkit.autopsy.coordinationservice.CoordinationService; -import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; - -/** - * Handles locating and opening cases created by auto ingest. - */ -final class AutoIngestCaseManager { - - private static AutoIngestCaseManager instance; - - private CoordinationService coordinationService; - - /** - * Gets the auto ingest case manager. - * - * @return The auto ingest case manager singleton. - * - * @throws AutoIngestCaseManagerException - */ - synchronized static AutoIngestCaseManager getInstance() throws AutoIngestCaseManager.AutoIngestCaseManagerException { - if (null == instance) { - instance = new AutoIngestCaseManager(); - } - return instance; - } - - /** - * Constructs an object that handles locating and opening cases created by - * auto ingest. - * - * @throws AutoIngestCaseManagerException - */ - private AutoIngestCaseManager() throws AutoIngestCaseManagerException { - try { - coordinationService = CoordinationService.getInstance(); - } catch (CoordinationServiceException ex) { - throw new AutoIngestCaseManager.AutoIngestCaseManagerException("Failed to get the coordination service.", ex); - } - } - - /** - * Gets a list of the cases in the top level case folder used by auto - * ingest. - * - * @return List of cases. - * - * @throws AutoIngestCaseManagerException - */ - List getCases() throws AutoIngestCaseManagerException { - List cases = new ArrayList<>(); - List casePathList = getCasePaths(); - for (Path casePath : casePathList) { - cases.add(new AutoIngestCase(casePath)); - } - return cases; - } - - /** - * Retrieve all of the case nodes and filter for only those that represent - * case paths. - * - * @return List of case paths. - * - * @throws AutoIngestCaseManagerException - */ - private List getCasePaths() throws AutoIngestCaseManagerException { - try { - List nodeList = coordinationService.getNodeList(CoordinationService.CategoryNode.CASES); - List casePathList = new ArrayList(0); - for (String node : nodeList) { - if(node.indexOf('\\') >= 0 || node.indexOf('/') >= 0) { - /* - * This is not a case name lock (name specifies a path). - */ - String nodeUpperCase = node.toUpperCase(); - if(!nodeUpperCase.endsWith("_RESOURCES") && !nodeUpperCase.endsWith("AUTO_INGEST_LOG.TXT")) { - /* - * This is not a case resource lock, nor a case auto - * ingest log lock. Collect the path. - */ - casePathList.add(Paths.get(node)); - } - } - } - return casePathList; - - } catch (CoordinationServiceException ex) { - throw new AutoIngestCaseManager.AutoIngestCaseManagerException("Failed to get node list from coordination service.", ex); - } - } - - /** - * Opens an auto ingest case case. - * - * @param caseMetadataFilePath Path to the case metadata file. - * - * @throws CaseActionException - */ - synchronized void openCase(Path caseMetadataFilePath) throws CaseActionException { - /* - * Open the case. - */ - Case.openAsCurrentCase(caseMetadataFilePath.toString()); - } - - /** - * Exception type thrown when there is an error completing an auto ingest - * case manager operation. - */ - static final class AutoIngestCaseManagerException extends Exception { - - private static final long serialVersionUID = 1L; - - /** - * Constructs an instance of the exception type thrown when there is an - * error completing an auto ingest case manager operation. - * - * @param message The exception message. - */ - private AutoIngestCaseManagerException(String message) { - super(message); - } - - /** - * Constructs an instance of the exception type thrown when there is an - * error completing an auto ingest case manager operation. - * - * @param message The exception message. - * @param cause A Throwable cause for the error. - */ - private AutoIngestCaseManagerException(String message, Throwable cause) { - super(message, cause); - } - - } -} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseOpenAction.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseOpenAction.java index e86a7bcf8a..265190663e 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseOpenAction.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseOpenAction.java @@ -27,9 +27,9 @@ import org.openide.util.NbBundle; import org.openide.util.actions.CallableSystemAction; import org.openide.util.actions.SystemAction; import org.sleuthkit.autopsy.casemodule.CaseCloseAction; -import org.sleuthkit.autopsy.casemodule.CaseOpenAction; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.CaseOpenAction; import org.sleuthkit.autopsy.casemodule.StartupWindowProvider; import org.sleuthkit.autopsy.core.UserPreferences; @@ -46,23 +46,6 @@ final class AutoIngestCaseOpenAction extends CallableSystemAction implements Act UserPreferences.SelectedMode mode = UserPreferences.getMode(); switch (mode) { - case REVIEW: - - if (Case.isCaseOpen()) { - /* - * In review mode, close the currently open case, if any, and - * then display the review mode cases panel. This can be - * accomplished by invoking CaseCloseAction because it calls - * StartupWindowProvider.getInstance().open() after it closes - * the current case. - */ - SystemAction.get(CaseCloseAction.class).actionPerformed(e); - } else { - // no case is open, so show the startup window - StartupWindowProvider.getInstance().open(); - } - break; - case AUTOINGEST: /* * New case action is disabled in auto ingest mode. @@ -70,13 +53,13 @@ final class AutoIngestCaseOpenAction extends CallableSystemAction implements Act break; case STANDALONE: + case REVIEW: /** * In standalone mode, invoke default Autopsy version of CaseOpenAction. */ Lookup.getDefault().lookup(CaseOpenAction.class).actionPerformed(e); break; - default: logger.log(Level.SEVERE, "Attempting to open case in unsupported mode {0}", mode.toString()); } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java index 891975223a..de737978cb 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java @@ -57,6 +57,8 @@ import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.core.ServicesMonitor; +import org.sleuthkit.autopsy.coreutils.CaseStatusIconCellRenderer; +import org.sleuthkit.autopsy.coreutils.LongDateCellRenderer; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.NetworkUtils; import org.sleuthkit.autopsy.coreutils.PlatformUtil; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java index 2d10dff258..5537d07236 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java @@ -41,7 +41,9 @@ import javax.swing.table.TableColumn; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.core.ServicesMonitor; +import org.sleuthkit.autopsy.coreutils.CaseStatusIconCellRenderer; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.LongDateCellRenderer; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestMonitor.JobsSnapshot; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java index 7e1b1907af..10ff60da2a 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java @@ -39,8 +39,7 @@ public final class AutoIngestDashboardOpenAction extends CallableSystemAction { @Override public boolean isEnabled() { - UserPreferences.SelectedMode mode = UserPreferences.getMode(); - return (mode == REVIEW); + return (UserPreferences.getIsMultiUserModeEnabled()); } @Override diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties index 422c7a56c4..fc80df5551 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties @@ -1,4 +1,4 @@ -CTL_OpenAction=Open Case... +CTL_OpenAction=Open Case AutoIngestDashboard.lbCompleted.text=Completed Jobs AutoIngestDashboard.lbRunning.text=Running Jobs AutoIngestDashboard.lbPending.text=Pending Jobs @@ -47,14 +47,10 @@ OpenIDE-Module-Long-Description=\ We make no guarantee that the API of this module will not change, so developers should be careful when relying on it. OpenIDE-Module-Name=Experimental OpenIDE-Module-Short-Description=This module contains features that are being developed by Basis Technology and are not part of the default Autopsy distribution. -ReviewModeCasePanel.cannotOpenCase=Cannot Open Case -ReviewModeCasePanel.casePathNotFound=Case path not found -ReviewModeCasePanel.caseIsLocked=Single-user case is locked. DisplayLogDialog.cannotOpenLog=Unable to open the selected case log file DisplayLogDialog.cannotFindLog=Unable to find the selected case log file DisplayLogDialog.unableToShowLogFile=Unable to show log file DisplayLogDialog.okay=Okay -ReviewModeCasePanel.bnShowLog.text=&Show Log CopyFilesPanel.lbFrom.text=From Source CopyFilesPanel.lbTo.text=Destination Case CopyFilesPanel.bnCopy.text=&Copy @@ -128,8 +124,6 @@ CopyFilesPanel.cbThrottleNetwork.toolTipText=Select this box if a low-band CopyFilesPanel.bnShowCurrentLog.text=Show &Log CopyFilesPanel.bnShowCurrentLog.text=Show &Log CopyFilesPanel.lbCaseName.text=Case Name -CaseStatusIconCellRenderer.tooltiptext.ok=Images processed successfully -CaseStatusIconCellRenderer.tooltiptext.warning=An error occurred or processing was canceled for at least one image - please check the log OptionsCategory_Name_Case_Import=Case Import OptionsCategory_Keywords_Case_Import=Case Import Settings CaseImportPanel.validationErrMsg.MUdisabled=Multi user settings must be enabled and saved @@ -165,11 +159,6 @@ SingleUserCaseImporter.FailedToComplete=Failed to complete processing of SingleUserCaseImporter.CompletedBatch=Completed batch processing of SingleUserCaseImporter.AbortingBatch=Aborting batch processing of SingleUserCaseImporter.SourceImageMissing=. Source image missing for -ReviewModeCasePanel.CaseHeaderText=Case -ReviewModeCasePanel.CreatedTimeHeaderText=Created Time -ReviewModeCasePanel.StatusIconHeaderText=Status -ReviewModeCasePanel.OutputFolderHeaderText=Output Folder -ReviewModeCasePanel.LastAccessedTimeHeaderText=Last Accessed Time CopyFilesPanel.bnOptions.text=&Options AutoIngestDashboard.lbServicesStatus.text=Services Status: AutoIngestDashboard.tbServicesStatusMessage.text=Connecting... @@ -231,15 +220,6 @@ FileExporterSettingsPanel.BrowseReportTooltip_1=Browse for the Reports Folder FileExporterSettingsPanel.NewRuleTooltip_1=Clear the rule editor to begin a new rule FileExporterSettingsPanel.DeleteTooltip_1=Delete the selected rule FileExporterSettingsPanel.SaveTooltip_1=Save the current rule -AutoIngestCasePanel.rbDays.text=Days -AutoIngestCasePanel.rbWeeks.text=Weeks -AutoIngestCasePanel.rbMonths.text=Months -AutoIngestCasePanel.rbAllCases.text=Everything -AutoIngestCasePanel.bnRefresh.text=&Refresh -AutoIngestCasePanel.bnOpen.text=&Open -AutoIngestCasePanel.bnShowLog.toolTipText=Display case log file for selected case -AutoIngestCasePanel.bnShowLog.text=&Show Log -AutoIngestCasePanel.rbGroupLabel.text=Show cases accessed in the last 10: AutoIngestDashboard.refreshButton.toolTipText=Refresh displayed tables AutoIngestDashboard.refreshButton.text=&Refresh AutoIngestDashboard.jButton1.text=jButton1 diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CenteredGrayableCellRenderer.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CenteredGrayableCellRenderer.java index b9040b674b..264d37eedd 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CenteredGrayableCellRenderer.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CenteredGrayableCellRenderer.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.experimental.autoingest; import static javax.swing.SwingConstants.CENTER; +import org.sleuthkit.autopsy.coreutils.GrayableCellRenderer; /** * A JTable cell renderer that center-aligns cell content and grays out the cell diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DurationCellRenderer.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DurationCellRenderer.java index 6bac0a996b..c61e363222 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DurationCellRenderer.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DurationCellRenderer.java @@ -18,10 +18,12 @@ */ package org.sleuthkit.autopsy.experimental.autoingest; +import java.awt.Color; import java.awt.Component; import java.time.Duration; import javax.swing.JTable; import static javax.swing.SwingConstants.CENTER; +import org.sleuthkit.autopsy.coreutils.GrayableCellRenderer; /** * A JTable cell renderer that renders a duration represented as a long as a @@ -71,4 +73,26 @@ class DurationCellRenderer extends GrayableCellRenderer { grayCellIfTableNotEnabled(table, isSelected); return this; } + + void grayCellIfTableNotEnabled(JTable table, boolean isSelected) { + if (table.isEnabled()) { + /* + * The table is enabled, make the foreground and background the + * normal selected or unselected color. + */ + if (isSelected) { + setBackground(table.getSelectionBackground()); + setForeground(table.getSelectionForeground()); + } else { + setBackground(table.getBackground()); + setForeground(table.getForeground()); + } + } else { + /* + * The table is disabled, make the foreground and background gray. + */ + setBackground(Color.lightGray); + setForeground(Color.darkGray); + } + } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java index 18ce9709d5..a7d5675883 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.sleuthkit.autopsy.casemodule.CaseMetadata; +import org.sleuthkit.autopsy.coreutils.TimeStampUtils; final class PathUtils { diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ShortDateCellRenderer.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ShortDateCellRenderer.java index 713d177c0a..f2670fa1b7 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ShortDateCellRenderer.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ShortDateCellRenderer.java @@ -18,10 +18,12 @@ */ package org.sleuthkit.autopsy.experimental.autoingest; +import java.awt.Color; import java.awt.Component; import java.text.SimpleDateFormat; import javax.swing.JTable; import static javax.swing.SwingConstants.CENTER; +import org.sleuthkit.autopsy.coreutils.GrayableCellRenderer; /** * A JTable cell renderer that renders a date represented as a long as a @@ -46,4 +48,26 @@ class ShortDateCellRenderer extends GrayableCellRenderer { grayCellIfTableNotEnabled(table, isSelected); return this; } + + void grayCellIfTableNotEnabled(JTable table, boolean isSelected) { + if (table.isEnabled()) { + /* + * The table is enabled, make the foreground and background the + * normal selected or unselected color. + */ + if (isSelected) { + setBackground(table.getSelectionBackground()); + setForeground(table.getSelectionForeground()); + } else { + setBackground(table.getBackground()); + setForeground(table.getForeground()); + } + } else { + /* + * The table is disabled, make the foreground and background gray. + */ + setBackground(Color.lightGray); + setForeground(Color.darkGray); + } + } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/SingleUserCaseImporter.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/SingleUserCaseImporter.java index e04399d321..3a5c45632f 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/SingleUserCaseImporter.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/SingleUserCaseImporter.java @@ -47,6 +47,7 @@ import org.sleuthkit.autopsy.casemodule.SingleUserCaseConverter; import org.sleuthkit.autopsy.casemodule.SingleUserCaseConverter.ImportCaseData; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.NetworkUtils; +import org.sleuthkit.autopsy.coreutils.TimeStampUtils; public class SingleUserCaseImporter implements Runnable { diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties index 66ed50dd20..a12453e3c1 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties @@ -23,12 +23,9 @@ AIMIngestSettingsPanel.lbSecondsBetweenJobs.toolTipText=Increase this value if d AIMIngestSettingsPanel.spSecondsBetweenJobs.toolTipText=Increase this value if database locks cause problems. It gives a little more time for finalizing. AutoIngestSettingsPanel.AdvancedAutoIngestSettingsPanel.Title=Advanced Settings AutoIngestSettingsPanel.browseGlobalSettingsButton.text=Browse -AutoIngestSettingsPanel.browseSharedSettingsButton.text=Browse AutoIngestSettingsPanel.CannotAccess=Cannot access AutoIngestSettingsPanel.cbJoinAutoIngestCluster.text=Join auto ingest cluster AutoIngestSettingsPanel.CheckPermissions=Check permissions. -AutoIngestSettingsPanel.configButtonErrorTextField.text=configButtonErrorTextField -AutoIngestSettingsPanel.downloadButton.text=Download Config AutoIngestSettingsPanel.EmptySettingsDirectory=Enter path to settings directory AutoIngestSettingsPanel.ErrorSettingDefaultFolder=Error creating default folder AutoIngestSettingsPanel.FileExportRules.text=File Export Rules @@ -36,12 +33,8 @@ AutoIngestSettingsPanel.globalSettingsErrorTextField.text= AutoIngestSettingsPanel.globalSettingsTextField.text= AutoIngestSettingsPanel.ImageDirectoryUnspecified=Shared images folder must be set AutoIngestSettingsPanel.InvalidPortNumber=Invalid port number. -AutoIngestSettingsPanel.jLabelCurrentTask.text=Current task: -AutoIngestSettingsPanel.jLabelTaskDescription.text=jLabel1 -AutoIngestSettingsPanel.jPanelSharedConfig.border.title=Shared Configuration AutoIngestSettingsPanel.jRadioButtonCopyFiles.text=File Copy mode AutoIngestSettingsPanel.KeywordSearchNull=Cannot find Keyword Search service -AutoIngestSettingsPanel.masterNodeCheckBox.text=Use this node as a master node that can upload settings AutoIngestSettingsPanel.MustRestart=Autopsy must be restarted for new configuration to take effect AutoIngestSettingsPanel.nodePanel.TabConstraints.tabTitle=Node Configuration AutoIngestSettingsPanel.NodeStatusLogging.text=Node Status Logging Settings @@ -49,11 +42,7 @@ AutoIngestSettingsPanel.PathInvalid=Path is not valid AutoIngestSettingsPanel.restartRequiredLabel.text=Application restart required to take effect. AutoIngestSettingsPanel.restartRequiredLabel.text=Application restart required AutoIngestSettingsPanel.ResultsDirectoryUnspecified=Shared cases folder must be set -AutoIngestSettingsPanel.sharedConfigCheckbox.text=Use shared configuration in folder: -AutoIngestSettingsPanel.sharedSettingsErrorTextField.text=globalSettingsErrorTextField -AutoIngestSettingsPanel.sharedSettingsTextField.text= AutoIngestSettingsPanel.tbOops.text= -AutoIngestSettingsPanel.uploadButton.text=Save & Upload Config AutoIngestSettingsPanel.validationErrMsg.incomplete=Fill in all values AutoIngestSettingsPanel.validationErrMsg.invalidDatabasePort=Invalid database port number AutoIngestSettingsPanel.validationErrMsg.invalidIndexingServerPort=Invalid Solr server port number @@ -119,8 +108,16 @@ AdvancedAutoIngestSettingsPanel.lbConcurrentJobsPerCase.toolTipText_1=A soft lim AdvancedAutoIngestSettingsPanel.lbNumberOfThreads.toolTipText_1=The number of threads running file level ingest modules. AdvancedAutoIngestSettingsPanel.numberOfFileIngestThreadsComboBox.toolTipText=The number of threads running file level ingest modules. NodeStatusLogPanel.tbDbName.toolTipText_1=Database name -AutoIngestSettingsPanel.jPanelNodeType.border.title=Node Type Setup -AutoIngestSettingsPanel.jLabel1.text= +AutoIngestSettingsPanel.sharedSettingsTextField.text= +AutoIngestSettingsPanel.sharedConfigCheckbox.text=Use shared configuration in folder: +AutoIngestSettingsPanel.configButtonErrorTextField.text=configButtonErrorTextField +AutoIngestSettingsPanel.jLabelTaskDescription.text=jLabel1 +AutoIngestSettingsPanel.jLabelCurrentTask.text=Current task: +AutoIngestSettingsPanel.downloadButton.text=Download Config +AutoIngestSettingsPanel.uploadButton.text=Save & Upload Config +AutoIngestSettingsPanel.masterNodeCheckBox.text=Use this node as a master node that can upload settings +AutoIngestSettingsPanel.sharedSettingsErrorTextField.text=globalSettingsErrorTextField +AutoIngestSettingsPanel.browseSharedSettingsButton.text=Browse AutoIngestSettingsPanel.jLabelInvalidResultsFolder.text=jLabelInvalidResultsFolder AutoIngestSettingsPanel.jLabelInvalidImageFolder.text=jLabelInvalidImageFolder AutoIngestSettingsPanel.browseOutputFolderButton.text=Browse @@ -131,12 +128,6 @@ AutoIngestSettingsPanel.browseInputFolderButton.text=Browse AutoIngestSettingsPanel.inputPathTextField.toolTipText=Input folder for automated processing, i.e., the location where input case folders will be created for ingest by automated processing mode AutoIngestSettingsPanel.inputPathTextField.text= AutoIngestSettingsPanel.jLabelSelectInputFolder.text=Select shared images folder: -AutoIngestSettingsPanel.jRadioButtonReview.toolTipText=Review cases created in automated processing mode -AutoIngestSettingsPanel.jRadioButtonReview.text=Examiner node -AutoIngestSettingsPanel.jRadioButtonAutomated.toolTipText=Automatically detect new data sources and create cases. -AutoIngestSettingsPanel.jRadioButtonAutomated.text=Auto ingest node (application restart required) -AutoIngestSettingsPanel.jLabelSelectMode.text=Select mode: -AutoIngestSettingsPanel.jPanelIngestSettings.border.title=Automated Ingest Settings AutoIngestSettingsPanel.bnLogging.text=Node Status Logging AutoIngestSettingsPanel.bnFileExport.text=File Export Settings AutoIngestSettingsPanel.bnAdvancedSettings.text=Advanced Settings From d750ebfa24f0b864de69a1159ab707a2aaadf104 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 18 Oct 2017 16:43:10 -0400 Subject: [PATCH 002/115] Fixed merge conflicts. --- .../casemodule/MultiUserCaseManager.java | 26 +- .../AutoIngestSettingsPanel.form | 884 +++++++----------- .../AutoIngestSettingsPanel.java | 745 ++++++--------- 3 files changed, 635 insertions(+), 1020 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java index b1a0141a4f..ec3b42116d 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java @@ -67,21 +67,21 @@ final class MultiUserCaseManager { * * @return List of cases. * - * @throws MultiUserCaseManagerException + * @throws CoordinationServiceException */ - List getCases() { + List getCases() throws CoordinationServiceException { List cases = new ArrayList<>(); - List nodeList = coordinationService.getNodeList(CoordinationService.CategoryNode.CASES); - for (String node : nodeList) { - Path casePath = Paths.get(node); - File caseFolder = casePath.toFile(); - if(caseFolder.exists()) { - File[] autFiles = caseFolder.listFiles((dir, name) -> name.toLowerCase().endsWith(".aut")); - if(autFiles != null && autFiles.length > 0) { - cases.add(new MultiUserCase(casePath)); - } - } - } + List nodeList = coordinationService.getNodeList(CoordinationService.CategoryNode.CASES); + for (String node : nodeList) { + Path casePath = Paths.get(node); + File caseFolder = casePath.toFile(); + if(caseFolder.exists()) { + File[] autFiles = caseFolder.listFiles((dir, name) -> name.toLowerCase().endsWith(".aut")); + if(autFiles != null && autFiles.length > 0) { + cases.add(new MultiUserCase(casePath)); + } + } + } return cases; } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.form b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.form index 20c8c7a981..9965d1ad8f 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.form @@ -56,18 +56,71 @@ - - - - + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -79,542 +132,65 @@ - - + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -649,6 +225,238 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java index 4877ce9d60..892a27aab6 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java @@ -56,7 +56,7 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { enum OptionsUiMode { - STANDALONE, AIM, REVIEW, DOWNLOADING_CONFIGURATION + STANDALONE, AIM, DOWNLOADING_CONFIGURATION }; /** @@ -127,21 +127,10 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { if (inStartup) { UserPreferences.SelectedMode storedMode = UserPreferences.getMode(); inputPathTextField.requestFocusInWindow(); - if (null != storedMode) { - switch (storedMode) { - case REVIEW: - jRadioButtonReview.setSelected(true); - enableOptionsBasedOnMode(OptionsUiMode.REVIEW); - break; - case AUTOINGEST: - jRadioButtonAutomated.setSelected(true); - enableOptionsBasedOnMode(OptionsUiMode.AIM); - break; - default: - cbJoinAutoIngestCluster.setSelected(false); - enableOptionsBasedOnMode(OptionsUiMode.STANDALONE); - break; - } + if (storedMode == UserPreferences.SelectedMode.AUTOINGEST) { + enableOptionsBasedOnMode(OptionsUiMode.AIM); + } else if (storedMode != null) { + enableOptionsBasedOnMode(OptionsUiMode.STANDALONE); } } @@ -207,22 +196,12 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { * Save mode to persistent storage. */ void store() { - boolean needsRestart = false; - UserPreferences.SelectedMode storedMode = UserPreferences.getMode(); - + boolean needsRestart = (cbJoinAutoIngestCluster.isSelected() != AutoIngestUserPreferences.getJoinAutoModeCluster()); + AutoIngestUserPreferences.setJoinAutoModeCluster(cbJoinAutoIngestCluster.isSelected()); if (!cbJoinAutoIngestCluster.isSelected()) { - if(storedMode == UserPreferences.SelectedMode.AUTOINGEST) { - needsRestart = true; - } - UserPreferences.setMode(UserPreferences.SelectedMode.STANDALONE); - } - else if (jRadioButtonAutomated.isSelected()) { - if (storedMode == UserPreferences.SelectedMode.REVIEW) { - needsRestart = true; - } - + } else { UserPreferences.setMode(UserPreferences.SelectedMode.AUTOINGEST); String imageFolderPath = getNormalizedFolderPath(inputPathTextField.getText().trim()); AutoIngestUserPreferences.setAutoModeImageFolder(imageFolderPath); @@ -234,15 +213,8 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { AutoIngestUserPreferences.setSharedConfigFolder(globalSettingsPath); AutoIngestUserPreferences.setSharedConfigMaster(masterNodeCheckBox.isSelected()); } - } else if (jRadioButtonReview.isSelected()) { - if (storedMode == UserPreferences.SelectedMode.AUTOINGEST) { - needsRestart = true; - } - - UserPreferences.setMode(UserPreferences.SelectedMode.REVIEW); - String resultsFolderPath = getNormalizedFolderPath(outputPathTextField.getText().trim()); - AutoIngestUserPreferences.setAutoModeResultsFolder(resultsFolderPath); } + if (needsRestart) { SwingUtilities.invokeLater(() -> { JOptionPane.showMessageDialog(null, @@ -306,23 +278,14 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { configButtonErrorTextField.setText("Shared configuration folder is invalid"); } break; - case REVIEW: - jLabelInvalidImageFolder.setVisible(false); - if (!validateResultsPath()) { - isValidNodePanel = false; - } - break; - case STANDALONE: break; default: break; } - if (jRadioButtonAutomated.isSelected()) { - if (sharedConfigCheckbox.isEnabled() && sharedConfigCheckbox.isSelected() && !validSharedConfigSettings()) { - isValidNodePanel = false; - } + if (sharedConfigCheckbox.isEnabled() && sharedConfigCheckbox.isSelected() && !validSharedConfigSettings()) { + isValidNodePanel = false; } return isValidNodePanel; } @@ -579,24 +542,17 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { private void enableOptionsBasedOnMode(OptionsUiMode mode) { if (mode != OptionsUiMode.DOWNLOADING_CONFIGURATION) { boolean nonMasterSharedConfig = !masterNodeCheckBox.isSelected() && sharedConfigCheckbox.isSelected(); - jRadioButtonAutomated.setEnabled(cbJoinAutoIngestCluster.isSelected()); - jRadioButtonReview.setEnabled(cbJoinAutoIngestCluster.isSelected()); - jLabelSelectInputFolder.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); inputPathTextField.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); browseInputFolderButton.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); - jLabelSelectOutputFolder.setEnabled((mode == OptionsUiMode.AIM && !nonMasterSharedConfig) || mode == OptionsUiMode.REVIEW); - outputPathTextField.setEnabled((mode == OptionsUiMode.AIM && !nonMasterSharedConfig) || mode == OptionsUiMode.REVIEW); - browseOutputFolderButton.setEnabled((mode == OptionsUiMode.AIM && !nonMasterSharedConfig) || mode == OptionsUiMode.REVIEW); + jLabelSelectOutputFolder.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); + outputPathTextField.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); + browseOutputFolderButton.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); - jPanelSharedConfig.setEnabled(mode == OptionsUiMode.AIM); - - jPanelIngestSettings.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); bnEditIngestSettings.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); bnAdvancedSettings.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); bnLogging.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); - jPanelSharedConfig.setEnabled(mode == OptionsUiMode.AIM); sharedConfigCheckbox.setEnabled(mode == OptionsUiMode.AIM); masterNodeCheckBox.setEnabled(mode == OptionsUiMode.AIM && sharedConfigCheckbox.isSelected()); bnFileExport.setEnabled(mode == OptionsUiMode.AIM); @@ -613,14 +569,8 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { private OptionsUiMode getModeFromRadioButtons() { if (!cbJoinAutoIngestCluster.isSelected()) { return OptionsUiMode.STANDALONE; - } - - if (jRadioButtonAutomated.isSelected()) { - return OptionsUiMode.AIM; - } else if (jRadioButtonReview.isSelected()) { - return OptionsUiMode.REVIEW; } else { - return OptionsUiMode.STANDALONE; + return OptionsUiMode.AIM; } } @@ -636,289 +586,49 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { modeRadioButtons = new javax.swing.ButtonGroup(); nodeScrollPane = new javax.swing.JScrollPane(); nodePanel = new javax.swing.JPanel(); - jPanelNodeType = new javax.swing.JPanel(); - jLabelSelectMode = new javax.swing.JLabel(); - jRadioButtonAutomated = new javax.swing.JRadioButton(); - jRadioButtonReview = new javax.swing.JRadioButton(); - jLabelSelectInputFolder = new javax.swing.JLabel(); - inputPathTextField = new javax.swing.JTextField(); - browseInputFolderButton = new javax.swing.JButton(); - jLabelSelectOutputFolder = new javax.swing.JLabel(); - outputPathTextField = new javax.swing.JTextField(); - browseOutputFolderButton = new javax.swing.JButton(); - jLabelInvalidImageFolder = new javax.swing.JLabel(); - jLabelInvalidResultsFolder = new javax.swing.JLabel(); - jLabel1 = new javax.swing.JLabel(); - jPanelSharedConfig = new javax.swing.JPanel(); - sharedConfigCheckbox = new javax.swing.JCheckBox(); - sharedSettingsTextField = new javax.swing.JTextField(); - browseSharedSettingsButton = new javax.swing.JButton(); - sharedSettingsErrorTextField = new javax.swing.JTextField(); - masterNodeCheckBox = new javax.swing.JCheckBox(); - uploadButton = new javax.swing.JButton(); - downloadButton = new javax.swing.JButton(); - jLabelCurrentTask = new javax.swing.JLabel(); - pbTaskInProgress = new javax.swing.JProgressBar(); - jLabelTaskDescription = new javax.swing.JLabel(); - configButtonErrorTextField = new javax.swing.JTextField(); - jSeparator1 = new javax.swing.JSeparator(); - jPanelIngestSettings = new javax.swing.JPanel(); + cbJoinAutoIngestCluster = new javax.swing.JCheckBox(); + tbOops = new javax.swing.JTextField(); bnEditIngestSettings = new javax.swing.JButton(); bnAdvancedSettings = new javax.swing.JButton(); bnFileExport = new javax.swing.JButton(); bnLogging = new javax.swing.JButton(); - cbJoinAutoIngestCluster = new javax.swing.JCheckBox(); - tbOops = new javax.swing.JTextField(); + browseOutputFolderButton = new javax.swing.JButton(); + browseInputFolderButton = new javax.swing.JButton(); + inputPathTextField = new javax.swing.JTextField(); + outputPathTextField = new javax.swing.JTextField(); + jLabelInvalidResultsFolder = new javax.swing.JLabel(); + jLabelInvalidImageFolder = new javax.swing.JLabel(); + jLabelSelectInputFolder = new javax.swing.JLabel(); + jLabelSelectOutputFolder = new javax.swing.JLabel(); + sharedConfigCheckbox = new javax.swing.JCheckBox(); + sharedSettingsErrorTextField = new javax.swing.JTextField(); + sharedSettingsTextField = new javax.swing.JTextField(); + browseSharedSettingsButton = new javax.swing.JButton(); + downloadButton = new javax.swing.JButton(); + configButtonErrorTextField = new javax.swing.JTextField(); + pbTaskInProgress = new javax.swing.JProgressBar(); + jLabelTaskDescription = new javax.swing.JLabel(); + jLabelCurrentTask = new javax.swing.JLabel(); + uploadButton = new javax.swing.JButton(); + masterNodeCheckBox = new javax.swing.JCheckBox(); nodeScrollPane.setMinimumSize(new java.awt.Dimension(0, 0)); nodePanel.setMinimumSize(new java.awt.Dimension(100, 100)); - jPanelNodeType.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jPanelNodeType.border.title"))); // NOI18N - jPanelNodeType.setMinimumSize(new java.awt.Dimension(50, 50)); - - org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectMode, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelSelectMode.text")); // NOI18N - - modeRadioButtons.add(jRadioButtonAutomated); - jRadioButtonAutomated.setSelected(true); - org.openide.awt.Mnemonics.setLocalizedText(jRadioButtonAutomated, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jRadioButtonAutomated.text")); // NOI18N - jRadioButtonAutomated.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jRadioButtonAutomated.toolTipText")); // NOI18N - jRadioButtonAutomated.addActionListener(new java.awt.event.ActionListener() { + cbJoinAutoIngestCluster.setFont(cbJoinAutoIngestCluster.getFont().deriveFont(cbJoinAutoIngestCluster.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + org.openide.awt.Mnemonics.setLocalizedText(cbJoinAutoIngestCluster, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.cbJoinAutoIngestCluster.text")); // NOI18N + cbJoinAutoIngestCluster.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - jRadioButtonAutomatedActionPerformed(evt); + cbJoinAutoIngestClusterActionPerformed(evt); } }); - modeRadioButtons.add(jRadioButtonReview); - org.openide.awt.Mnemonics.setLocalizedText(jRadioButtonReview, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jRadioButtonReview.text")); // NOI18N - jRadioButtonReview.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jRadioButtonReview.toolTipText")); // NOI18N - jRadioButtonReview.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - jRadioButtonReviewActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectInputFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelSelectInputFolder.text")); // NOI18N - jLabelSelectInputFolder.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM); - - inputPathTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.inputPathTextField.text")); // NOI18N - inputPathTextField.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.inputPathTextField.toolTipText")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(browseInputFolderButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseInputFolderButton.text")); // NOI18N - browseInputFolderButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - browseInputFolderButtonActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectOutputFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelSelectOutputFolder.text")); // NOI18N - jLabelSelectOutputFolder.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM); - - outputPathTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.outputPathTextField.text")); // NOI18N - outputPathTextField.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.outputPathTextField.toolTipText")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(browseOutputFolderButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseOutputFolderButton.text")); // NOI18N - browseOutputFolderButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - browseOutputFolderButtonActionPerformed(evt); - } - }); - - jLabelInvalidImageFolder.setForeground(new java.awt.Color(255, 0, 0)); - org.openide.awt.Mnemonics.setLocalizedText(jLabelInvalidImageFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelInvalidImageFolder.text")); // NOI18N - - jLabelInvalidResultsFolder.setForeground(new java.awt.Color(255, 0, 0)); - org.openide.awt.Mnemonics.setLocalizedText(jLabelInvalidResultsFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelInvalidResultsFolder.text")); // NOI18N - - jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/experimental/images/AIM.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabel1.text")); // NOI18N - - javax.swing.GroupLayout jPanelNodeTypeLayout = new javax.swing.GroupLayout(jPanelNodeType); - jPanelNodeType.setLayout(jPanelNodeTypeLayout); - jPanelNodeTypeLayout.setHorizontalGroup( - jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(outputPathTextField, javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(inputPathTextField, javax.swing.GroupLayout.Alignment.LEADING)) - .addGap(10, 10, 10) - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(browseInputFolderButton, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(browseOutputFolderButton, javax.swing.GroupLayout.Alignment.TRAILING))) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabelSelectMode) - .addComponent(jRadioButtonReview) - .addComponent(jRadioButtonAutomated)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jLabel1)) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addComponent(jLabelSelectInputFolder) - .addGap(18, 18, 18) - .addComponent(jLabelInvalidImageFolder, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addComponent(jLabelSelectOutputFolder) - .addGap(18, 18, 18) - .addComponent(jLabelInvalidResultsFolder, javax.swing.GroupLayout.PREFERRED_SIZE, 544, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE))) - .addContainerGap()) - ); - jPanelNodeTypeLayout.setVerticalGroup( - jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addContainerGap() - .addComponent(jLabelSelectMode) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jRadioButtonAutomated) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jRadioButtonReview)) - .addComponent(jLabel1)) - .addGap(1, 1, 1) - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabelSelectInputFolder) - .addComponent(jLabelInvalidImageFolder)) - .addGap(1, 1, 1) - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(inputPathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(browseInputFolderButton)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabelSelectOutputFolder, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jLabelInvalidResultsFolder)) - .addGap(1, 1, 1) - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(browseOutputFolderButton) - .addComponent(outputPathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(0, 0, Short.MAX_VALUE)) - ); - - jPanelSharedConfig.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jPanelSharedConfig.border.title"))); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(sharedConfigCheckbox, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedConfigCheckbox.text")); // NOI18N - sharedConfigCheckbox.setMaximumSize(new java.awt.Dimension(191, 14)); - sharedConfigCheckbox.setMinimumSize(new java.awt.Dimension(191, 14)); - sharedConfigCheckbox.setPreferredSize(new java.awt.Dimension(191, 14)); - sharedConfigCheckbox.addItemListener(new java.awt.event.ItemListener() { - public void itemStateChanged(java.awt.event.ItemEvent evt) { - sharedConfigCheckboxItemStateChanged(evt); - } - }); - - sharedSettingsTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedSettingsTextField.text")); // NOI18N - sharedSettingsTextField.setEnabled(false); - - org.openide.awt.Mnemonics.setLocalizedText(browseSharedSettingsButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseSharedSettingsButton.text")); // NOI18N - browseSharedSettingsButton.setEnabled(false); - browseSharedSettingsButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - browseSharedSettingsButtonActionPerformed(evt); - } - }); - - sharedSettingsErrorTextField.setEditable(false); - sharedSettingsErrorTextField.setForeground(new java.awt.Color(255, 0, 0)); - sharedSettingsErrorTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedSettingsErrorTextField.text")); // NOI18N - sharedSettingsErrorTextField.setBorder(null); - - org.openide.awt.Mnemonics.setLocalizedText(masterNodeCheckBox, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.masterNodeCheckBox.text")); // NOI18N - masterNodeCheckBox.setEnabled(false); - masterNodeCheckBox.addItemListener(new java.awt.event.ItemListener() { - public void itemStateChanged(java.awt.event.ItemEvent evt) { - masterNodeCheckBoxItemStateChanged(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(uploadButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.uploadButton.text")); // NOI18N - uploadButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - uploadButtonActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(downloadButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.downloadButton.text")); // NOI18N - downloadButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - downloadButtonActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(jLabelCurrentTask, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelCurrentTask.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(jLabelTaskDescription, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelTaskDescription.text")); // NOI18N - - configButtonErrorTextField.setEditable(false); - configButtonErrorTextField.setForeground(new java.awt.Color(255, 0, 0)); - configButtonErrorTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.configButtonErrorTextField.text")); // NOI18N - configButtonErrorTextField.setBorder(null); - - javax.swing.GroupLayout jPanelSharedConfigLayout = new javax.swing.GroupLayout(jPanelSharedConfig); - jPanelSharedConfig.setLayout(jPanelSharedConfigLayout); - jPanelSharedConfigLayout.setHorizontalGroup( - jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelSharedConfigLayout.createSequentialGroup() - .addGap(10, 10, 10) - .addComponent(jLabelCurrentTask) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jLabelTaskDescription, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addContainerGap()) - .addGroup(jPanelSharedConfigLayout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelSharedConfigLayout.createSequentialGroup() - .addComponent(sharedSettingsTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 400, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(browseSharedSettingsButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(uploadButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanelSharedConfigLayout.createSequentialGroup() - .addComponent(downloadButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(configButtonErrorTextField)) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanelSharedConfigLayout.createSequentialGroup() - .addComponent(sharedConfigCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(sharedSettingsErrorTextField)) - .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 692, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(pbTaskInProgress, javax.swing.GroupLayout.PREFERRED_SIZE, 695, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(masterNodeCheckBox)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - jPanelSharedConfigLayout.setVerticalGroup( - jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelSharedConfigLayout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(sharedConfigCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(sharedSettingsErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(sharedSettingsTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(browseSharedSettingsButton)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(downloadButton) - .addComponent(configButtonErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(1, 1, 1) - .addComponent(masterNodeCheckBox, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(uploadButton) - .addGap(8, 8, 8) - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabelCurrentTask) - .addComponent(jLabelTaskDescription)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(pbTaskInProgress, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - - jPanelIngestSettings.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jPanelIngestSettings.border.title"))); // NOI18N + tbOops.setEditable(false); + tbOops.setFont(tbOops.getFont().deriveFont(tbOops.getFont().getStyle() | java.awt.Font.BOLD, 12)); + tbOops.setForeground(new java.awt.Color(255, 0, 0)); + tbOops.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.tbOops.text")); // NOI18N + tbOops.setBorder(null); org.openide.awt.Mnemonics.setLocalizedText(bnEditIngestSettings, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.bnEditIngestSettings.text")); // NOI18N bnEditIngestSettings.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.bnEditIngestSettings.toolTipText")); // NOI18N @@ -949,46 +659,94 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } }); - javax.swing.GroupLayout jPanelIngestSettingsLayout = new javax.swing.GroupLayout(jPanelIngestSettings); - jPanelIngestSettings.setLayout(jPanelIngestSettingsLayout); - jPanelIngestSettingsLayout.setHorizontalGroup( - jPanelIngestSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelIngestSettingsLayout.createSequentialGroup() - .addContainerGap() - .addComponent(bnEditIngestSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnAdvancedSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnFileExport, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnLogging, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - jPanelIngestSettingsLayout.setVerticalGroup( - jPanelIngestSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelIngestSettingsLayout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanelIngestSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(bnEditIngestSettings) - .addComponent(bnFileExport) - .addComponent(bnAdvancedSettings) - .addComponent(bnLogging)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - - cbJoinAutoIngestCluster.setFont(cbJoinAutoIngestCluster.getFont().deriveFont(cbJoinAutoIngestCluster.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - org.openide.awt.Mnemonics.setLocalizedText(cbJoinAutoIngestCluster, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.cbJoinAutoIngestCluster.text")); // NOI18N - cbJoinAutoIngestCluster.addActionListener(new java.awt.event.ActionListener() { + org.openide.awt.Mnemonics.setLocalizedText(browseOutputFolderButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseOutputFolderButton.text")); // NOI18N + browseOutputFolderButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - cbJoinAutoIngestClusterActionPerformed(evt); + browseOutputFolderButtonActionPerformed(evt); } }); - tbOops.setEditable(false); - tbOops.setFont(tbOops.getFont().deriveFont(tbOops.getFont().getStyle() | java.awt.Font.BOLD, 12)); - tbOops.setForeground(new java.awt.Color(255, 0, 0)); - tbOops.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.tbOops.text")); // NOI18N - tbOops.setBorder(null); + org.openide.awt.Mnemonics.setLocalizedText(browseInputFolderButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseInputFolderButton.text")); // NOI18N + browseInputFolderButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + browseInputFolderButtonActionPerformed(evt); + } + }); + + inputPathTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.inputPathTextField.text")); // NOI18N + inputPathTextField.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.inputPathTextField.toolTipText")); // NOI18N + + outputPathTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.outputPathTextField.text")); // NOI18N + outputPathTextField.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.outputPathTextField.toolTipText")); // NOI18N + + jLabelInvalidResultsFolder.setForeground(new java.awt.Color(255, 0, 0)); + org.openide.awt.Mnemonics.setLocalizedText(jLabelInvalidResultsFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelInvalidResultsFolder.text")); // NOI18N + + jLabelInvalidImageFolder.setForeground(new java.awt.Color(255, 0, 0)); + org.openide.awt.Mnemonics.setLocalizedText(jLabelInvalidImageFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelInvalidImageFolder.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectInputFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelSelectInputFolder.text")); // NOI18N + jLabelSelectInputFolder.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM); + + org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectOutputFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelSelectOutputFolder.text")); // NOI18N + jLabelSelectOutputFolder.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM); + + org.openide.awt.Mnemonics.setLocalizedText(sharedConfigCheckbox, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedConfigCheckbox.text")); // NOI18N + sharedConfigCheckbox.setMaximumSize(new java.awt.Dimension(191, 14)); + sharedConfigCheckbox.setMinimumSize(new java.awt.Dimension(191, 14)); + sharedConfigCheckbox.setPreferredSize(new java.awt.Dimension(191, 14)); + sharedConfigCheckbox.addItemListener(new java.awt.event.ItemListener() { + public void itemStateChanged(java.awt.event.ItemEvent evt) { + sharedConfigCheckboxItemStateChanged(evt); + } + }); + + sharedSettingsErrorTextField.setEditable(false); + sharedSettingsErrorTextField.setForeground(new java.awt.Color(255, 0, 0)); + sharedSettingsErrorTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedSettingsErrorTextField.text")); // NOI18N + sharedSettingsErrorTextField.setBorder(null); + + sharedSettingsTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedSettingsTextField.text")); // NOI18N + sharedSettingsTextField.setEnabled(false); + + org.openide.awt.Mnemonics.setLocalizedText(browseSharedSettingsButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseSharedSettingsButton.text")); // NOI18N + browseSharedSettingsButton.setEnabled(false); + browseSharedSettingsButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + browseSharedSettingsButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(downloadButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.downloadButton.text")); // NOI18N + downloadButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + downloadButtonActionPerformed(evt); + } + }); + + configButtonErrorTextField.setEditable(false); + configButtonErrorTextField.setForeground(new java.awt.Color(255, 0, 0)); + configButtonErrorTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.configButtonErrorTextField.text")); // NOI18N + configButtonErrorTextField.setBorder(null); + + org.openide.awt.Mnemonics.setLocalizedText(jLabelTaskDescription, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelTaskDescription.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jLabelCurrentTask, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelCurrentTask.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(uploadButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.uploadButton.text")); // NOI18N + uploadButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + uploadButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(masterNodeCheckBox, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.masterNodeCheckBox.text")); // NOI18N + masterNodeCheckBox.setEnabled(false); + masterNodeCheckBox.addItemListener(new java.awt.event.ItemListener() { + public void itemStateChanged(java.awt.event.ItemEvent evt) { + masterNodeCheckBoxItemStateChanged(evt); + } + }); javax.swing.GroupLayout nodePanelLayout = new javax.swing.GroupLayout(nodePanel); nodePanel.setLayout(nodePanelLayout); @@ -998,14 +756,56 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { .addContainerGap() .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(nodePanelLayout.createSequentialGroup() - .addComponent(cbJoinAutoIngestCluster, javax.swing.GroupLayout.PREFERRED_SIZE, 171, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabelCurrentTask) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jLabelTaskDescription, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(outputPathTextField, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(inputPathTextField, javax.swing.GroupLayout.Alignment.LEADING)) + .addGap(10, 10, 10) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(browseInputFolderButton, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(browseOutputFolderButton, javax.swing.GroupLayout.Alignment.TRAILING))) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(jLabelSelectInputFolder) .addGap(18, 18, 18) - .addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, 465, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(jPanelNodeType, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jPanelSharedConfig, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jPanelIngestSettings, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(jLabelInvalidImageFolder, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(uploadButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(pbTaskInProgress, javax.swing.GroupLayout.PREFERRED_SIZE, 695, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(masterNodeCheckBox) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(cbJoinAutoIngestCluster, javax.swing.GroupLayout.PREFERRED_SIZE, 171, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, 465, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(bnEditIngestSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bnAdvancedSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bnFileExport, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bnLogging, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(jLabelSelectOutputFolder) + .addGap(18, 18, 18) + .addComponent(jLabelInvalidResultsFolder, javax.swing.GroupLayout.PREFERRED_SIZE, 544, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(sharedConfigCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(sharedSettingsErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(sharedSettingsTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 400, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(browseSharedSettingsButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(downloadButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(configButtonErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 396, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGap(0, 32, Short.MAX_VALUE))) + .addContainerGap()) ); nodePanelLayout.setVerticalGroup( nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -1014,12 +814,51 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(cbJoinAutoIngestCluster) .addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(3, 3, 3) - .addComponent(jPanelNodeType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabelSelectInputFolder) + .addComponent(jLabelInvalidImageFolder)) + .addGap(1, 1, 1) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(inputPathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(browseInputFolderButton)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jPanelIngestSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 62, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabelSelectOutputFolder, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabelInvalidResultsFolder)) + .addGap(1, 1, 1) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(browseOutputFolderButton) + .addComponent(outputPathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(25, 25, 25) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(bnEditIngestSettings) + .addComponent(bnFileExport) + .addComponent(bnAdvancedSettings) + .addComponent(bnLogging)) + .addGap(18, 18, 18) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(sharedConfigCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(sharedSettingsErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jPanelSharedConfig, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(sharedSettingsTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(browseSharedSettingsButton)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(downloadButton) + .addComponent(configButtonErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(18, 18, 18) + .addComponent(masterNodeCheckBox, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(uploadButton) + .addGap(8, 8, 8) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabelCurrentTask) + .addComponent(jLabelTaskDescription)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(pbTaskInProgress, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(161, Short.MAX_VALUE)) ); nodeScrollPane.setViewportView(nodePanel); @@ -1039,31 +878,35 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { ); }// //GEN-END:initComponents - private void browseSharedSettingsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseSharedSettingsButtonActionPerformed - - String oldText = sharedSettingsTextField.getText().trim(); - // set the current directory of the FileChooser if the oldText is valid - File currentDir = new File(oldText); - if (currentDir.exists()) { - fc.setCurrentDirectory(currentDir); - } - - fc.setDialogTitle("Select shared configuration folder:"); - fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - - int retval = fc.showOpenDialog(this); - if (retval == JFileChooser.APPROVE_OPTION) { - String path = fc.getSelectedFile().getPath(); - sharedSettingsTextField.setText(path); - validateSettings(); - controller.changed(); - } - }//GEN-LAST:event_browseSharedSettingsButtonActionPerformed - boolean permissionsAppropriate(String path) { return FileUtil.hasReadWriteAccess(Paths.get(path)); } + private void setSharedConfigEnable() { + setEnabledStateForSharedConfiguration(); + if (sharedConfigCheckbox.isEnabled() && sharedConfigCheckbox.isSelected()) { + sharedSettingsTextField.setEnabled(true); + browseSharedSettingsButton.setEnabled(true); + masterNodeCheckBox.setEnabled(true); + downloadButton.setEnabled(true); + validateSettings(); + controller.changed(); + } else { + sharedSettingsTextField.setEnabled(false); + browseSharedSettingsButton.setEnabled(false); + masterNodeCheckBox.setEnabled(false); + downloadButton.setEnabled(false); + sharedSettingsErrorTextField.setText(""); + validateSettings(); + controller.changed(); + } + } + + private void cbJoinAutoIngestClusterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbJoinAutoIngestClusterActionPerformed + enableOptionsBasedOnMode(getModeFromRadioButtons()); + controller.changed(); + }//GEN-LAST:event_cbJoinAutoIngestClusterActionPerformed + private void downloadButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_downloadButtonActionPerformed // First save the shared config folder and solr settings to the properties String globalSettingsPath = getNormalizedFolderPath(sharedSettingsTextField.getText().trim()); @@ -1100,31 +943,6 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } }//GEN-LAST:event_uploadButtonActionPerformed - private void sharedConfigCheckboxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_sharedConfigCheckboxItemStateChanged - // Enable the global settings text box and browse button iff the checkbox is checked and enabled - setSharedConfigEnable(); - }//GEN-LAST:event_sharedConfigCheckboxItemStateChanged - - private void setSharedConfigEnable() { - setEnabledStateForSharedConfiguration(); - if (sharedConfigCheckbox.isEnabled() && sharedConfigCheckbox.isSelected() && jRadioButtonAutomated.isSelected()) { - sharedSettingsTextField.setEnabled(true); - browseSharedSettingsButton.setEnabled(true); - masterNodeCheckBox.setEnabled(true); - downloadButton.setEnabled(true); - validateSettings(); - controller.changed(); - } else { - sharedSettingsTextField.setEnabled(false); - browseSharedSettingsButton.setEnabled(false); - masterNodeCheckBox.setEnabled(false); - downloadButton.setEnabled(false); - sharedSettingsErrorTextField.setText(""); - validateSettings(); - controller.changed(); - } - } - private void masterNodeCheckBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_masterNodeCheckBoxItemStateChanged // Enable the global settings text box and browse button iff the checkbox is checked and enabled setEnabledStateForSharedConfiguration(); @@ -1137,10 +955,31 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } }//GEN-LAST:event_masterNodeCheckBoxItemStateChanged - private void cbJoinAutoIngestClusterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbJoinAutoIngestClusterActionPerformed - enableOptionsBasedOnMode(getModeFromRadioButtons()); - controller.changed(); - }//GEN-LAST:event_cbJoinAutoIngestClusterActionPerformed + private void browseSharedSettingsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseSharedSettingsButtonActionPerformed + + String oldText = sharedSettingsTextField.getText().trim(); + // set the current directory of the FileChooser if the oldText is valid + File currentDir = new File(oldText); + if (currentDir.exists()) { + fc.setCurrentDirectory(currentDir); + } + + fc.setDialogTitle("Select shared configuration folder:"); + fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + + int retval = fc.showOpenDialog(this); + if (retval == JFileChooser.APPROVE_OPTION) { + String path = fc.getSelectedFile().getPath(); + sharedSettingsTextField.setText(path); + validateSettings(); + controller.changed(); + } + }//GEN-LAST:event_browseSharedSettingsButtonActionPerformed + + private void sharedConfigCheckboxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_sharedConfigCheckboxItemStateChanged + // Enable the global settings text box and browse button iff the checkbox is checked and enabled + setSharedConfigEnable(); + }//GEN-LAST:event_sharedConfigCheckboxItemStateChanged private void browseOutputFolderButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseOutputFolderButtonActionPerformed String oldText = outputPathTextField.getText().trim(); @@ -1182,24 +1021,6 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } }//GEN-LAST:event_browseInputFolderButtonActionPerformed - private void jRadioButtonReviewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButtonReviewActionPerformed - if (cbJoinAutoIngestCluster.isSelected()) { - enableOptionsBasedOnMode(OptionsUiMode.REVIEW); - setSharedConfigEnable(); - validateSettings(); - controller.changed(); - } - }//GEN-LAST:event_jRadioButtonReviewActionPerformed - - private void jRadioButtonAutomatedActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButtonAutomatedActionPerformed - if (cbJoinAutoIngestCluster.isSelected()) { - enableOptionsBasedOnMode(OptionsUiMode.AIM); - setSharedConfigEnable(); - validateSettings(); - controller.changed(); - } - }//GEN-LAST:event_jRadioButtonAutomatedActionPerformed - private void bnLoggingActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnLoggingActionPerformed JDialog jDialog = new JDialog(); NodeStatusLogPanel loggingPanel = new NodeStatusLogPanel(jDialog); @@ -1242,9 +1063,9 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { private void bnAdvancedSettingsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnAdvancedSettingsActionPerformed AdvancedAutoIngestSettingsPanel advancedAutoIngestSettingsPanel = new AdvancedAutoIngestSettingsPanel(getModeFromRadioButtons()); if (JOptionPane.showConfirmDialog(null, advancedAutoIngestSettingsPanel, - NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.AdvancedAutoIngestSettingsPanel.Title"), - JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE) == JOptionPane.OK_OPTION) { - advancedAutoIngestSettingsPanel.store(); + NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.AdvancedAutoIngestSettingsPanel.Title"), + JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE) == JOptionPane.OK_OPTION) { + advancedAutoIngestSettingsPanel.store(); } }//GEN-LAST:event_bnAdvancedSettingsActionPerformed @@ -1349,7 +1170,7 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } void setEnabledStateForSharedConfiguration() { - if (jRadioButtonAutomated.isSelected() && cbJoinAutoIngestCluster.isSelected()) { + if (cbJoinAutoIngestCluster.isSelected()) { enableOptionsBasedOnMode(OptionsUiMode.AIM); } } @@ -1361,19 +1182,13 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { bnLogging.setEnabled(enabled); browseInputFolderButton.setEnabled(enabled); browseOutputFolderButton.setEnabled(enabled); - browseSharedSettingsButton.setEnabled(sharedConfigCheckbox.isSelected() && jRadioButtonAutomated.isSelected()); + browseSharedSettingsButton.setEnabled(sharedConfigCheckbox.isSelected() && cbJoinAutoIngestCluster.isSelected()); configButtonErrorTextField.setEnabled(enabled); inputPathTextField.setEnabled(enabled); jLabelInvalidImageFolder.setEnabled(enabled); jLabelInvalidResultsFolder.setEnabled(enabled); jLabelSelectInputFolder.setEnabled(enabled); - jLabelSelectMode.setEnabled(enabled); jLabelSelectOutputFolder.setEnabled(enabled); - jPanelIngestSettings.setEnabled(enabled); - jPanelNodeType.setEnabled(enabled); - jPanelSharedConfig.setEnabled(enabled); - jRadioButtonAutomated.setEnabled(enabled); - jRadioButtonReview.setEnabled(enabled); outputPathTextField.setEnabled(enabled); } @@ -1389,20 +1204,12 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { private javax.swing.JTextField configButtonErrorTextField; private javax.swing.JButton downloadButton; private javax.swing.JTextField inputPathTextField; - private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabelCurrentTask; private javax.swing.JLabel jLabelInvalidImageFolder; private javax.swing.JLabel jLabelInvalidResultsFolder; private javax.swing.JLabel jLabelSelectInputFolder; - private javax.swing.JLabel jLabelSelectMode; private javax.swing.JLabel jLabelSelectOutputFolder; private javax.swing.JLabel jLabelTaskDescription; - private javax.swing.JPanel jPanelIngestSettings; - private javax.swing.JPanel jPanelNodeType; - private javax.swing.JPanel jPanelSharedConfig; - private javax.swing.JRadioButton jRadioButtonAutomated; - private javax.swing.JRadioButton jRadioButtonReview; - private javax.swing.JSeparator jSeparator1; private javax.swing.JCheckBox masterNodeCheckBox; private javax.swing.ButtonGroup modeRadioButtons; private javax.swing.JPanel nodePanel; From 9b69a2a75a62c75d824bfc109d7308917751cedd Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 23 Oct 2017 14:53:24 -0400 Subject: [PATCH 003/115] 3153 enabled sorting of of AID tables and added Priority column to pending jobs --- .../autoingest/AutoIngestControlPanel.form | 3 - .../autoingest/AutoIngestControlPanel.java | 105 ++++++++++-------- 2 files changed, 57 insertions(+), 51 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.form index ad525e92ee..cec9d21492 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.form @@ -169,7 +169,6 @@ - @@ -193,7 +192,6 @@ - @@ -217,7 +215,6 @@ - diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java index 891975223a..d87efb41ff 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java @@ -49,6 +49,7 @@ import javax.swing.UIManager; import javax.swing.event.ListSelectionEvent; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableColumn; +import javax.swing.table.TableModel; import org.netbeans.api.options.OptionsDisplayer; import org.openide.DialogDisplayer; import org.openide.LifecycleManager; @@ -138,6 +139,8 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { private static final int GENERIC_COL_MAX_WIDTH = 2000; private static final int PENDING_TABLE_COL_PREFERRED_WIDTH = 280; private static final int RUNNING_TABLE_COL_PREFERRED_WIDTH = 175; + private static final int PRIORITY_COLUMN_PREFERRED_WIDTH = 50; + private static final int PRIORITY_COLUMN_MAX_WIDTH=150; private static final int ACTIVITY_TIME_COL_MIN_WIDTH = 250; private static final int ACTIVITY_TIME_COL_MAX_WIDTH = 450; private static final int TIME_COL_MIN_WIDTH = 30; @@ -177,6 +180,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { * ordinal or a column header string. */ @Messages({ + "AutoIngestControlPanel.JobsTableModel.ColumnHeader.Priority=Priority", "AutoIngestControlPanel.JobsTableModel.ColumnHeader.Case=Case", "AutoIngestControlPanel.JobsTableModel.ColumnHeader.ImageFolder=Data Source", "AutoIngestControlPanel.JobsTableModel.ColumnHeader.HostName=Host Name", @@ -203,8 +207,8 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { STATUS(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.JobsTableModel.ColumnHeader.Status")), CASE_DIRECTORY_PATH(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.JobsTableModel.ColumnHeader.CaseFolder")), IS_LOCAL_JOB(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.JobsTableModel.ColumnHeader.LocalJob")), - MANIFEST_FILE_PATH(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.JobsTableModel.ColumnHeader.ManifestFilePath")); - + MANIFEST_FILE_PATH(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.JobsTableModel.ColumnHeader.ManifestFilePath")), + PRIORITY(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.JobsTableModel.ColumnHeader.Priority")); private final String header; private JobsTableModelColumns(String header) { @@ -227,7 +231,8 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { STAGE_TIME.getColumnHeader(), CASE_DIRECTORY_PATH.getColumnHeader(), IS_LOCAL_JOB.getColumnHeader(), - MANIFEST_FILE_PATH.getColumnHeader()}; + MANIFEST_FILE_PATH.getColumnHeader(), + PRIORITY.getColumnHeader()}; } /** @@ -411,11 +416,16 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { column.setMaxWidth(TIME_COL_MAX_WIDTH); column.setPreferredWidth(TIME_COL_PREFERRED_WIDTH); column.setWidth(TIME_COL_PREFERRED_WIDTH); + + column = pendingTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader()); + column.setMaxWidth(PRIORITY_COLUMN_MAX_WIDTH); + column.setPreferredWidth(PRIORITY_COLUMN_PREFERRED_WIDTH); + column.setWidth(PRIORITY_COLUMN_PREFERRED_WIDTH); /** * Prevent sorting when a column header is clicked. */ - pendingTable.setAutoCreateRowSorter(false); + pendingTable.setAutoCreateRowSorter(true); /* * Create a row selection listener to enable/disable the prioritize @@ -454,7 +464,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader())); runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.IS_LOCAL_JOB.getColumnHeader())); runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader())); - + runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader())); /* * Set up a column to display the cases associated with the jobs. */ @@ -524,9 +534,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { } private void updateRunningTableButtonsBasedOnSelectedRow() { - int row = runningTable.getSelectedRow(); + int row = runningTable.convertRowIndexToModel(runningTable.getSelectedRow()); if (row >= 0 && row < runningTable.getRowCount()) { - if ((boolean) runningTableModel.getValueAt(row, JobsTableModelColumns.IS_LOCAL_JOB.ordinal())) { + if ((boolean) runningTable.getModel().getValueAt(row, JobsTableModelColumns.IS_LOCAL_JOB.ordinal())) { enableRunningTableButtons(true); return; } @@ -550,7 +560,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.HOST_NAME.getColumnHeader())); completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader())); completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader())); - + completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader())); /* * Set up a column to display the cases associated with the jobs. */ @@ -605,7 +615,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { /* * Prevent sorting when a column header is clicked. */ - completedTable.setAutoCreateRowSorter(false); + completedTable.setAutoCreateRowSorter(true); /* * Create a row selection listener to enable/disable the delete case and @@ -1030,9 +1040,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { */ if (null != pendingJobs) { - Path currentRow = getSelectedEntry(pendingTable, pendingTableModel); - refreshTable(pendingJobs, pendingTableModel, null); - setSelectedEntry(pendingTable, pendingTableModel, currentRow); + Path currentRow = getSelectedEntry(pendingTable); + refreshTable(pendingJobs, (DefaultTableModel)pendingTable.getModel(), null); + setSelectedEntry(pendingTable, currentRow); } if (null != runningJobs) { @@ -1041,15 +1051,15 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { } else { updateRunningTableButtonsBasedOnSelectedRow(); } - Path currentRow = getSelectedEntry(runningTable, runningTableModel); - refreshTable(runningJobs, runningTableModel, null); - setSelectedEntry(runningTable, runningTableModel, currentRow); + Path currentRow = getSelectedEntry(runningTable); + refreshTable(runningJobs, (DefaultTableModel)runningTable.getModel(), null); + setSelectedEntry(runningTable, currentRow); } if (null != completedJobs) { - Path currentRow = getSelectedEntry(completedTable, completedTableModel); - refreshTable(completedJobs, completedTableModel, null); - setSelectedEntry(completedTable, completedTableModel, currentRow); + Path currentRow = getSelectedEntry(completedTable); + refreshTable(completedJobs, (DefaultTableModel)completedTable.getModel(), null); + setSelectedEntry(completedTable, currentRow); } } @@ -1087,12 +1097,12 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { * * @return a path representing the current selection */ - Path getSelectedEntry(JTable table, DefaultTableModel tableModel) { + Path getSelectedEntry(JTable table) { try { - int currentlySelectedRow = table.getSelectedRow(); + int currentlySelectedRow = table.convertRowIndexToModel(table.getSelectedRow()); if (currentlySelectedRow >= 0 && currentlySelectedRow < table.getRowCount()) { - return Paths.get(tableModel.getValueAt(currentlySelectedRow, JobsTableModelColumns.CASE.ordinal()).toString(), - tableModel.getValueAt(currentlySelectedRow, JobsTableModelColumns.DATA_SOURCE.ordinal()).toString()); + return Paths.get(table.getModel().getValueAt(currentlySelectedRow, JobsTableModelColumns.CASE.ordinal()).toString(), + table.getModel().getValueAt(currentlySelectedRow, JobsTableModelColumns.DATA_SOURCE.ordinal()).toString()); } } catch (Exception ignored) { return null; @@ -1108,12 +1118,12 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { * @param tableModel The tableModel of the table to set * @param path The path of the item to set */ - void setSelectedEntry(JTable table, DefaultTableModel tableModel, Path path) { + void setSelectedEntry(JTable table, Path path) { if (path != null) { try { for (int row = 0; row < table.getRowCount(); ++row) { - Path temp = Paths.get(tableModel.getValueAt(row, JobsTableModelColumns.CASE.ordinal()).toString(), - tableModel.getValueAt(row, JobsTableModelColumns.DATA_SOURCE.ordinal()).toString()); + Path temp = Paths.get(table.getModel().getValueAt(row, JobsTableModelColumns.CASE.ordinal()).toString(), + table.getModel().getValueAt(row, JobsTableModelColumns.DATA_SOURCE.ordinal()).toString()); if (temp.compareTo(path) == 0) { // found it table.setRowSelectionInterval(row, row); return; @@ -1156,7 +1166,8 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { ((Date.from(Instant.now()).getTime()) - (status.getStartDate().getTime())), // ACTIVITY_TIME job.getCaseDirectoryPath(), // CASE_DIRECTORY_PATH job.getProcessingHostName().equals(LOCAL_HOST_NAME), // IS_LOCAL_JOB - job.getManifest().getFilePath()}); // MANIFEST_FILE_PATH + job.getManifest().getFilePath(), + job.getPriority()}); // MANIFEST_FILE_PATH } } catch (Exception ex) { SYS_LOGGER.log(Level.SEVERE, "Dashboard error refreshing table", ex); @@ -1168,9 +1179,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { */ private void refreshTables() { JobsSnapshot jobsSnapshot = manager.getCurrentJobsSnapshot(); - refreshTable(jobsSnapshot.getCompletedJobs(), completedTableModel, null); - refreshTable(jobsSnapshot.getPendingJobs(), pendingTableModel, null); - refreshTable(jobsSnapshot.getRunningJobs(), runningTableModel, null); + refreshTable(jobsSnapshot.getCompletedJobs(), (DefaultTableModel)completedTable.getModel(), null); + refreshTable(jobsSnapshot.getPendingJobs(), (DefaultTableModel)pendingTable.getModel(), null); + refreshTable(jobsSnapshot.getRunningJobs(), (DefaultTableModel)runningTable.getModel(), null); } /** @@ -1211,7 +1222,6 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { pendingTable.setModel(pendingTableModel); pendingTable.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.pendingTable.toolTipText")); // NOI18N - pendingTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS); pendingTable.setRowHeight(20); pendingTable.setSelectionModel(new DefaultListSelectionModel() { private static final long serialVersionUID = 1L; @@ -1229,7 +1239,6 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { runningTable.setModel(runningTableModel); runningTable.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.runningTable.toolTipText")); // NOI18N - runningTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS); runningTable.setRowHeight(20); runningTable.setSelectionModel(new DefaultListSelectionModel() { private static final long serialVersionUID = 1L; @@ -1247,7 +1256,6 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { completedTable.setModel(completedTableModel); completedTable.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.completedTable.toolTipText")); // NOI18N - completedTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS); completedTable.setRowHeight(20); completedTable.setSelectionModel(new DefaultListSelectionModel() { private static final long serialVersionUID = 1L; @@ -1425,10 +1433,10 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { .addComponent(completedScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 920, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(bnCancelJob, javax.swing.GroupLayout.DEFAULT_SIZE, 117, Short.MAX_VALUE) - .addComponent(bnShowProgress, javax.swing.GroupLayout.DEFAULT_SIZE, 116, Short.MAX_VALUE) - .addComponent(bnCancelModule, javax.swing.GroupLayout.DEFAULT_SIZE, 117, Short.MAX_VALUE) - .addComponent(bnDeleteCase, javax.swing.GroupLayout.DEFAULT_SIZE, 117, Short.MAX_VALUE) + .addComponent(bnCancelJob, javax.swing.GroupLayout.PREFERRED_SIZE, 117, Short.MAX_VALUE) + .addComponent(bnShowProgress, javax.swing.GroupLayout.PREFERRED_SIZE, 116, Short.MAX_VALUE) + .addComponent(bnCancelModule, javax.swing.GroupLayout.PREFERRED_SIZE, 117, Short.MAX_VALUE) + .addComponent(bnDeleteCase, javax.swing.GroupLayout.PREFERRED_SIZE, 117, Short.MAX_VALUE) .addComponent(bnShowCaseLog, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(bnReprocessJob, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) .addGroup(layout.createSequentialGroup() @@ -1535,11 +1543,11 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { "AutoIngestControlPanel.DeletionFailed=Deletion failed for job" }) private void bnDeleteCaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnDeleteCaseActionPerformed - if (completedTableModel.getRowCount() < 0 || completedTable.getSelectedRow() < 0) { + if (completedTable.getModel().getRowCount() < 0 || completedTable.getSelectedRow() < 0) { return; } - String caseName = (String) completedTable.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal()); + String caseName = (String) completedTable.getModel().getValueAt(completedTable.convertRowIndexToModel(completedTable.getSelectedRow()), JobsTableModelColumns.CASE.ordinal()); Object[] options = { org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "ConfirmationDialog.Delete"), org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "ConfirmationDialog.DoNotDelete") @@ -1556,8 +1564,8 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { if (reply == JOptionPane.YES_OPTION) { bnDeleteCase.setEnabled(false); bnShowCaseLog.setEnabled(false); - if (completedTableModel.getRowCount() > 0 && completedTable.getSelectedRow() >= 0) { - Path caseDirectoryPath = (Path) completedTableModel.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.CASE_DIRECTORY_PATH.ordinal()); + if (completedTable.getModel().getRowCount() > 0 && completedTable.getSelectedRow() >= 0) { + Path caseDirectoryPath = (Path) completedTable.getModel().getValueAt(completedTable.convertRowIndexToModel(completedTable.getSelectedRow()), JobsTableModelColumns.CASE_DIRECTORY_PATH.ordinal()); completedTable.clearSelection(); this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); CaseDeletionResult result = manager.deleteCase(caseName, caseDirectoryPath); @@ -1703,9 +1711,10 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { */ @Messages({"AutoIngestControlPanel.casePrioritization.errorMessage=An error occurred when prioritizing the case. Some or all jobs may not have been prioritized."}) private void bnPrioritizeCaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPrioritizeCaseActionPerformed - if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { + if (pendingTable.getModel().getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - String caseName = (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal())).toString(); + + String caseName = (pendingTable.getModel().getValueAt(pendingTable.convertRowIndexToModel(pendingTable.getSelectedRow()), JobsTableModelColumns.CASE.ordinal())).toString(); try { manager.prioritizeCase(caseName); } catch (AutoIngestManager.AutoIngestManagerException ex) { @@ -1731,9 +1740,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { }) private void bnShowCaseLogActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnShowCaseLogActionPerformed try { - int selectedRow = completedTable.getSelectedRow(); + int selectedRow = completedTable.convertRowIndexToModel(completedTable.getSelectedRow()); if (selectedRow != -1) { - Path caseDirectoryPath = (Path) completedTableModel.getValueAt(selectedRow, JobsTableModelColumns.CASE_DIRECTORY_PATH.ordinal()); + Path caseDirectoryPath = (Path) completedTable.getModel().getValueAt(selectedRow, JobsTableModelColumns.CASE_DIRECTORY_PATH.ordinal()); if (null != caseDirectoryPath) { Path pathToLog = AutoIngestJobLogger.getLogPath(caseDirectoryPath); if (pathToLog.toFile().exists()) { @@ -1762,9 +1771,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { @Messages({"AutoIngestControlPanel.jobPrioritization.errorMessage=An error occurred when prioritizing the job."}) private void bnPrioritizeJobActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPrioritizeJobActionPerformed - if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { + if (pendingTable.getModel().getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - Path manifestFilePath = (Path) (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal())); + Path manifestFilePath = (Path) (pendingTable.getModel().getValueAt(pendingTable.convertRowIndexToModel(pendingTable.getSelectedRow()), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal())); try { manager.prioritizeJob(manifestFilePath); } catch (AutoIngestManager.AutoIngestManagerException ex) { @@ -1791,11 +1800,11 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { }//GEN-LAST:event_bnOpenLogDirActionPerformed private void bnReprocessJobActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnReprocessJobActionPerformed - if (completedTableModel.getRowCount() < 0 || completedTable.getSelectedRow() < 0) { + if (completedTable.getModel().getRowCount() < 0 || completedTable.getSelectedRow() < 0) { return; } this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - Path manifestPath = (Path) completedTableModel.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal()); + Path manifestPath = (Path) completedTable.getModel().getValueAt(completedTable.convertRowIndexToModel(completedTable.getSelectedRow()), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal()); manager.reprocessJob(manifestPath); refreshTables(); AutoIngestControlPanel.this.setCursor(Cursor.getDefaultCursor()); From 9b5dca32ae6604ef941b8096d3ad12308fb28e4c Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 23 Oct 2017 18:18:03 -0400 Subject: [PATCH 004/115] 3153 fixed issue with completed jobs re-ordering upon reprocess --- .../autoingest/AutoIngestControlPanel.java | 39 +++++++++++-------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java index d87efb41ff..22b758f2fc 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java @@ -39,17 +39,19 @@ import javax.swing.DefaultListSelectionModel; import java.awt.Color; import java.beans.PropertyChangeEvent; import java.io.File; -import java.util.Collections; + import java.util.logging.Logger; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTable; +import javax.swing.RowSorter; +import static javax.swing.SortOrder.DESCENDING; import javax.swing.SwingWorker; import javax.swing.UIManager; import javax.swing.event.ListSelectionEvent; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableColumn; -import javax.swing.table.TableModel; +import javax.swing.table.TableRowSorter; import org.netbeans.api.options.OptionsDisplayer; import org.openide.DialogDisplayer; import org.openide.LifecycleManager; @@ -140,7 +142,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { private static final int PENDING_TABLE_COL_PREFERRED_WIDTH = 280; private static final int RUNNING_TABLE_COL_PREFERRED_WIDTH = 175; private static final int PRIORITY_COLUMN_PREFERRED_WIDTH = 50; - private static final int PRIORITY_COLUMN_MAX_WIDTH=150; + private static final int PRIORITY_COLUMN_MAX_WIDTH = 150; private static final int ACTIVITY_TIME_COL_MIN_WIDTH = 250; private static final int ACTIVITY_TIME_COL_MAX_WIDTH = 450; private static final int TIME_COL_MIN_WIDTH = 30; @@ -290,7 +292,6 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { return false; } }; - initComponents(); // Generated code. setServicesStatusMessage(); initPendingJobsTable(); @@ -298,6 +299,13 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { initCompletedJobsTable(); initButtons(); + @SuppressWarnings("unchecked") + TableRowSorter sorter = (TableRowSorter) completedTable.getRowSorter(); + List list = new ArrayList<>(); + list.add(new RowSorter.SortKey(JobsTableModelColumns.COMPLETED_TIME.ordinal(), DESCENDING)); + sorter.setSortKeys(list); + sorter.sort(); + /* * Must set this flag, otherwise pop up menus don't close properly. */ @@ -416,7 +424,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { column.setMaxWidth(TIME_COL_MAX_WIDTH); column.setPreferredWidth(TIME_COL_PREFERRED_WIDTH); column.setWidth(TIME_COL_PREFERRED_WIDTH); - + column = pendingTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader()); column.setMaxWidth(PRIORITY_COLUMN_MAX_WIDTH); column.setPreferredWidth(PRIORITY_COLUMN_PREFERRED_WIDTH); @@ -554,10 +562,10 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { * does not remove the columns from the model, just from this table. */ completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.STARTED_TIME.getColumnHeader())); + completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.HOST_NAME.getColumnHeader())); completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.STAGE.getColumnHeader())); completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.STAGE_TIME.getColumnHeader())); completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.IS_LOCAL_JOB.getColumnHeader())); - completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.HOST_NAME.getColumnHeader())); completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader())); completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader())); completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader())); @@ -992,7 +1000,6 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { List completedJobs = new ArrayList<>(); manager.getJobs(pendingJobs, runningJobs, completedJobs); // Sort the completed jobs list by completed date - Collections.sort(completedJobs, new AutoIngestJob.CompletedDateDescendingComparator()); EventQueue.invokeLater(new RefreshComponentsTask(pendingJobs, runningJobs, completedJobs)); } } @@ -1041,7 +1048,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { if (null != pendingJobs) { Path currentRow = getSelectedEntry(pendingTable); - refreshTable(pendingJobs, (DefaultTableModel)pendingTable.getModel(), null); + refreshTable(pendingJobs, (DefaultTableModel) pendingTable.getModel(), null); setSelectedEntry(pendingTable, currentRow); } @@ -1052,14 +1059,14 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { updateRunningTableButtonsBasedOnSelectedRow(); } Path currentRow = getSelectedEntry(runningTable); - refreshTable(runningJobs, (DefaultTableModel)runningTable.getModel(), null); - setSelectedEntry(runningTable, currentRow); + refreshTable(runningJobs, (DefaultTableModel) runningTable.getModel(), null); + setSelectedEntry(runningTable, currentRow); } if (null != completedJobs) { Path currentRow = getSelectedEntry(completedTable); - refreshTable(completedJobs, (DefaultTableModel)completedTable.getModel(), null); - setSelectedEntry(completedTable, currentRow); + refreshTable(completedJobs, (DefaultTableModel) completedTable.getModel(), null); + setSelectedEntry(completedTable, currentRow); } } @@ -1179,9 +1186,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { */ private void refreshTables() { JobsSnapshot jobsSnapshot = manager.getCurrentJobsSnapshot(); - refreshTable(jobsSnapshot.getCompletedJobs(), (DefaultTableModel)completedTable.getModel(), null); - refreshTable(jobsSnapshot.getPendingJobs(), (DefaultTableModel)pendingTable.getModel(), null); - refreshTable(jobsSnapshot.getRunningJobs(), (DefaultTableModel)runningTable.getModel(), null); + refreshTable(jobsSnapshot.getCompletedJobs(), (DefaultTableModel) completedTable.getModel(), null); + refreshTable(jobsSnapshot.getPendingJobs(), (DefaultTableModel) pendingTable.getModel(), null); + refreshTable(jobsSnapshot.getRunningJobs(), (DefaultTableModel) runningTable.getModel(), null); } /** @@ -1713,7 +1720,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { private void bnPrioritizeCaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPrioritizeCaseActionPerformed if (pendingTable.getModel().getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - + String caseName = (pendingTable.getModel().getValueAt(pendingTable.convertRowIndexToModel(pendingTable.getSelectedRow()), JobsTableModelColumns.CASE.ordinal())).toString(); try { manager.prioritizeCase(caseName); From 3a555648d608fb3f6dab8653be1a5188e65a5504 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 24 Oct 2017 14:32:33 -0400 Subject: [PATCH 005/115] Minor clean-up and bug fixes. --- .../autopsy/casemodule/Bundle.properties | 18 ++++---- .../casemodule/CaseOpenMultiUserAction.java | 27 ++++++----- .../autopsy/casemodule/CueBannerPanel.java | 10 ++--- .../autopsy/casemodule/MultiUserCase.java | 45 ++++++++++++++----- .../casemodule/MultiUserCaseManager.java | 6 +++ ...asePanel.form => MultiUserCasesPanel.form} | 18 ++++---- ...asePanel.java => MultiUserCasesPanel.java} | 42 ++++++++--------- 7 files changed, 96 insertions(+), 70 deletions(-) rename Core/src/org/sleuthkit/autopsy/casemodule/{MultiUserCasePanel.form => MultiUserCasesPanel.form} (91%) rename Core/src/org/sleuthkit/autopsy/casemodule/{MultiUserCasePanel.java => MultiUserCasesPanel.java} (92%) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 6ce0c76f3d..d23d86d6f8 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -235,15 +235,15 @@ ReviewModeCasePanel.CreatedTimeHeaderText=Created Time ReviewModeCasePanel.StatusIconHeaderText=Status ReviewModeCasePanel.OutputFolderHeaderText=Output Folder ReviewModeCasePanel.LastAccessedTimeHeaderText=Last Accessed Time -MultiUserCasePanel.rbDays.text=Days -MultiUserCasePanel.rbWeeks.text=Weeks -MultiUserCasePanel.rbMonths.text=Months -MultiUserCasePanel.rbAllCases.text=Everything -MultiUserCasePanel.bnRefresh.text=&Refresh -MultiUserCasePanel.bnOpen.text=&Open -MultiUserCasePanel.bnShowLog.toolTipText=Display case log file for selected case -MultiUserCasePanel.bnShowLog.text=&Show Auto Ingest Case Log -MultiUserCasePanel.rbGroupLabel.text=Show cases accessed in the last 10: OpenMultiUserCasePanel.jLabel1.text=Recent Cases OpenMultiUserCasePanel.openButton.text=Open OpenMultiUserCasePanel.cancelButton.text=Cancel +MultiUserCasesPanel.rbWeeks.text=Weeks +MultiUserCasesPanel.rbDays.text=Days +MultiUserCasesPanel.bnShowLog.toolTipText=Display case log file for selected case +MultiUserCasesPanel.bnShowLog.text=&Show Auto Ingest Case Log +MultiUserCasesPanel.rbAllCases.text=Everything +MultiUserCasesPanel.bnRefresh.text=&Refresh +MultiUserCasesPanel.bnOpen.text=&Open +MultiUserCasesPanel.rbGroupLabel.text=Show cases accessed in the last 10: +MultiUserCasesPanel.rbMonths.text=Months diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java index aa9b0eac6a..4d3af01f26 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java @@ -31,16 +31,13 @@ import org.openide.awt.ActionRegistration; import org.openide.util.HelpCtx; import org.openide.util.NbBundle; import org.openide.util.actions.CallableSystemAction; -import org.openide.util.lookup.ServiceProvider; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.core.UserPreferences; -import static org.sleuthkit.autopsy.core.UserPreferences.SelectedMode.REVIEW; import org.sleuthkit.autopsy.coreutils.NetworkUtils; /** - * The action associated with the Case/Open Case menu item via the layer.xml - * file, a toolbar button, and the Create New Case button of the start up window - * that allows a user to open a case. It opens an existing case. + * The action associated with the Open Multi-User Case menu item via the + * layer.xml file. * * This action should only be invoked in the event dispatch thread (EDT). */ @@ -57,14 +54,13 @@ public final class CaseOpenMultiUserAction extends CallableSystemAction implemen private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName(); private static final String REVIEW_MODE_TITLE = "Open Multi-User Case (" + LOCAL_HOST_NAME + ")"; + public CaseOpenMultiUserAction() {} + /** - * Constructs the action associated with the Case/Open Case menu item via - * the layer.xml file, a toolbar button, and the Create New Case button of - * the start up window that allows a user to open a case. It opens an - * existing case. - * + * Constructs the Multi-User Cases window used by the Open Multi-User Case + * menu item. */ - public CaseOpenMultiUserAction() { + private void initMultiUserCasesWindow() { multiUserCaseWindow = new JDialog( WindowManager.getDefault().getMainWindow(), REVIEW_MODE_TITLE, @@ -74,7 +70,7 @@ public final class CaseOpenMultiUserAction extends CallableSystemAction implemen multiUserCaseWindow.setVisible(false); }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); - multiUserCaseWindow.add(new MultiUserCasePanel()); + multiUserCaseWindow.add(new MultiUserCasesPanel()); multiUserCaseWindow.pack(); multiUserCaseWindow.setResizable(false); } @@ -91,13 +87,16 @@ public final class CaseOpenMultiUserAction extends CallableSystemAction implemen } /** - * Pops up a file chooser to allow the user to select a case metadata file - * (.aut file) and attempts to open the case described by the file. + * Pops up a case selection panel to allow the user to selecte a multi-user + * case to open. * * @param e The action event. */ @Override public void actionPerformed(ActionEvent event) { + if(multiUserCaseWindow == null) { + initMultiUserCasesWindow(); + } multiUserCaseWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); multiUserCaseWindow.setVisible(true); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java index 48e54a3f9f..ff25e934cf 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java @@ -31,7 +31,6 @@ import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.core.UserPreferences; -import org.sleuthkit.autopsy.coreutils.NetworkUtils; /* * The panel in the default Autopsy startup window. @@ -39,8 +38,7 @@ import org.sleuthkit.autopsy.coreutils.NetworkUtils; public class CueBannerPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; - private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName(); - private static final String REVIEW_MODE_TITLE = "Open Multi-User Case (" + LOCAL_HOST_NAME + ")"; + private static final String REVIEW_MODE_TITLE = "Open Multi-User Case"; /* * This is field is static for the sake of the closeOpenRecentCasesWindow * method. @@ -91,7 +89,6 @@ public class CueBannerPanel extends javax.swing.JPanel { private void customizeComponents() { initRecentCasesWindow(); - initMultiUserCasesWindow(); } private void initRecentCasesWindow() { @@ -127,7 +124,7 @@ public class CueBannerPanel extends javax.swing.JPanel { multiUserCaseWindow.setVisible(false); }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); - multiUserCaseWindow.add(new MultiUserCasePanel()); + multiUserCaseWindow.add(new MultiUserCasesPanel()); multiUserCaseWindow.pack(); multiUserCaseWindow.setResizable(false); } @@ -306,6 +303,9 @@ public class CueBannerPanel extends javax.swing.JPanel { }//GEN-LAST:event_openRecentCaseButtonActionPerformed private void openMultiUserCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openMultiUserCaseButtonActionPerformed + if(multiUserCaseWindow == null) { + initMultiUserCasesWindow(); + } multiUserCaseWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); multiUserCaseWindow.setVisible(true); }//GEN-LAST:event_openMultiUserCaseButtonActionPerformed diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java index d1a2bc65da..453c0bb27f 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java @@ -18,9 +18,11 @@ */ package org.sleuthkit.autopsy.casemodule; +import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; import java.util.Comparator; import java.util.Date; @@ -47,10 +49,19 @@ class MultiUserCase implements Comparable { * * @param caseDirectoryPath The case directory path. */ - MultiUserCase(Path caseDirectoryPath) { + MultiUserCase(Path caseDirectoryPath) throws CaseMetadata.CaseMetadataException { + CaseMetadata caseMetadata = null; + + try { + caseMetadata = getCaseMetadataFromCaseDirectoryPath(caseDirectoryPath); + } catch (CaseMetadata.CaseMetadataException ex) { + logger.log(Level.SEVERE, String.format("Error reading the case metadata for %s.", caseDirectoryPath), ex); + throw ex; + } + this.caseDirectoryPath = caseDirectoryPath; - caseName = getCaseNameFromCaseDirectoryPath(caseDirectoryPath); - metadataFilePath = caseDirectoryPath.resolve(caseName + CaseMetadata.getFileExtension()); + caseName = caseMetadata.getCaseDisplayName(); + metadataFilePath = caseDirectoryPath.resolve(caseMetadata.getCaseName() + CaseMetadata.getFileExtension()); BasicFileAttributes fileAttrs = null; try { fileAttrs = Files.readAttributes(metadataFilePath, BasicFileAttributes.class); @@ -119,19 +130,29 @@ class MultiUserCase implements Comparable { } /** - * Extracts the case name from a case folder path. + * Gets the case metadata from a case directory path. * - * @param caseFolderPath A case folder path. + * @param caseDirectoryPath The case directory path. * - * @return A case name, with the time stamp suffix removed. + * @return Case metadata. */ - static String getCaseNameFromCaseDirectoryPath(Path caseFolderPath) { - String caseName = caseFolderPath.getFileName().toString(); - if (caseName.length() > TimeStampUtils.getTimeStampLength()) { - return caseName.substring(0, caseName.length() - TimeStampUtils.getTimeStampLength()); - } else { - return caseName; + static CaseMetadata getCaseMetadataFromCaseDirectoryPath(Path caseDirectoryPath) throws CaseMetadata.CaseMetadataException { + CaseMetadata caseMetadata = null; + + File directory = new File(caseDirectoryPath.toString()); + if (directory.isDirectory()) { + String fileNamePrefix = directory.getName(); + if (TimeStampUtils.endsWithTimeStamp(fileNamePrefix)) { + fileNamePrefix = fileNamePrefix.substring(0, fileNamePrefix.length() - TimeStampUtils.getTimeStampLength()); + } + + File file = new File(directory + "/" + fileNamePrefix + CaseMetadata.getFileExtension()); + if(file.isFile()) { + caseMetadata = new CaseMetadata(Paths.get(file.getAbsolutePath())); + } } + + return caseMetadata; } /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java index ec3b42116d..5fa8b80f7b 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java @@ -23,6 +23,8 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; @@ -78,7 +80,11 @@ final class MultiUserCaseManager { if(caseFolder.exists()) { File[] autFiles = caseFolder.listFiles((dir, name) -> name.toLowerCase().endsWith(".aut")); if(autFiles != null && autFiles.length > 0) { + try { cases.add(new MultiUserCase(casePath)); + } catch (CaseMetadata.CaseMetadataException ex) { + // Ignore and continue. + } } } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasePanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.form similarity index 91% rename from Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasePanel.form rename to Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.form index a54439c4d3..179bc23bb8 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasePanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.form @@ -82,7 +82,7 @@ - + @@ -118,7 +118,7 @@ - + @@ -153,7 +153,7 @@ - + @@ -165,10 +165,10 @@ - + - + @@ -182,7 +182,7 @@ - + @@ -196,7 +196,7 @@ - + @@ -209,7 +209,7 @@ - + @@ -222,7 +222,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java similarity index 92% rename from Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasePanel.java rename to Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java index 5f3365e8b1..6b20a41147 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java @@ -39,10 +39,10 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; /** * A panel that allows a user to open cases created by auto ingest. */ -public class MultiUserCasePanel extends javax.swing.JPanel { +public class MultiUserCasesPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; - private static final Logger LOGGER = Logger.getLogger(MultiUserCasePanel.class.getName()); + private static final Logger LOGGER = Logger.getLogger(MultiUserCasesPanel.class.getName()); private static final String LOG_FILE_NAME = "auto_ingest_log.txt"; private static final MultiUserCase.LastAccessedDateDescendingComparator REVERSE_DATE_MODIFIED_COMPARATOR = new MultiUserCase.LastAccessedDateDescendingComparator(); private static final int CASE_COL_MIN_WIDTH = 30; @@ -62,11 +62,11 @@ public class MultiUserCasePanel extends javax.swing.JPanel { * TODO (RC): Consider unifying this stuff in an enum as in * AutoIngestDashboard to make it less error prone. */ - private static final String CASE_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "ReviewModeCasePanel.CaseHeaderText"); - private static final String CREATEDTIME_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "ReviewModeCasePanel.CreatedTimeHeaderText"); - private static final String COMPLETEDTIME_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "ReviewModeCasePanel.LastAccessedTimeHeaderText"); - private static final String STATUS_ICON_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "ReviewModeCasePanel.StatusIconHeaderText"); - private static final String OUTPUT_FOLDER_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "ReviewModeCasePanel.OutputFolderHeaderText"); + private static final String CASE_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.CaseHeaderText"); + private static final String CREATEDTIME_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.CreatedTimeHeaderText"); + private static final String COMPLETEDTIME_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.LastAccessedTimeHeaderText"); + private static final String STATUS_ICON_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.StatusIconHeaderText"); + private static final String OUTPUT_FOLDER_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.OutputFolderHeaderText"); enum COLUMN_HEADERS { @@ -86,7 +86,7 @@ public class MultiUserCasePanel extends javax.swing.JPanel { * * @param parent The parent dialog for this panel. */ - MultiUserCasePanel() { + MultiUserCasesPanel() { caseTableModel = new DefaultTableModel(columnNames, 0) { private static final long serialVersionUID = 1L; @@ -326,7 +326,7 @@ public class MultiUserCasePanel extends javax.swing.JPanel { setName("Completed Cases"); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(bnOpen, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.bnOpen.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(bnOpen, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnOpen.text")); // NOI18N bnOpen.setEnabled(false); bnOpen.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -346,7 +346,7 @@ public class MultiUserCasePanel extends javax.swing.JPanel { }); scrollPaneTable.setViewportView(casesTable); - org.openide.awt.Mnemonics.setLocalizedText(bnRefresh, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.bnRefresh.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(bnRefresh, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnRefresh.text")); // NOI18N bnRefresh.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnRefreshActionPerformed(evt); @@ -355,7 +355,7 @@ public class MultiUserCasePanel extends javax.swing.JPanel { rbGroupHistoryLength.add(rbAllCases); rbAllCases.setSelected(true); - org.openide.awt.Mnemonics.setLocalizedText(rbAllCases, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.rbAllCases.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbAllCases, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbAllCases.text")); // NOI18N rbAllCases.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { rbAllCasesItemStateChanged(evt); @@ -377,8 +377,8 @@ public class MultiUserCasePanel extends javax.swing.JPanel { .addComponent(rbAllCases)) ); - org.openide.awt.Mnemonics.setLocalizedText(bnShowLog, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.bnShowLog.text")); // NOI18N - bnShowLog.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.bnShowLog.toolTipText")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(bnShowLog, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnShowLog.text")); // NOI18N + bnShowLog.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnShowLog.toolTipText")); // NOI18N bnShowLog.setEnabled(false); bnShowLog.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -387,7 +387,7 @@ public class MultiUserCasePanel extends javax.swing.JPanel { }); rbGroupHistoryLength.add(rbDays); - org.openide.awt.Mnemonics.setLocalizedText(rbDays, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.rbDays.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbDays, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbDays.text")); // NOI18N rbDays.setName(""); // NOI18N rbDays.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { @@ -396,7 +396,7 @@ public class MultiUserCasePanel extends javax.swing.JPanel { }); rbGroupHistoryLength.add(rbWeeks); - org.openide.awt.Mnemonics.setLocalizedText(rbWeeks, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.rbWeeks.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbWeeks, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbWeeks.text")); // NOI18N rbWeeks.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { rbWeeksItemStateChanged(evt); @@ -404,7 +404,7 @@ public class MultiUserCasePanel extends javax.swing.JPanel { }); rbGroupHistoryLength.add(rbMonths); - org.openide.awt.Mnemonics.setLocalizedText(rbMonths, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.rbMonths.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbMonths, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbMonths.text")); // NOI18N rbMonths.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { rbMonthsItemStateChanged(evt); @@ -412,7 +412,7 @@ public class MultiUserCasePanel extends javax.swing.JPanel { }); rbGroupLabel.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(rbGroupLabel, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.rbGroupLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbGroupLabel, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbGroupLabel.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -521,14 +521,14 @@ public class MultiUserCasePanel extends javax.swing.JPanel { Desktop.getDesktop().edit(pathToLog.toFile()); } else { - JOptionPane.showMessageDialog(this, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "DisplayLogDialog.cannotFindLog"), - org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "DisplayLogDialog.unableToShowLogFile"), JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(this, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.cannotFindLog"), + org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.unableToShowLogFile"), JOptionPane.ERROR_MESSAGE); } } catch (IOException ex) { LOGGER.log(Level.SEVERE, String.format("Error attempting to open case auto ingest log file %s", pathToLog), ex); JOptionPane.showMessageDialog(this, - org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "DisplayLogDialog.cannotOpenLog"), - org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "DisplayLogDialog.unableToShowLogFile"), + org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.cannotOpenLog"), + org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.unableToShowLogFile"), JOptionPane.PLAIN_MESSAGE); } } From 98609be8f92b00f5fbc7c299ebe2822c0af3adf0 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 24 Oct 2017 14:39:07 -0400 Subject: [PATCH 006/115] Removed unused imports. --- Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java | 1 - .../org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java | 2 -- 2 files changed, 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java index 453c0bb27f..6220b84a80 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java @@ -28,7 +28,6 @@ import java.util.Comparator; import java.util.Date; import java.util.Objects; import java.util.logging.Level; -import org.sleuthkit.autopsy.casemodule.CaseMetadata; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.TimeStampUtils; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java index 5fa8b80f7b..0975e60ce3 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java @@ -23,8 +23,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; From 8e8b957f4c9c965fa7ba95283c0fb1719c8a2d46 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 24 Oct 2017 15:17:57 -0400 Subject: [PATCH 007/115] Bug fix regarding assumed AUT filename. --- .../autopsy/casemodule/MultiUserCase.java | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java index 6220b84a80..6a9ae04c12 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java @@ -145,9 +145,30 @@ class MultiUserCase implements Comparable { fileNamePrefix = fileNamePrefix.substring(0, fileNamePrefix.length() - TimeStampUtils.getTimeStampLength()); } - File file = new File(directory + "/" + fileNamePrefix + CaseMetadata.getFileExtension()); - if(file.isFile()) { - caseMetadata = new CaseMetadata(Paths.get(file.getAbsolutePath())); + /* + * Attempt to open an AUT file that has the folder name without a + * time stamp. + */ + File autFile = new File(directory + "/" + fileNamePrefix + CaseMetadata.getFileExtension()); + + /* + * If the AUT file doesn't exist, attempt to find an AUT file via a + * directory scan. + */ + if(!autFile.isFile()) { + for (File file : directory.listFiles()) { + if (file.getName().toLowerCase().endsWith(CaseMetadata.getFileExtension()) && file.isFile()) { + autFile = file; + break; + } + } + } + + /* + * If the AUT file has been found, grab the case metadata. + */ + if(autFile.isFile()) { + caseMetadata = new CaseMetadata(Paths.get(autFile.getAbsolutePath())); } } From 935827122de95e24584d7617a5d7e283ed5c4c74 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Tue, 24 Oct 2017 16:59:16 -0400 Subject: [PATCH 008/115] Updated Java doc --- .../AutoIngestDataSourceProcessor.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/AutoIngestDataSourceProcessor.java b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/AutoIngestDataSourceProcessor.java index 11c0559795..163d164376 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/AutoIngestDataSourceProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/AutoIngestDataSourceProcessor.java @@ -43,9 +43,7 @@ public interface AutoIngestDataSourceProcessor extends DataSourceProcessor { * or less means the data source is not supported by the * DataSourceProcessor. Value of 100 indicates high certainty in * being able to process the data source. - * - * @throws - * org.sleuthkit.autopsy.corecomponentinterfaces.AutomatedIngestDataSourceProcessor.AutomatedIngestDataSourceProcessorException + * @throws org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException */ int canProcess(Path dataSourcePath) throws AutoIngestDataSourceProcessorException; @@ -65,9 +63,7 @@ public interface AutoIngestDataSourceProcessor extends DataSourceProcessor { * background task to report progress. * @param callBack Callback that will be used by the background task * to return results. - * - * @throws - * org.sleuthkit.autopsy.corecomponentinterfaces.AutomatedIngestDataSourceProcessor.AutomatedIngestDataSourceProcessorException + * @throws org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException */ void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) throws AutoIngestDataSourceProcessorException; From 112de482a4e3bfa7c09b5d450101ee22a094d7f7 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Tue, 24 Oct 2017 16:59:49 -0400 Subject: [PATCH 009/115] First cut at implementing the functionality of ArchiveDSP --- .../autoingest/AddArchiveTask.java | 70 +++++++++++++++++-- .../autoingest/AddDataSourceCallback.java | 7 ++ .../ArchiveExtractorDSProcessor.java | 8 +-- .../experimental/autoingest/ArchiveUtil.java | 7 +- .../autoingest/AutoIngestManager.java | 5 +- .../DataSourceProcessorUtility.java | 23 +++++- 6 files changed, 104 insertions(+), 16 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index 3bc76e61fd..42c208ad58 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -22,12 +22,17 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.UUID; import java.util.logging.Level; import org.apache.commons.io.FilenameUtils; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.LocalDiskDSProcessor; +import org.sleuthkit.autopsy.casemodule.LocalFilesDSProcessor; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; import org.sleuthkit.datamodel.Content; /* @@ -42,6 +47,7 @@ class AddArchiveTask implements Runnable { private final DataSourceProcessorProgressMonitor progressMonitor; private final DataSourceProcessorCallback callback; private boolean criticalErrorOccurred; + private final Object archiveDspLock; private static final String ARCHIVE_EXTRACTOR_MODULE_OUTPUT_DIR = "Archive Extractor"; @@ -62,6 +68,7 @@ class AddArchiveTask implements Runnable { this.archivePath = archivePath; this.callback = callback; this.progressMonitor = progressMonitor; + this.archiveDspLock = new Object(); } /** @@ -75,13 +82,18 @@ class AddArchiveTask implements Runnable { if (!ArchiveUtil.isArchive(Paths.get(archivePath))) { criticalErrorOccurred = true; logger.log(Level.SEVERE, String.format("Input data source is not a valid datasource: %s", archivePath)); //NON-NLS - errorMessages.add("Input data source is not a valid datasource: " + archivePath); + errorMessages.add("Input data source is not a valid datasource: " + archivePath); result = DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS; callback.done(result, errorMessages, newDataSources); } // extract the archive and pass the extracted folder as input Path destinationFolder = Paths.get(""); + UUID taskId = UUID.randomUUID(); + if (callback instanceof AddDataSourceCallback) { + // if running as part of automated ingest - re-use the task ID + taskId = ((AddDataSourceCallback) callback).getTaskId(); + } try { Case currentCase = Case.getCurrentCase(); @@ -93,10 +105,58 @@ class AddArchiveTask implements Runnable { destinationFolder.toFile().mkdirs(); // extract contents of ZIP archive into destination folder - //ArchiveUtil.unpackArchiveFile(archivePath, destinationFolder.toString()); - + List extractedFiles = ArchiveUtil.unpackArchiveFile(archivePath, destinationFolder.toString()); + // do processing - + Map validDataSourceProcessorsMap; + for (String file : extractedFiles) { + Path filePath = Paths.get(file); + // identify DSP for this file + // lookup all AutomatedIngestDataSourceProcessors and poll which ones are able to process the current data source + validDataSourceProcessorsMap = DataSourceProcessorUtility.getDataSourceProcessor(filePath); + if (validDataSourceProcessorsMap.isEmpty()) { + continue; + } + + // Get an ordered list of data source processors to try + List validDataSourceProcessors = DataSourceProcessorUtility.orderDataSourceProcessorsByConfidence(validDataSourceProcessorsMap); + + // Try each DSP in decreasing order of confidence + for (AutoIngestDataSourceProcessor selectedProcessor : validDataSourceProcessors) { + + // skip local files and local disk DSPs, only looking for "valid" data sources + if (selectedProcessor instanceof LocalDiskDSProcessor) { + continue; + } + if (selectedProcessor instanceof LocalFilesDSProcessor) { + continue; + } + + //jobLogger.logDataSourceProcessorSelected(selectedProcessor.getDataSourceType()); + //SYS_LOGGER.log(Level.INFO, "Identified data source type for {0} as {1}", new Object[]{manifestPath, selectedProcessor.getDataSourceType()}); + try { + DataSource internalDataSource = new DataSource(deviceId, filePath); + DataSourceProcessorCallback internalArchiveDspCallBack = new AddDataSourceCallback(currentCase, internalDataSource, taskId, archiveDspLock); + selectedProcessor.process(deviceId, filePath, progressMonitor, internalArchiveDspCallBack); + archiveDspLock.wait(); + + // at this point we got the content object(s) from the current DSP + newDataSources.addAll(internalDataSource.getContent()); + + return; + } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) { + // Log that the current DSP failed and set the error flag. We consider it an error + // if a DSP fails even if a later one succeeds since we expected to be able to process + // the data source which each DSP on the list. + //AutoIngestAlertFile.create(caseDirectoryPath); + //currentJob.setErrorsOccurred(true); + //jobLogger.logDataSourceProcessorError(selectedProcessor.getDataSourceType()); + criticalErrorOccurred = true; + errorMessages.add(ex.getMessage()); + logger.log(Level.SEVERE, "Exception while processing {0} with data source processor {1}", new Object[]{file, selectedProcessor.getDataSourceType()}); + } + } + } } catch (Exception ex) { criticalErrorOccurred = true; errorMessages.add(ex.getMessage()); @@ -117,6 +177,6 @@ class AddArchiveTask implements Runnable { * Attempts to cancel adding the archive to the case database. */ public void cancelTask() { - + // do a cancelation via future instead } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java index db19fc2fbc..181ad4d4d2 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java @@ -54,6 +54,13 @@ class AddDataSourceCallback extends DataSourceProcessorCallback { this.taskId = taskId; this.lock = lock; } + + /** + * @return the taskId + */ + public UUID getTaskId() { + return taskId; + } /** * Called by the data source processor when it finishes running in its own diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java index a649b0f37a..0123592593 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java @@ -35,10 +35,10 @@ import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; * add data source wizard. It also provides a run method overload to allow it to * be used independently of the wizard. */ -//@ServiceProviders(value={ -// @ServiceProvider(service=DataSourceProcessor.class), -// @ServiceProvider(service=AutoIngestDataSourceProcessor.class)} -//) +@ServiceProviders(value={ + @ServiceProvider(service=DataSourceProcessor.class), + @ServiceProvider(service=AutoIngestDataSourceProcessor.class)} +) @NbBundle.Messages({ "ArchiveDSP.dsType.text=Archive file"}) public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIngestDataSourceProcessor { diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveUtil.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveUtil.java index b7a2926092..823390d56b 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveUtil.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveUtil.java @@ -214,10 +214,11 @@ final class ArchiveUtil { * @param destinationFolder Path to directory where results will be * extracted to. * + * @return List of file names contained within archive * @throws * ArchiveExtractionException */ - static void unpackArchiveFile(String archiveFilePath, String destinationFolder) throws ArchiveExtractionException { + static List unpackArchiveFile(String archiveFilePath, String destinationFolder) throws ArchiveExtractionException { if (!SevenZip.isInitializedSuccessfully() && (SevenZip.getLastInitializationException() == null)) { try { SevenZip.initSevenZipFromPlatformJAR(); @@ -225,6 +226,7 @@ final class ArchiveUtil { throw new ArchiveExtractionException("Unable to initialize 7Zip libraries", ex); } } + List files = new ArrayList<>(); ISevenZipInArchive inArchive = null; try { RandomAccessFile randomAccessFile = new RandomAccessFile(new File(archiveFilePath), "r"); @@ -251,6 +253,8 @@ final class ArchiveUtil { } } } + // keep track of extracted files + files.add(entryPathInArchive); } } catch (Exception ex) { throw new ArchiveExtractionException("Exception while unpacking archive contents", ex); @@ -263,6 +267,7 @@ final class ArchiveUtil { throw new ArchiveExtractionException("Exception while closing the archive", ex); } } + return files; } /** diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index 2f2f22fb0d..5ece1a3dcf 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -2334,10 +2334,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang } // Get an ordered list of data source processors to try - List validDataSourceProcessors = validDataSourceProcessorsMap.entrySet().stream() - .sorted(Map.Entry.comparingByValue().reversed()) - .map(Map.Entry::getKey) - .collect(Collectors.toList()); + List validDataSourceProcessors = DataSourceProcessorUtility.orderDataSourceProcessorsByConfidence(validDataSourceProcessorsMap); synchronized (ingestLock) { // Try each DSP in decreasing order of confidence diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSourceProcessorUtility.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSourceProcessorUtility.java index 6f88d70a28..a8aafe4236 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSourceProcessorUtility.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSourceProcessorUtility.java @@ -21,7 +21,9 @@ package org.sleuthkit.autopsy.experimental.autoingest; import java.nio.file.Path; import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import org.openide.util.Lookup; import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException; @@ -30,8 +32,8 @@ import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor. * A utility class to find Data Source Processors */ class DataSourceProcessorUtility { - - private DataSourceProcessorUtility() { + + private DataSourceProcessorUtility() { } /** @@ -60,4 +62,21 @@ class DataSourceProcessorUtility { return validDataSourceProcessorsMap; } + + /** + * A utility method to get an ordered list of data source processors. DSPs + * are ordered in descending order from highest confidence to lowest. + * + * @param validDataSourceProcessorsMap Hash map of all DSPs that can process + * the data source along with their confidence score + * @return Ordered list of data source processors + */ + static List orderDataSourceProcessorsByConfidence(Map validDataSourceProcessorsMap) { + List validDataSourceProcessors = validDataSourceProcessorsMap.entrySet().stream() + .sorted(Map.Entry.comparingByValue().reversed()) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + + return validDataSourceProcessors; + } } From 71dfdca9b13aa05751c9a1e3d98ed86ec586e7ae Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 24 Oct 2017 17:28:24 -0400 Subject: [PATCH 010/115] 3153 change priority column to prioritized flag column, fix priority saving bug --- .../autoingest/AutoIngestControlPanel.java | 64 +++++++++++-------- .../autoingest/AutoIngestManager.java | 19 ++++-- .../PrioritizedIconCellRenderer.java | 58 +++++++++++++++++ 3 files changed, 107 insertions(+), 34 deletions(-) create mode 100644 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizedIconCellRenderer.java diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java index 22b758f2fc..fa0ec8e065 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java @@ -141,7 +141,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { private static final int GENERIC_COL_MAX_WIDTH = 2000; private static final int PENDING_TABLE_COL_PREFERRED_WIDTH = 280; private static final int RUNNING_TABLE_COL_PREFERRED_WIDTH = 175; - private static final int PRIORITY_COLUMN_PREFERRED_WIDTH = 50; + private static final int PRIORITY_COLUMN_PREFERRED_WIDTH = 60; private static final int PRIORITY_COLUMN_MAX_WIDTH = 150; private static final int ACTIVITY_TIME_COL_MIN_WIDTH = 250; private static final int ACTIVITY_TIME_COL_MAX_WIDTH = 450; @@ -182,7 +182,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { * ordinal or a column header string. */ @Messages({ - "AutoIngestControlPanel.JobsTableModel.ColumnHeader.Priority=Priority", + "AutoIngestControlPanel.JobsTableModel.ColumnHeader.Priority=Prioritized", "AutoIngestControlPanel.JobsTableModel.ColumnHeader.Case=Case", "AutoIngestControlPanel.JobsTableModel.ColumnHeader.ImageFolder=Data Source", "AutoIngestControlPanel.JobsTableModel.ColumnHeader.HostName=Host Name", @@ -266,32 +266,12 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { manager = AutoIngestManager.getInstance(); - pendingTableModel = new DefaultTableModel(JobsTableModelColumns.headers, 0) { - private static final long serialVersionUID = 1L; + pendingTableModel = new AutoIngestTableModel(JobsTableModelColumns.headers, 0); - @Override - public boolean isCellEditable(int row, int column) { - return false; - } - }; + runningTableModel = new AutoIngestTableModel(JobsTableModelColumns.headers, 0); - runningTableModel = new DefaultTableModel(JobsTableModelColumns.headers, 0) { - private static final long serialVersionUID = 1L; + completedTableModel = new AutoIngestTableModel(JobsTableModelColumns.headers, 0); - @Override - public boolean isCellEditable(int row, int column) { - return false; - } - }; - - completedTableModel = new DefaultTableModel(JobsTableModelColumns.headers, 0) { - private static final long serialVersionUID = 1L; - - @Override - public boolean isCellEditable(int row, int column) { - return false; - } - }; initComponents(); // Generated code. setServicesStatusMessage(); initPendingJobsTable(); @@ -426,12 +406,13 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { column.setWidth(TIME_COL_PREFERRED_WIDTH); column = pendingTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader()); + column.setCellRenderer(new PrioritizedIconCellRenderer()); column.setMaxWidth(PRIORITY_COLUMN_MAX_WIDTH); column.setPreferredWidth(PRIORITY_COLUMN_PREFERRED_WIDTH); column.setWidth(PRIORITY_COLUMN_PREFERRED_WIDTH); /** - * Prevent sorting when a column header is clicked. + * Allow sorting when a column header is clicked. */ pendingTable.setAutoCreateRowSorter(true); @@ -621,7 +602,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { column.setWidth(STATUS_COL_PREFERRED_WIDTH); /* - * Prevent sorting when a column header is clicked. + * Allow sorting when a column header is clicked. */ completedTable.setAutoCreateRowSorter(true); @@ -1846,4 +1827,33 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { private javax.swing.JTextField tbStatusMessage; // End of variables declaration//GEN-END:variables + private class AutoIngestTableModel extends DefaultTableModel { + + private static final long serialVersionUID = 1L; + + private AutoIngestTableModel(String[] headers, int i) { + super(headers, i); + } + + @Override + public boolean isCellEditable(int row, int column) { + return false; + } + + @Override + public Class getColumnClass(int columnIndex) { + if (columnIndex == JobsTableModelColumns.PRIORITY.ordinal()) { + return Integer.class; + } else if (columnIndex == JobsTableModelColumns.CREATED_TIME.ordinal() + || columnIndex == JobsTableModelColumns.COMPLETED_TIME.ordinal() + || columnIndex == JobsTableModelColumns.STARTED_TIME.ordinal() + || columnIndex == JobsTableModelColumns.STAGE_TIME.ordinal()) { + return Date.class; + } else if (columnIndex == JobsTableModelColumns.STATUS.ordinal()) { + return Boolean.class; + } else { + return super.getColumnClass(columnIndex); + } + } + } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index c5f43a8f1f..9f43879b55 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -503,6 +503,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang } SYS_LOGGER.log(Level.INFO, "Starting input scan of {0}", rootInputDirectory); InputDirScanner scanner = new InputDirScanner(); + scanner.scan(); SYS_LOGGER.log(Level.INFO, "Completed input scan of {0}", rootInputDirectory); } @@ -558,10 +559,12 @@ public final class AutoIngestManager extends Observable implements PropertyChang if (!prioritizedJobs.isEmpty()) { ++maxPriority; for (AutoIngestJob job : prioritizedJobs) { + int oldPriority = job.getPriority(); + job.setPriority(maxPriority); try { this.updateCoordinationServiceNode(job); - job.setPriority(maxPriority); } catch (CoordinationServiceException | InterruptedException ex) { + job.setPriority(oldPriority); throw new AutoIngestManagerException("Error updating case priority", ex); } } @@ -612,12 +615,14 @@ public final class AutoIngestManager extends Observable implements PropertyChang */ if (null != prioritizedJob) { ++maxPriority; + int oldPriority = prioritizedJob.getPriority(); + prioritizedJob.setPriority(maxPriority); try { this.updateCoordinationServiceNode(prioritizedJob); } catch (CoordinationServiceException | InterruptedException ex) { + prioritizedJob.setPriority(oldPriority); throw new AutoIngestManagerException("Error updating job priority", ex); } - prioritizedJob.setPriority(maxPriority); } Collections.sort(pendingJobs, new AutoIngestJob.PriorityComparator()); @@ -1046,8 +1051,8 @@ public final class AutoIngestManager extends Observable implements PropertyChang if (null != manifest) { /* - * Update the mapping of case names to manifest paths that is - * used for case deletion. + * Update the mapping of case names to manifest paths that + * is used for case deletion. */ String caseName = manifest.getCaseName(); Path manifestPath = manifest.getFilePath(); @@ -1061,8 +1066,8 @@ public final class AutoIngestManager extends Observable implements PropertyChang } /* - * Add a job to the pending jobs queue, the completed jobs list, - * or do crashed job recovery, as required. + * Add a job to the pending jobs queue, the completed jobs + * list, or do crashed job recovery, as required. */ try { byte[] rawData = coordinationService.getNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestPath.toString()); @@ -1082,7 +1087,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang break; case DELETED: /* - * Ignore jobs marked as "deleted." + * Ignore jobs marked as "deleted." */ break; default: diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizedIconCellRenderer.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizedIconCellRenderer.java new file mode 100644 index 0000000000..11127093ac --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizedIconCellRenderer.java @@ -0,0 +1,58 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2017 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.experimental.autoingest; + +import java.awt.Component; +import javax.swing.ImageIcon; +import javax.swing.JTable; +import static javax.swing.SwingConstants.CENTER; +import org.openide.util.ImageUtilities; +import org.openide.util.NbBundle.Messages; + +/** + * A JTable cell renderer that represents whether the priority value of a job + * has ever been increased, tick if prioritized nothing if not. + */ +class PrioritizedIconCellRenderer extends GrayableCellRenderer { + + + @Messages({ + "PrioritizedIconCellRenderer.prioritized.tooltiptext=This job has been prioritised. The most recently prioritised job should be processed next.", + "PrioritizedIconCellRenderer.notPrioritized.tooltiptext=This job has not been prioritized." + }) + private static final long serialVersionUID = 1L; + static final ImageIcon checkedIcon = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/experimental/images/tick.png", false)); + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + setHorizontalAlignment(CENTER); + if ((value instanceof Integer)) { + if ((int) value == 0) { + setIcon(null); + setToolTipText(org.openide.util.NbBundle.getMessage(CaseStatusIconCellRenderer.class, "PrioritizedIconCellRenderer.notPrioritized.tooltiptext")); + } else { + setIcon(checkedIcon); + setToolTipText(org.openide.util.NbBundle.getMessage(CaseStatusIconCellRenderer.class, "PrioritizedIconCellRenderer.prioritized.tooltiptext")); + } + } + grayCellIfTableNotEnabled(table, isSelected); + + return this; + } +} From 1402e683b59db69de50bc77dc93ab669865e2f17 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 24 Oct 2017 17:41:13 -0400 Subject: [PATCH 011/115] 3153 fix spelling of prioritized --- .../experimental/autoingest/PrioritizedIconCellRenderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizedIconCellRenderer.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizedIconCellRenderer.java index 11127093ac..8452e0fc22 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizedIconCellRenderer.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizedIconCellRenderer.java @@ -33,7 +33,7 @@ class PrioritizedIconCellRenderer extends GrayableCellRenderer { @Messages({ - "PrioritizedIconCellRenderer.prioritized.tooltiptext=This job has been prioritised. The most recently prioritised job should be processed next.", + "PrioritizedIconCellRenderer.prioritized.tooltiptext=This job has been prioritized. The most recently prioritized job should be processed next.", "PrioritizedIconCellRenderer.notPrioritized.tooltiptext=This job has not been prioritized." }) private static final long serialVersionUID = 1L; From 5b080df30f945de7fffbc93b3686cc356c5b9c68 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 24 Oct 2017 19:08:29 -0400 Subject: [PATCH 012/115] 3153 put comment on correct line --- .../experimental/autoingest/AutoIngestControlPanel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java index fa0ec8e065..7499a770d7 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java @@ -1154,8 +1154,8 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { ((Date.from(Instant.now()).getTime()) - (status.getStartDate().getTime())), // ACTIVITY_TIME job.getCaseDirectoryPath(), // CASE_DIRECTORY_PATH job.getProcessingHostName().equals(LOCAL_HOST_NAME), // IS_LOCAL_JOB - job.getManifest().getFilePath(), - job.getPriority()}); // MANIFEST_FILE_PATH + job.getManifest().getFilePath(), // MANIFEST_FILE_PATH + job.getPriority()}); // PRIORITY } } catch (Exception ex) { SYS_LOGGER.log(Level.SEVERE, "Dashboard error refreshing table", ex); From 0f5fb4cb5248312212b5fa1584a185b3fa379a66 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 24 Oct 2017 19:10:16 -0400 Subject: [PATCH 013/115] 3166 Sortable columns and prioritized column added to Aid 2.0 --- .../autoingest/AutoIngestDashboard.form | 3 -- .../autoingest/AutoIngestDashboard.java | 32 ++++++++++++------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form index 4a943b4924..2ab9f9051c 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form @@ -103,7 +103,6 @@ - @@ -127,7 +126,6 @@ - @@ -151,7 +149,6 @@ - diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java index 2d10dff258..edbefe51d7 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java @@ -55,6 +55,8 @@ public final class AutoIngestDashboard extends JPanel implements Observer { private static final int GENERIC_COL_MAX_WIDTH = 2000; private static final int PENDING_TABLE_COL_PREFERRED_WIDTH = 280; private static final int RUNNING_TABLE_COL_PREFERRED_WIDTH = 175; + private static final int PRIORITY_COLUMN_PREFERRED_WIDTH = 60; + private static final int PRIORITY_COLUMN_MAX_WIDTH = 150; private static final int STAGE_TIME_COL_MIN_WIDTH = 250; private static final int STAGE_TIME_COL_MAX_WIDTH = 450; private static final int TIME_COL_MIN_WIDTH = 30; @@ -243,10 +245,15 @@ public final class AutoIngestDashboard extends JPanel implements Observer { column.setPreferredWidth(TIME_COL_PREFERRED_WIDTH); column.setWidth(TIME_COL_PREFERRED_WIDTH); + column = pendingTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader()); + column.setCellRenderer(new PrioritizedIconCellRenderer()); + column.setMaxWidth(PRIORITY_COLUMN_MAX_WIDTH); + column.setPreferredWidth(PRIORITY_COLUMN_PREFERRED_WIDTH); + column.setWidth(PRIORITY_COLUMN_PREFERRED_WIDTH); /** - * Prevent sorting when a column header is clicked. + * Allow sorting when a column header is clicked. */ - pendingTable.setAutoCreateRowSorter(false); + pendingTable.setAutoCreateRowSorter(true); /* * Create a row selection listener to enable/disable the Prioritize @@ -257,8 +264,8 @@ public final class AutoIngestDashboard extends JPanel implements Observer { return; } int row = pendingTable.getSelectedRow(); - - boolean enablePrioritizeButtons = (row >= 0 && row < pendingTable.getRowCount()); + + boolean enablePrioritizeButtons = (row >= 0 && row < pendingTable.getRowCount()); this.prioritizeJobButton.setEnabled(enablePrioritizeButtons); this.prioritizeCaseButton.setEnabled(enablePrioritizeButtons); }); @@ -280,7 +287,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer { runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader())); runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader())); runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.JOB.getColumnHeader())); - + runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader())); /* * Set up a column to display the cases associated with the jobs. */ @@ -354,7 +361,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer { completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader())); completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader())); completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.JOB.getColumnHeader())); - + completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader())); /* * Set up a column to display the cases associated with the jobs. */ @@ -407,9 +414,9 @@ public final class AutoIngestDashboard extends JPanel implements Observer { column.setWidth(STATUS_COL_PREFERRED_WIDTH); /* - * Prevent sorting when a column header is clicked. + * Allow sorting when a column header is clicked. */ - completedTable.setAutoCreateRowSorter(false); + completedTable.setAutoCreateRowSorter(true); } /** @@ -476,6 +483,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer { ((Date.from(Instant.now()).getTime()) - (status.getStartDate().getTime())), // STAGE_TIME job.getCaseDirectoryPath(), // CASE_DIRECTORY_PATH job.getManifest().getFilePath(), // MANIFEST_FILE_PATH + job.getPriority(), // PRIORITY job }); } @@ -541,7 +549,8 @@ public final class AutoIngestDashboard extends JPanel implements Observer { * described by either an enum ordinal or a column header string. */ private enum JobsTableModelColumns { - + @Messages({"AutoIngestDashboard.JobsTableModel.ColumnHeader.Priority=Prioritized"}) + CASE(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.Case")), DATA_SOURCE(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.ImageFolder")), HOST_NAME(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.HostName")), @@ -553,6 +562,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer { STATUS(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.Status")), CASE_DIRECTORY_PATH(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.CaseFolder")), MANIFEST_FILE_PATH(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.ManifestFilePath")), + PRIORITY(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.Priority")), JOB(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.Job")); private final String header; @@ -577,6 +587,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer { STAGE_TIME.getColumnHeader(), CASE_DIRECTORY_PATH.getColumnHeader(), MANIFEST_FILE_PATH.getColumnHeader(), + PRIORITY.getColumnHeader(), JOB.getColumnHeader() }; }; @@ -667,7 +678,6 @@ public final class AutoIngestDashboard extends JPanel implements Observer { pendingTable.setModel(pendingTableModel); pendingTable.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.pendingTable.toolTipText")); // NOI18N - pendingTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS); pendingTable.setRowHeight(20); pendingTable.setSelectionModel(new DefaultListSelectionModel() { private static final long serialVersionUID = 1L; @@ -685,7 +695,6 @@ public final class AutoIngestDashboard extends JPanel implements Observer { runningTable.setModel(runningTableModel); runningTable.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.runningTable.toolTipText")); // NOI18N - runningTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS); runningTable.setRowHeight(20); runningTable.setSelectionModel(new DefaultListSelectionModel() { private static final long serialVersionUID = 1L; @@ -703,7 +712,6 @@ public final class AutoIngestDashboard extends JPanel implements Observer { completedTable.setModel(completedTableModel); completedTable.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.completedTable.toolTipText")); // NOI18N - completedTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS); completedTable.setRowHeight(20); completedTable.setSelectionModel(new DefaultListSelectionModel() { private static final long serialVersionUID = 1L; From 90823a7f9d6ab20c0cc7b3321bd93e365905d30a Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 25 Oct 2017 14:23:57 -0400 Subject: [PATCH 014/115] Bug fixes, using progress updater --- .../experimental/autoingest/AddArchiveTask.java | 14 +++++++++++--- .../experimental/autoingest/ArchiveUtil.java | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index 42c208ad58..0a5b5ad8a3 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -76,6 +76,7 @@ class AddArchiveTask implements Runnable { */ @Override public void run() { + progressMonitor.setIndeterminate(true); List errorMessages = new ArrayList<>(); List newDataSources = new ArrayList<>(); DataSourceProcessorCallback.DataSourceProcessorResult result; @@ -88,7 +89,6 @@ class AddArchiveTask implements Runnable { } // extract the archive and pass the extracted folder as input - Path destinationFolder = Paths.get(""); UUID taskId = UUID.randomUUID(); if (callback instanceof AddDataSourceCallback) { // if running as part of automated ingest - re-use the task ID @@ -101,8 +101,14 @@ class AddArchiveTask implements Runnable { String dataSourceFileNameNoExt = FilenameUtils.getBaseName(archivePath); // create folder to extract archive to - destinationFolder = Paths.get(currentCase.getModuleDirectory(), ARCHIVE_EXTRACTOR_MODULE_OUTPUT_DIR, dataSourceFileNameNoExt + "_" + TimeStampUtils.createTimeStamp()); - destinationFolder.toFile().mkdirs(); + Path destinationFolder = Paths.get(currentCase.getModuleDirectory(), ARCHIVE_EXTRACTOR_MODULE_OUTPUT_DIR, dataSourceFileNameNoExt + "_" + TimeStampUtils.createTimeStamp()); + if (destinationFolder.toFile().mkdirs() == false) { + // unable to create directory + criticalErrorOccurred = true; + errorMessages.add("Unable to create directory for archive extraction " + destinationFolder.toString()); + logger.log(Level.SEVERE, "Unable to create directory for archive extraction {0}", destinationFolder.toString()); + return; + } // extract contents of ZIP archive into destination folder List extractedFiles = ArchiveUtil.unpackArchiveFile(archivePath, destinationFolder.toString()); @@ -110,6 +116,7 @@ class AddArchiveTask implements Runnable { // do processing Map validDataSourceProcessorsMap; for (String file : extractedFiles) { + progressMonitor.setProgressText(String.format("Adding: %s", file)); Path filePath = Paths.get(file); // identify DSP for this file // lookup all AutomatedIngestDataSourceProcessors and poll which ones are able to process the current data source @@ -162,6 +169,7 @@ class AddArchiveTask implements Runnable { errorMessages.add(ex.getMessage()); logger.log(Level.SEVERE, String.format("Critical error occurred while extracting archive %s", archivePath), ex); //NON-NLS } finally { + progressMonitor.setProgress(100); if (criticalErrorOccurred) { result = DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS; } else if (!errorMessages.isEmpty()) { diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveUtil.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveUtil.java index 823390d56b..db2b954bca 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveUtil.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveUtil.java @@ -254,7 +254,7 @@ final class ArchiveUtil { } } // keep track of extracted files - files.add(entryPathInArchive); + files.add(fullPath.toString()); } } catch (Exception ex) { throw new ArchiveExtractionException("Exception while unpacking archive contents", ex); From ed697df912b704c632279a39e0d5dbdb5c6c50c0 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 25 Oct 2017 14:38:56 -0400 Subject: [PATCH 015/115] Bug fixes --- .../autoingest/AddArchiveTask.java | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index 0a5b5ad8a3..8176db8810 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -89,7 +89,7 @@ class AddArchiveTask implements Runnable { } // extract the archive and pass the extracted folder as input - UUID taskId = UUID.randomUUID(); + UUID taskId = UUID.randomUUID(); // ELTODO: do we want to come with a way to re-use task id? if (callback instanceof AddDataSourceCallback) { // if running as part of automated ingest - re-use the task ID taskId = ((AddDataSourceCallback) callback).getTaskId(); @@ -141,26 +141,28 @@ class AddArchiveTask implements Runnable { //jobLogger.logDataSourceProcessorSelected(selectedProcessor.getDataSourceType()); //SYS_LOGGER.log(Level.INFO, "Identified data source type for {0} as {1}", new Object[]{manifestPath, selectedProcessor.getDataSourceType()}); - try { - DataSource internalDataSource = new DataSource(deviceId, filePath); - DataSourceProcessorCallback internalArchiveDspCallBack = new AddDataSourceCallback(currentCase, internalDataSource, taskId, archiveDspLock); - selectedProcessor.process(deviceId, filePath, progressMonitor, internalArchiveDspCallBack); - archiveDspLock.wait(); - - // at this point we got the content object(s) from the current DSP - newDataSources.addAll(internalDataSource.getContent()); - - return; - } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) { - // Log that the current DSP failed and set the error flag. We consider it an error - // if a DSP fails even if a later one succeeds since we expected to be able to process - // the data source which each DSP on the list. - //AutoIngestAlertFile.create(caseDirectoryPath); - //currentJob.setErrorsOccurred(true); - //jobLogger.logDataSourceProcessorError(selectedProcessor.getDataSourceType()); - criticalErrorOccurred = true; - errorMessages.add(ex.getMessage()); - logger.log(Level.SEVERE, "Exception while processing {0} with data source processor {1}", new Object[]{file, selectedProcessor.getDataSourceType()}); + synchronized (archiveDspLock) { + try { + DataSource internalDataSource = new DataSource(deviceId, filePath); + DataSourceProcessorCallback internalArchiveDspCallBack = new AddDataSourceCallback(currentCase, internalDataSource, taskId, archiveDspLock); + selectedProcessor.process(deviceId, filePath, progressMonitor, internalArchiveDspCallBack); + archiveDspLock.wait(); + + // at this point we got the content object(s) from the current DSP + newDataSources.addAll(internalDataSource.getContent()); + + break; // skip all other DSPs for this file + } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) { + // Log that the current DSP failed and set the error flag. We consider it an error + // if a DSP fails even if a later one succeeds since we expected to be able to process + // the data source which each DSP on the list. + //AutoIngestAlertFile.create(caseDirectoryPath); + //currentJob.setErrorsOccurred(true); + //jobLogger.logDataSourceProcessorError(selectedProcessor.getDataSourceType()); + criticalErrorOccurred = true; + errorMessages.add(ex.getMessage()); + logger.log(Level.SEVERE, "Exception while processing {0} with data source processor {1}", new Object[]{file, selectedProcessor.getDataSourceType()}); + } } } } From 405fc296461e8691c50109554628a23c63c50a66 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 25 Oct 2017 14:54:45 -0400 Subject: [PATCH 016/115] Minor code revisions. --- .../autopsy/casemodule/MultiUserCase.java | 80 +++++++++++++------ .../casemodule/MultiUserCaseManager.java | 2 +- 2 files changed, 58 insertions(+), 24 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java index 6a9ae04c12..a85eeeb9df 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java @@ -47,8 +47,15 @@ class MultiUserCase implements Comparable { * Constructs a representation of case created by automated ingest. * * @param caseDirectoryPath The case directory path. + * + * @throws CaseMetadata.CaseMetadataException If the CaseMetadata object + * cannot be constructed for the + * case display name. + * @throws MultiUserCaseException If no case metadata (.aut) + * file is found in the case + * directory. */ - MultiUserCase(Path caseDirectoryPath) throws CaseMetadata.CaseMetadataException { + MultiUserCase(Path caseDirectoryPath) throws CaseMetadata.CaseMetadataException, MultiUserCaseException { CaseMetadata caseMetadata = null; try { @@ -60,7 +67,7 @@ class MultiUserCase implements Comparable { this.caseDirectoryPath = caseDirectoryPath; caseName = caseMetadata.getCaseDisplayName(); - metadataFilePath = caseDirectoryPath.resolve(caseMetadata.getCaseName() + CaseMetadata.getFileExtension()); + metadataFilePath = caseMetadata.getFilePath(); BasicFileAttributes fileAttrs = null; try { fileAttrs = Files.readAttributes(metadataFilePath, BasicFileAttributes.class); @@ -134,8 +141,14 @@ class MultiUserCase implements Comparable { * @param caseDirectoryPath The case directory path. * * @return Case metadata. + * + * @throws CaseMetadata.CaseMetadataException If the CaseMetadata object + * cannot be constructed. + * @throws MultiUserCaseException If no case metadata (.aut) + * file is found in the case + * directory. */ - static CaseMetadata getCaseMetadataFromCaseDirectoryPath(Path caseDirectoryPath) throws CaseMetadata.CaseMetadataException { + private static CaseMetadata getCaseMetadataFromCaseDirectoryPath(Path caseDirectoryPath) throws CaseMetadata.CaseMetadataException, MultiUserCaseException { CaseMetadata caseMetadata = null; File directory = new File(caseDirectoryPath.toString()); @@ -145,31 +158,23 @@ class MultiUserCase implements Comparable { fileNamePrefix = fileNamePrefix.substring(0, fileNamePrefix.length() - TimeStampUtils.getTimeStampLength()); } - /* - * Attempt to open an AUT file that has the folder name without a - * time stamp. - */ - File autFile = new File(directory + "/" + fileNamePrefix + CaseMetadata.getFileExtension()); + File autFile = null; /* - * If the AUT file doesn't exist, attempt to find an AUT file via a - * directory scan. + * Attempt to find an AUT file via a directory scan. */ - if(!autFile.isFile()) { - for (File file : directory.listFiles()) { - if (file.getName().toLowerCase().endsWith(CaseMetadata.getFileExtension()) && file.isFile()) { - autFile = file; - break; - } + for (File file : directory.listFiles()) { + if (file.getName().toLowerCase().endsWith(CaseMetadata.getFileExtension()) && file.isFile()) { + autFile = file; + break; } } - /* - * If the AUT file has been found, grab the case metadata. - */ - if(autFile.isFile()) { - caseMetadata = new CaseMetadata(Paths.get(autFile.getAbsolutePath())); + if(autFile == null || !autFile.isFile()) { + throw new MultiUserCaseException(String.format("No case metadata (.aut) file found in the case directory '%s'.", caseDirectoryPath.toString())); } + + caseMetadata = new CaseMetadata(Paths.get(autFile.getAbsolutePath())); } return caseMetadata; @@ -210,7 +215,7 @@ class MultiUserCase implements Comparable { /** * Compares this AutopIngestCase object with abnother MultiUserCase object - for order. + * for order. */ @Override public int compareTo(MultiUserCase other) { @@ -224,7 +229,7 @@ class MultiUserCase implements Comparable { /** * Compares two MultiUserCase objects for order based on last accessed - date (descending). + * date (descending). * * @param object The first MultiUserCase object * @param otherObject The second AuotIngestCase object. @@ -237,6 +242,35 @@ class MultiUserCase implements Comparable { return -object.getLastAccessedDate().compareTo(otherObject.getLastAccessedDate()); } } + + /** + * Exception thrown when there is a problem creating a multi-user case. + */ + final static class MultiUserCaseException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructs an exception to throw when there is a problem creating a + * multi-user case. + * + * @param message The exception message. + */ + private MultiUserCaseException(String message) { + super(message); + } + + /** + * Constructs an exception to throw when there is a problem creating a + * multi-user case. + * + * @param message The exception message. + * @param cause The cause of the exception, if it was an exception. + */ + private MultiUserCaseException(String message, Throwable cause) { + super(message, cause); + } + } enum CaseStatus { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java index 0975e60ce3..3101461443 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java @@ -80,7 +80,7 @@ final class MultiUserCaseManager { if(autFiles != null && autFiles.length > 0) { try { cases.add(new MultiUserCase(casePath)); - } catch (CaseMetadata.CaseMetadataException ex) { + } catch (CaseMetadata.CaseMetadataException | MultiUserCase.MultiUserCaseException ex) { // Ignore and continue. } } From 950e534a9268e71f3e9947c32caef38c90a64ba8 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 25 Oct 2017 16:07:35 -0400 Subject: [PATCH 017/115] Adding archive file itself as a local file --- .../autoingest/AddArchiveTask.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index 8176db8810..80c4bb958e 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -166,6 +166,32 @@ class AddArchiveTask implements Runnable { } } } + + // after all archive contents have been ingested - all the archive itself as a logical file + progressMonitor.setProgressText(String.format("Adding: %s", archivePath)); + LocalFilesDSProcessor localFilesDSP = new LocalFilesDSProcessor(); + synchronized (archiveDspLock) { + try { + Path filePath = Paths.get(archivePath); + DataSource internalDataSource = new DataSource(deviceId, filePath); + DataSourceProcessorCallback internalArchiveDspCallBack = new AddDataSourceCallback(currentCase, internalDataSource, taskId, archiveDspLock); + localFilesDSP.process(deviceId, filePath, progressMonitor, internalArchiveDspCallBack); + archiveDspLock.wait(); + + // at this point we got the content object(s) from the current DSP + newDataSources.addAll(internalDataSource.getContent()); + } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) { + // Log that the current DSP failed and set the error flag. We consider it an error + // if a DSP fails even if a later one succeeds since we expected to be able to process + // the data source which each DSP on the list. + //AutoIngestAlertFile.create(caseDirectoryPath); + //currentJob.setErrorsOccurred(true); + //jobLogger.logDataSourceProcessorError(selectedProcessor.getDataSourceType()); + criticalErrorOccurred = true; + errorMessages.add(ex.getMessage()); + logger.log(Level.SEVERE, "Exception while processing {0} with data source processor {1}", new Object[]{archivePath, localFilesDSP.getDataSourceType()}); + } + } } catch (Exception ex) { criticalErrorOccurred = true; errorMessages.add(ex.getMessage()); From 6d42d16191f50b8f6200fe5977c3d15f8b2bb98e Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 25 Oct 2017 17:28:47 -0400 Subject: [PATCH 018/115] 3153 - Date Columns in AID now sort by descending order first --- .../autoingest/AutoIngestControlPanel.java | 45 ++++++++++++++----- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java index 7499a770d7..26dcabff58 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java @@ -45,7 +45,7 @@ import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.RowSorter; -import static javax.swing.SortOrder.DESCENDING; +import javax.swing.SortOrder; import javax.swing.SwingWorker; import javax.swing.UIManager; import javax.swing.event.ListSelectionEvent; @@ -278,14 +278,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { initRunningJobsTable(); initCompletedJobsTable(); initButtons(); - - @SuppressWarnings("unchecked") - TableRowSorter sorter = (TableRowSorter) completedTable.getRowSorter(); - List list = new ArrayList<>(); - list.add(new RowSorter.SortKey(JobsTableModelColumns.COMPLETED_TIME.ordinal(), DESCENDING)); - sorter.setSortKeys(list); - sorter.sort(); - + completedTable.getRowSorter().toggleSortOrder(JobsTableModelColumns.COMPLETED_TIME.ordinal()); /* * Must set this flag, otherwise pop up menus don't close properly. */ @@ -414,7 +407,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { /** * Allow sorting when a column header is clicked. */ - pendingTable.setAutoCreateRowSorter(true); + pendingTable.setRowSorter(new AutoIngestTableRowSorter<>(pendingTableModel)); /* * Create a row selection listener to enable/disable the prioritize @@ -604,7 +597,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { /* * Allow sorting when a column header is clicked. */ - completedTable.setAutoCreateRowSorter(true); + completedTable.setRowSorter(new AutoIngestTableRowSorter<>(completedTableModel)); /* * Create a row selection listener to enable/disable the delete case and @@ -1856,4 +1849,34 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { } } } + + /** + * RowSorter which makes columns whose type is Date to be sorted first in + * Descending order then in Ascending order + */ + private class AutoIngestTableRowSorter extends TableRowSorter { + + private AutoIngestTableRowSorter(M tModel) { + super(tModel); + } + + @Override + public void toggleSortOrder(int column) { + if (!this.getModel().getColumnClass(column).equals(Date.class)) { + super.toggleSortOrder(column); //if it isn't a date perform the regular sorting + } else { + ArrayList sortKeys = new ArrayList<>(getSortKeys()); + if (sortKeys.isEmpty() || sortKeys.get(0).getColumn() != column) { //sort descending + sortKeys.add(0, new RowSorter.SortKey(column, SortOrder.DESCENDING)); + } else if (sortKeys.get(0).getSortOrder() == SortOrder.ASCENDING) { + sortKeys.removeIf(key -> key.getColumn() == column); + sortKeys.add(0, new RowSorter.SortKey(column, SortOrder.DESCENDING)); + } else { + sortKeys.removeIf(key -> key.getColumn() == column); + sortKeys.add(0, new RowSorter.SortKey(column, SortOrder.ASCENDING)); + } + setSortKeys(sortKeys); + } + } + } } From 34c705252769d36cb5a6cafd92a39df692087fad Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 25 Oct 2017 18:18:50 -0400 Subject: [PATCH 019/115] 3166 Applied the date column sorting chages from 3153 to AID 2.0 and AutoIngestCasePanel --- .../autoingest/AutoIngestCasePanel.form | 2 - .../autoingest/AutoIngestCasePanel.java | 4 +- .../autoingest/AutoIngestControlPanel.java | 34 ---------- .../autoingest/AutoIngestDashboard.java | 67 ++++++++++--------- .../autoingest/AutoIngestRowSorter.java | 56 ++++++++++++++++ 5 files changed, 94 insertions(+), 69 deletions(-) create mode 100644 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestRowSorter.java diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.form index cb0f275809..f5963ff59d 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.form @@ -99,11 +99,9 @@ - - diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java index 9b6b3ddefa..0a847dbd0e 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java @@ -150,7 +150,7 @@ public final class AutoIngestCasePanel extends JPanel { theColumn.setWidth(STATUS_COL_PREFERRED_WIDTH); casesTable.removeColumn(casesTable.getColumn(OUTPUT_FOLDER_HEADER)); - + casesTable.setRowSorter(new AutoIngestTableRowSorter<>(caseTableModel)); /* * Listen for row selection changes and set button state for the current * selection. @@ -408,9 +408,7 @@ public final class AutoIngestCasePanel extends JPanel { } }); - casesTable.setAutoCreateRowSorter(true); casesTable.setModel(caseTableModel); - casesTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS); casesTable.setRowHeight(20); casesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); casesTable.addMouseListener(new java.awt.event.MouseAdapter() { diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java index 26dcabff58..aa47fb3271 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java @@ -39,19 +39,15 @@ import javax.swing.DefaultListSelectionModel; import java.awt.Color; import java.beans.PropertyChangeEvent; import java.io.File; - import java.util.logging.Logger; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTable; -import javax.swing.RowSorter; -import javax.swing.SortOrder; import javax.swing.SwingWorker; import javax.swing.UIManager; import javax.swing.event.ListSelectionEvent; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableColumn; -import javax.swing.table.TableRowSorter; import org.netbeans.api.options.OptionsDisplayer; import org.openide.DialogDisplayer; import org.openide.LifecycleManager; @@ -1849,34 +1845,4 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { } } } - - /** - * RowSorter which makes columns whose type is Date to be sorted first in - * Descending order then in Ascending order - */ - private class AutoIngestTableRowSorter extends TableRowSorter { - - private AutoIngestTableRowSorter(M tModel) { - super(tModel); - } - - @Override - public void toggleSortOrder(int column) { - if (!this.getModel().getColumnClass(column).equals(Date.class)) { - super.toggleSortOrder(column); //if it isn't a date perform the regular sorting - } else { - ArrayList sortKeys = new ArrayList<>(getSortKeys()); - if (sortKeys.isEmpty() || sortKeys.get(0).getColumn() != column) { //sort descending - sortKeys.add(0, new RowSorter.SortKey(column, SortOrder.DESCENDING)); - } else if (sortKeys.get(0).getSortOrder() == SortOrder.ASCENDING) { - sortKeys.removeIf(key -> key.getColumn() == column); - sortKeys.add(0, new RowSorter.SortKey(column, SortOrder.DESCENDING)); - } else { - sortKeys.removeIf(key -> key.getColumn() == column); - sortKeys.add(0, new RowSorter.SortKey(column, SortOrder.ASCENDING)); - } - setSortKeys(sortKeys); - } - } - } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java index edbefe51d7..8222ccc1a6 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java @@ -48,7 +48,7 @@ import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestMonitor.JobsSnaps /** * A dashboard for monitoring an automated ingest cluster. */ -public final class AutoIngestDashboard extends JPanel implements Observer { +final class AutoIngestDashboard extends JPanel implements Observer { private static final long serialVersionUID = 1L; private static final int GENERIC_COL_MIN_WIDTH = 30; @@ -102,32 +102,11 @@ public final class AutoIngestDashboard extends JPanel implements Observer { * Constructs a panel for monitoring an automated ingest cluster. */ private AutoIngestDashboard() { - pendingTableModel = new DefaultTableModel(JobsTableModelColumns.headers, 0) { - private static final long serialVersionUID = 1L; + pendingTableModel = new AutoIngestTableModel(JobsTableModelColumns.headers, 0); - @Override - public boolean isCellEditable(int row, int column) { - return false; - } - }; + runningTableModel = new AutoIngestTableModel(JobsTableModelColumns.headers, 0); - runningTableModel = new DefaultTableModel(JobsTableModelColumns.headers, 0) { - private static final long serialVersionUID = 1L; - - @Override - public boolean isCellEditable(int row, int column) { - return false; - } - }; - - completedTableModel = new DefaultTableModel(JobsTableModelColumns.headers, 0) { - private static final long serialVersionUID = 1L; - - @Override - public boolean isCellEditable(int row, int column) { - return false; - } - }; + completedTableModel = new AutoIngestTableModel(JobsTableModelColumns.headers, 0); initComponents(); setServicesStatusMessage(); @@ -250,10 +229,10 @@ public final class AutoIngestDashboard extends JPanel implements Observer { column.setMaxWidth(PRIORITY_COLUMN_MAX_WIDTH); column.setPreferredWidth(PRIORITY_COLUMN_PREFERRED_WIDTH); column.setWidth(PRIORITY_COLUMN_PREFERRED_WIDTH); - /** + /* * Allow sorting when a column header is clicked. */ - pendingTable.setAutoCreateRowSorter(true); + pendingTable.setRowSorter(new AutoIngestRowSorter<>(pendingTableModel)); /* * Create a row selection listener to enable/disable the Prioritize @@ -412,11 +391,10 @@ public final class AutoIngestDashboard extends JPanel implements Observer { column.setMaxWidth(STATUS_COL_MAX_WIDTH); column.setPreferredWidth(STATUS_COL_PREFERRED_WIDTH); column.setWidth(STATUS_COL_PREFERRED_WIDTH); - /* * Allow sorting when a column header is clicked. */ - completedTable.setAutoCreateRowSorter(true); + completedTable.setRowSorter(new AutoIngestRowSorter<>(completedTableModel)); } /** @@ -550,7 +528,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer { */ private enum JobsTableModelColumns { @Messages({"AutoIngestDashboard.JobsTableModel.ColumnHeader.Priority=Prioritized"}) - + CASE(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.Case")), DATA_SOURCE(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.ImageFolder")), HOST_NAME(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.HostName")), @@ -898,4 +876,33 @@ public final class AutoIngestDashboard extends JPanel implements Observer { private javax.swing.JTextField tbServicesStatusMessage; // End of variables declaration//GEN-END:variables + private class AutoIngestTableModel extends DefaultTableModel { + + private static final long serialVersionUID = 1L; + + private AutoIngestTableModel(String[] headers, int i) { + super(headers, i); + } + + @Override + public boolean isCellEditable(int row, int column) { + return false; + } + + @Override + public Class getColumnClass(int columnIndex) { + if (columnIndex == JobsTableModelColumns.PRIORITY.ordinal()) { + return Integer.class; + } else if (columnIndex == JobsTableModelColumns.CREATED_TIME.ordinal() + || columnIndex == JobsTableModelColumns.COMPLETED_TIME.ordinal() + || columnIndex == JobsTableModelColumns.STARTED_TIME.ordinal() + || columnIndex == JobsTableModelColumns.STAGE_TIME.ordinal()) { + return Date.class; + } else if (columnIndex == JobsTableModelColumns.STATUS.ordinal()) { + return Boolean.class; + } else { + return super.getColumnClass(columnIndex); + } + } + } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestRowSorter.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestRowSorter.java new file mode 100644 index 0000000000..c866b2d7f6 --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestRowSorter.java @@ -0,0 +1,56 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.experimental.autoingest; + +import java.util.ArrayList; +import java.util.Date; +import javax.swing.RowSorter; +import javax.swing.SortOrder; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableRowSorter; + +/** + * RowSorter which makes columns whose type is Date to be sorted first in + * Descending order then in Ascending order + */ +final class AutoIngestTableRowSorter extends TableRowSorter { + + AutoIngestTableRowSorter(M tModel) { + super(tModel); + } + + @Override + public void toggleSortOrder(int column) { + if (!this.getModel().getColumnClass(column).equals(Date.class)) { + super.toggleSortOrder(column); //if it isn't a date perform the regular sorting + } else { + ArrayList sortKeys = new ArrayList<>(getSortKeys()); + if (sortKeys.isEmpty() || sortKeys.get(0).getColumn() != column) { //sort descending + sortKeys.add(0, new RowSorter.SortKey(column, SortOrder.DESCENDING)); + } else if (sortKeys.get(0).getSortOrder() == SortOrder.ASCENDING) { + sortKeys.removeIf(key -> key.getColumn() == column); + sortKeys.add(0, new RowSorter.SortKey(column, SortOrder.DESCENDING)); + } else { + sortKeys.removeIf(key -> key.getColumn() == column); + sortKeys.add(0, new RowSorter.SortKey(column, SortOrder.ASCENDING)); + } + setSortKeys(sortKeys); + } + } +} From 8a759d26fe83a1f069b00f8cdc05d85ccd584cc6 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 25 Oct 2017 18:41:26 -0400 Subject: [PATCH 020/115] 3166 fix incorrect rename of some methods from AutoIngestRowSorter refactor --- .../autopsy/experimental/autoingest/AutoIngestCasePanel.java | 2 +- .../experimental/autoingest/AutoIngestControlPanel.java | 4 ++-- .../autopsy/experimental/autoingest/AutoIngestRowSorter.java | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java index 0a847dbd0e..1be3430910 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java @@ -150,7 +150,7 @@ public final class AutoIngestCasePanel extends JPanel { theColumn.setWidth(STATUS_COL_PREFERRED_WIDTH); casesTable.removeColumn(casesTable.getColumn(OUTPUT_FOLDER_HEADER)); - casesTable.setRowSorter(new AutoIngestTableRowSorter<>(caseTableModel)); + casesTable.setRowSorter(new AutoIngestRowSorter<>(caseTableModel)); /* * Listen for row selection changes and set button state for the current * selection. diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java index aa47fb3271..b299b89e01 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java @@ -403,7 +403,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { /** * Allow sorting when a column header is clicked. */ - pendingTable.setRowSorter(new AutoIngestTableRowSorter<>(pendingTableModel)); + pendingTable.setRowSorter(new AutoIngestRowSorter<>(pendingTableModel)); /* * Create a row selection listener to enable/disable the prioritize @@ -593,7 +593,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { /* * Allow sorting when a column header is clicked. */ - completedTable.setRowSorter(new AutoIngestTableRowSorter<>(completedTableModel)); + completedTable.setRowSorter(new AutoIngestRowSorter<>(completedTableModel)); /* * Create a row selection listener to enable/disable the delete case and diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestRowSorter.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestRowSorter.java index c866b2d7f6..7334e31229 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestRowSorter.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestRowSorter.java @@ -29,9 +29,9 @@ import javax.swing.table.TableRowSorter; * RowSorter which makes columns whose type is Date to be sorted first in * Descending order then in Ascending order */ -final class AutoIngestTableRowSorter extends TableRowSorter { +class AutoIngestRowSorter extends TableRowSorter { - AutoIngestTableRowSorter(M tModel) { + AutoIngestRowSorter(M tModel) { super(tModel); } From 3c66cc242b3e417570f08499292e01ccb185c57f Mon Sep 17 00:00:00 2001 From: millmanorama Date: Thu, 26 Oct 2017 17:11:11 +0200 Subject: [PATCH 021/115] set initial sort to Priority and initialize toolbar from GroupManager --- .../autopsy/imagegallery/datamodel/grouping/GroupManager.java | 4 ++-- .../src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index ae9e17bb4a..8a934cda98 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -122,7 +122,7 @@ public class GroupManager { /* * --- current grouping/sorting attributes --- */ - private volatile GroupSortBy sortBy = GroupSortBy.NONE; + private volatile GroupSortBy sortBy = GroupSortBy.PRIORITY; private volatile DrawableAttribute groupBy = DrawableAttribute.PATH; private volatile SortOrder sortOrder = SortOrder.ASCENDING; @@ -466,7 +466,7 @@ public class GroupManager { } } - public Comparator getSortBy() { + public GroupSortBy getSortBy() { return sortBy; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java index 2dc85cbfd9..90c739287e 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java @@ -189,7 +189,7 @@ public class Toolbar extends ToolBar { }); sortChooser.sortOrderProperty().addListener(queryInvalidationListener); - sortChooser.setComparator(GroupSortBy.PRIORITY); + sortChooser.setComparator(controller.getGroupManager().getSortBy()); getItems().add(1, sortChooser); sortHelpImageView.setCursor(Cursor.HAND); From 3f325a86fd118d68b7106af4ed7cb6b87912a8cd Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 26 Oct 2017 15:52:19 -0400 Subject: [PATCH 022/115] Various bug fixes. --- .../autopsy/casemodule/CaseDeleteAction.java | 3 +-- .../autopsy/casemodule/CaseMetadata.java | 11 ++++++++++ .../casemodule/CaseOpenMultiUserAction.java | 2 +- .../autopsy/casemodule/CueBannerPanel.java | 2 +- .../autopsy/casemodule/MultiUserCase.java | 9 ++++++++ .../casemodule/MultiUserCasesPanel.java | 22 ++++++++++++++----- .../autopsy/core/UserPreferences.java | 12 +++++++--- .../autoingest/AutoIngestCaseOpenAction.java | 1 - .../AutoIngestDashboardOpenAction.java | 1 - .../autoingest/CaseImportPanel.java | 1 - 10 files changed, 48 insertions(+), 16 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java index 3ef30f2594..dcda423c18 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java @@ -33,7 +33,6 @@ import org.openide.util.HelpCtx; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; -import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; /** @@ -51,7 +50,7 @@ final class CaseDeleteAction extends CallableSystemAction { putValue(Action.NAME, NbBundle.getMessage(CaseDeleteAction.class, "CTL_CaseDeleteAction")); this.setEnabled(false); Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> { - setEnabled(null != evt.getNewValue() && UserPreferences.getMode() != UserPreferences.SelectedMode.REVIEW); + setEnabled(null != evt.getNewValue() && ((Case)evt.getNewValue()).getCaseType() != Case.CaseType.MULTI_USER_CASE); }); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index 1f4c5b7912..dee10f0ca1 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -172,6 +172,17 @@ public final class CaseMetadata { public String getCaseDirectory() { return metadataFilePath.getParent().toString(); } + + /** + * Gets the full case directory path. + * + * @return The case directory path. + */ + public String getCaseDirectoryPath() { + String fileName = metadataFilePath.getFileName().toString(); + String caseDirectoryPath = metadataFilePath.toString(); + return caseDirectoryPath.substring(0, caseDirectoryPath.lastIndexOf(fileName)); + } /** * Gets the case type. diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java index 4d3af01f26..96892cbb4e 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java @@ -70,7 +70,7 @@ public final class CaseOpenMultiUserAction extends CallableSystemAction implemen multiUserCaseWindow.setVisible(false); }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); - multiUserCaseWindow.add(new MultiUserCasesPanel()); + multiUserCaseWindow.add(MultiUserCasesPanel.getInstance()); multiUserCaseWindow.pack(); multiUserCaseWindow.setResizable(false); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java index ff25e934cf..7a1c32db85 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java @@ -124,7 +124,7 @@ public class CueBannerPanel extends javax.swing.JPanel { multiUserCaseWindow.setVisible(false); }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); - multiUserCaseWindow.add(new MultiUserCasesPanel()); + multiUserCaseWindow.add(MultiUserCasesPanel.getInstance()); multiUserCaseWindow.pack(); multiUserCaseWindow.setResizable(false); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java index a85eeeb9df..8ecc1c91e2 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java @@ -120,6 +120,15 @@ class MultiUserCase implements Comparable { Date getLastAccessedDate() { return this.lastAccessedDate; } + + /** + * Gets the full path of the metadata (.aut) file. + * + * @return The metadata file path. + */ + Path getMetadataFilePath() { + return this.metadataFilePath; + } /** * Gets the status of this case based on the auto ingest result file in the diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java index 6b20a41147..aa2f199967 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java @@ -79,6 +79,18 @@ public class MultiUserCasesPanel extends javax.swing.JPanel { private final String[] columnNames = {CASE_HEADER, CREATEDTIME_HEADER, COMPLETEDTIME_HEADER, STATUS_ICON_HEADER, OUTPUT_FOLDER_HEADER}; private DefaultTableModel caseTableModel; private Path currentlySelectedCase = null; + private static MultiUserCasesPanel instance; + + /* + * Gets the singleton instance of the panel. + */ + static MultiUserCasesPanel getInstance() { + if (instance == null) { + instance = new MultiUserCasesPanel(); + } + instance.refreshCasesTable(); + return instance; + } /** * Constructs a panel that allows a user to open cases created by automated @@ -86,7 +98,7 @@ public class MultiUserCasesPanel extends javax.swing.JPanel { * * @param parent The parent dialog for this panel. */ - MultiUserCasesPanel() { + private MultiUserCasesPanel() { caseTableModel = new DefaultTableModel(columnNames, 0) { private static final long serialVersionUID = 1L; @@ -174,7 +186,7 @@ public class MultiUserCasesPanel extends javax.swing.JPanel { autoIngestCase.getCreationDate(), autoIngestCase.getLastAccessedDate(), (MultiUserCase.CaseStatus.OK != autoIngestCase.getStatus()), - autoIngestCase.getCaseDirectoryPath().toString()}); + autoIngestCase.getMetadataFilePath().toString()}); } } setSelectedCase(currentlySelectedCase); @@ -472,8 +484,7 @@ public class MultiUserCasesPanel extends javax.swing.JPanel { private void bnOpenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOpenActionPerformed int modelRow = casesTable.convertRowIndexToModel(casesTable.getSelectedRow()); Path caseMetadataFilePath = Paths.get((String) caseTableModel.getValueAt(modelRow, - COLUMN_HEADERS.OUTPUTFOLDER.ordinal()), - caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.CASE.ordinal()) + CaseMetadata.getFileExtension()); + COLUMN_HEADERS.OUTPUTFOLDER.ordinal())); new Thread(() -> { openCase(caseMetadataFilePath); @@ -538,8 +549,7 @@ public class MultiUserCasesPanel extends javax.swing.JPanel { if (evt.getClickCount() == 2) { int modelRow = casesTable.convertRowIndexToModel(casesTable.getSelectedRow()); Path caseMetadataFilePath = Paths.get((String) caseTableModel.getValueAt(modelRow, - COLUMN_HEADERS.OUTPUTFOLDER.ordinal()), - caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.CASE.ordinal()) + CaseMetadata.getFileExtension()); + COLUMN_HEADERS.OUTPUTFOLDER.ordinal())); openCase(caseMetadataFilePath); } }//GEN-LAST:event_casesTableMouseClicked diff --git a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java index df63b0fa1f..dfcad8e516 100755 --- a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java +++ b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2014-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,6 @@ import java.util.prefs.BackingStoreException; import org.sleuthkit.autopsy.events.MessageServiceConnectionInfo; import java.util.prefs.PreferenceChangeListener; import java.util.prefs.Preferences; -import org.openide.util.Exceptions; import org.openide.util.NbPreferences; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; @@ -77,7 +76,6 @@ public final class UserPreferences { STANDALONE, AUTOINGEST, - REVIEW }; /** @@ -88,6 +86,14 @@ public final class UserPreferences { public static SelectedMode getMode() { if (ModuleSettings.settingExists(SETTINGS_PROPERTIES, MODE)) { int ordinal = Integer.parseInt(ModuleSettings.getConfigSetting(SETTINGS_PROPERTIES, MODE)); + + // If mode is 'REVIEW' (2, now invalid), set it to 'STANDALONE' (0). + if(ordinal > 1) { + setMode(SelectedMode.STANDALONE); + ModuleSettings.setConfigSetting(UserPreferences.SETTINGS_PROPERTIES, "JoinAutoModeCluster", Boolean.toString(false)); + ordinal = 0; + } + return UserPreferences.SelectedMode.values()[ordinal]; } return UserPreferences.SelectedMode.STANDALONE; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseOpenAction.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseOpenAction.java index 265190663e..6a84946c91 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseOpenAction.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseOpenAction.java @@ -53,7 +53,6 @@ final class AutoIngestCaseOpenAction extends CallableSystemAction implements Act break; case STANDALONE: - case REVIEW: /** * In standalone mode, invoke default Autopsy version of CaseOpenAction. */ diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java index 10ff60da2a..45563a4f4b 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java @@ -25,7 +25,6 @@ import org.openide.util.HelpCtx; import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; import org.sleuthkit.autopsy.core.UserPreferences; -import static org.sleuthkit.autopsy.core.UserPreferences.SelectedMode.REVIEW; import org.sleuthkit.autopsy.coreutils.Logger; @ActionID(category = "Tools", id = "org.sleuthkit.autopsy.experimental.autoingest.AutoIngestDashboardOpenAction") diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseImportPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseImportPanel.java index a7cd13af72..2e4866b010 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseImportPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseImportPanel.java @@ -672,7 +672,6 @@ public class CaseImportPanel extends javax.swing.JPanel implements ImportDoneCal */ private void enableStartButton() { if (UserPreferences.getIsMultiUserModeEnabled() - && AutoIngestUserPreferences.getJoinAutoModeCluster() && (! RuntimeProperties.runningWithGUI()) && !tbCaseSource.getText().isEmpty() && !tbCaseDestination.getText().isEmpty() From 2082928e514001878543a1b92c4fd8deffbb827b Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 26 Oct 2017 16:24:57 -0400 Subject: [PATCH 023/115] Moved config update logic. --- .../sleuthkit/autopsy/core/UserPreferences.java | 8 -------- .../autopsy/corecomponents/Installer.java | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java index dfcad8e516..0e7fc3da5e 100755 --- a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java +++ b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java @@ -86,14 +86,6 @@ public final class UserPreferences { public static SelectedMode getMode() { if (ModuleSettings.settingExists(SETTINGS_PROPERTIES, MODE)) { int ordinal = Integer.parseInt(ModuleSettings.getConfigSetting(SETTINGS_PROPERTIES, MODE)); - - // If mode is 'REVIEW' (2, now invalid), set it to 'STANDALONE' (0). - if(ordinal > 1) { - setMode(SelectedMode.STANDALONE); - ModuleSettings.setConfigSetting(UserPreferences.SETTINGS_PROPERTIES, "JoinAutoModeCluster", Boolean.toString(false)); - ordinal = 0; - } - return UserPreferences.SelectedMode.values()[ordinal]; } return UserPreferences.SelectedMode.STANDALONE; diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java b/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java index c908f3b35d..3f92a97760 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java @@ -30,7 +30,11 @@ import org.netbeans.swing.tabcontrol.plaf.DefaultTabbedContainerUI; import org.openide.modules.ModuleInstall; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.StartupWindowProvider; +import org.sleuthkit.autopsy.core.UserPreferences; +import static org.sleuthkit.autopsy.core.UserPreferences.SETTINGS_PROPERTIES; +import static org.sleuthkit.autopsy.core.UserPreferences.setMode; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; /** * Manages this module's life cycle. Opens the startup dialog during startup. @@ -59,6 +63,7 @@ public class Installer extends ModuleInstall { UIManager.put("ViewTabDisplayerUI", "org.sleuthkit.autopsy.corecomponents.NoTabsTabDisplayerUI"); UIManager.put(DefaultTabbedContainerUI.KEY_VIEW_CONTENT_BORDER, BorderFactory.createEmptyBorder()); UIManager.put("TabbedPane.contentBorderInsets", new Insets(0, 0, 0, 0)); + updateConfig(); WindowManager.getDefault().invokeWhenUIReady(() -> { StartupWindowProvider.getInstance().open(); }); @@ -68,6 +73,16 @@ public class Installer extends ModuleInstall { public void uninstalled() { super.uninstalled(); } + + private void updateConfig() { + // If mode is 'REVIEW' (2, now invalid), set it to 'STANDALONE' (0). + int ordinal = Integer.parseInt(ModuleSettings.getConfigSetting(SETTINGS_PROPERTIES, "AutopsyMode")); + if(ordinal > 1) { + setMode(UserPreferences.SelectedMode.STANDALONE); + ModuleSettings.setConfigSetting(UserPreferences.SETTINGS_PROPERTIES, "JoinAutoModeCluster", Boolean.toString(false)); + ordinal = 0; + } + } private void setLookAndFeel() { if (System.getProperty("os.name").toLowerCase().contains("mac")) { //NON-NLS From ad0fe641a72e9a74c0f67a65c0e7826724d6b64f Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 27 Oct 2017 12:23:22 -0400 Subject: [PATCH 024/115] Auto refresh fixed for multi-user cases panel. --- .../casemodule/CaseOpenMultiUserAction.java | 21 +---- .../autopsy/casemodule/CueBannerPanel.java | 17 +--- .../casemodule/MultiUserCasesDialog.java | 81 ++++++++++++++++++ .../casemodule/MultiUserCasesPanel.java | 84 +++++++++++-------- .../autopsy/corecomponents/Installer.java | 18 ++-- 5 files changed, 141 insertions(+), 80 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesDialog.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java index 96892cbb4e..76607210c5 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java @@ -55,25 +55,6 @@ public final class CaseOpenMultiUserAction extends CallableSystemAction implemen private static final String REVIEW_MODE_TITLE = "Open Multi-User Case (" + LOCAL_HOST_NAME + ")"; public CaseOpenMultiUserAction() {} - - /** - * Constructs the Multi-User Cases window used by the Open Multi-User Case - * menu item. - */ - private void initMultiUserCasesWindow() { - multiUserCaseWindow = new JDialog( - WindowManager.getDefault().getMainWindow(), - REVIEW_MODE_TITLE, - Dialog.ModalityType.APPLICATION_MODAL); - multiUserCaseWindow.getRootPane().registerKeyboardAction( - e -> { - multiUserCaseWindow.setVisible(false); - }, - KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); - multiUserCaseWindow.add(MultiUserCasesPanel.getInstance()); - multiUserCaseWindow.pack(); - multiUserCaseWindow.setResizable(false); - } public static void closeMultiUserCasesWindow() { if (null != multiUserCaseWindow) { @@ -95,7 +76,7 @@ public final class CaseOpenMultiUserAction extends CallableSystemAction implemen @Override public void actionPerformed(ActionEvent event) { if(multiUserCaseWindow == null) { - initMultiUserCasesWindow(); + multiUserCaseWindow = MultiUserCasesDialog.getInstance(); } multiUserCaseWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); multiUserCaseWindow.setVisible(true); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java index 7a1c32db85..c4c15fdd91 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java @@ -113,21 +113,6 @@ public class CueBannerPanel extends javax.swing.JPanel { recentCasesWindow.pack(); recentCasesWindow.setResizable(false); } - - private void initMultiUserCasesWindow() { - multiUserCaseWindow = new JDialog( - WindowManager.getDefault().getMainWindow(), - REVIEW_MODE_TITLE, - Dialog.ModalityType.APPLICATION_MODAL); - multiUserCaseWindow.getRootPane().registerKeyboardAction( - e -> { - multiUserCaseWindow.setVisible(false); - }, - KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); - multiUserCaseWindow.add(MultiUserCasesPanel.getInstance()); - multiUserCaseWindow.pack(); - multiUserCaseWindow.setResizable(false); - } private void enableComponents() { boolean enableOpenRecentCaseButton = (RecentCases.getInstance().getTotalRecentCases() > 0); @@ -304,7 +289,7 @@ public class CueBannerPanel extends javax.swing.JPanel { private void openMultiUserCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openMultiUserCaseButtonActionPerformed if(multiUserCaseWindow == null) { - initMultiUserCasesWindow(); + multiUserCaseWindow = MultiUserCasesDialog.getInstance(); } multiUserCaseWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); multiUserCaseWindow.setVisible(true); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesDialog.java new file mode 100755 index 0000000000..b6d9feeb7e --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesDialog.java @@ -0,0 +1,81 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.casemodule; + +import java.awt.Dialog; +import java.awt.event.KeyEvent; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.KeyStroke; +import org.openide.windows.WindowManager; + +/** + * This class extends a JDialog and maintains the MultiUserCasesPanel. + */ +public class MultiUserCasesDialog extends JDialog { + private static final String REVIEW_MODE_TITLE = "Open Multi-User Case"; + private final MultiUserCasesPanel multiUserCasesPanel; + private static MultiUserCasesDialog instance; + + /** + * Gets the instance of the MultiuserCasesDialog. + * + * @return The instance. + */ + static public MultiUserCasesDialog getInstance() { + if(instance == null) { + instance = new MultiUserCasesDialog(); + } + return instance; + } + + /** + * Constructs a MultiUserCasesDialog object. + */ + MultiUserCasesDialog() { + super(WindowManager.getDefault().getMainWindow(), + REVIEW_MODE_TITLE, + Dialog.ModalityType.APPLICATION_MODAL); + + getRootPane().registerKeyboardAction( + e -> { + setVisible(false); + }, + KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); + + multiUserCasesPanel = new MultiUserCasesPanel(); + add(multiUserCasesPanel); + pack(); + setResizable(false); + } + + /** + * Set the dialog visibility. When setting it to visible, the contents will + * refresh. + * + * @param value True or false. + */ + @Override + public void setVisible(boolean value) { + if(value) { + multiUserCasesPanel.refreshCasesTable(); + } + super.setVisible(value); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java index aa2f199967..d905f36c2c 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java @@ -20,13 +20,16 @@ package org.sleuthkit.autopsy.casemodule; import java.awt.Cursor; import java.awt.Desktop; +import java.awt.EventQueue; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Date; import java.util.List; +import java.util.concurrent.ExecutionException; import java.util.logging.Level; import javax.swing.JOptionPane; +import javax.swing.SwingWorker; import javax.swing.event.ListSelectionEvent; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableColumn; @@ -79,26 +82,12 @@ public class MultiUserCasesPanel extends javax.swing.JPanel { private final String[] columnNames = {CASE_HEADER, CREATEDTIME_HEADER, COMPLETEDTIME_HEADER, STATUS_ICON_HEADER, OUTPUT_FOLDER_HEADER}; private DefaultTableModel caseTableModel; private Path currentlySelectedCase = null; - private static MultiUserCasesPanel instance; - - /* - * Gets the singleton instance of the panel. - */ - static MultiUserCasesPanel getInstance() { - if (instance == null) { - instance = new MultiUserCasesPanel(); - } - instance.refreshCasesTable(); - return instance; - } /** * Constructs a panel that allows a user to open cases created by automated * ingest. - * - * @param parent The parent dialog for this panel. */ - private MultiUserCasesPanel() { + MultiUserCasesPanel() { caseTableModel = new DefaultTableModel(columnNames, 0) { private static final long serialVersionUID = 1L; @@ -164,36 +153,57 @@ public class MultiUserCasesPanel extends javax.swing.JPanel { } setButtons(); }); - refreshCasesTable(); } /** * Gets the list of cases known to the review mode cases manager and * refreshes the cases table. */ - private void refreshCasesTable() { - try { - currentlySelectedCase = getSelectedCase(); - MultiUserCaseManager manager = MultiUserCaseManager.getInstance(); - List cases = manager.getCases(); - cases.sort(REVERSE_DATE_MODIFIED_COMPARATOR); - caseTableModel.setRowCount(0); - long now = new Date().getTime(); - for (MultiUserCase autoIngestCase : cases) { - if (passesTimeFilter(now, autoIngestCase.getLastAccessedDate().getTime())) { - caseTableModel.addRow(new Object[]{ - autoIngestCase.getCaseName(), - autoIngestCase.getCreationDate(), - autoIngestCase.getLastAccessedDate(), - (MultiUserCase.CaseStatus.OK != autoIngestCase.getStatus()), - autoIngestCase.getMetadataFilePath().toString()}); + void refreshCasesTable() { + EventQueue.invokeLater(() -> { + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + }); + + new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + try { + currentlySelectedCase = getSelectedCase(); + MultiUserCaseManager manager = MultiUserCaseManager.getInstance(); + List cases = manager.getCases(); + cases.sort(REVERSE_DATE_MODIFIED_COMPARATOR); + caseTableModel.setRowCount(0); + long now = new Date().getTime(); + for (MultiUserCase autoIngestCase : cases) { + if (passesTimeFilter(now, autoIngestCase.getLastAccessedDate().getTime())) { + caseTableModel.addRow(new Object[]{ + autoIngestCase.getCaseName(), + autoIngestCase.getCreationDate(), + autoIngestCase.getLastAccessedDate(), + (MultiUserCase.CaseStatus.OK != autoIngestCase.getStatus()), + autoIngestCase.getMetadataFilePath().toString()}); + } + } + setSelectedCase(currentlySelectedCase); + setButtons(); + } catch (Exception ex) { + LOGGER.log(Level.SEVERE, "Unexpected exception while refreshing the table.", ex); //NON-NLS + } + return null; + } + + @Override + protected void done() { + super.done(); + setCursor(null); + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + LOGGER.log(Level.SEVERE, "Unexpected exception while refreshing the table.", ex); //NON-NLS } } - setSelectedCase(currentlySelectedCase); - setButtons(); - } catch (Exception ex) { - LOGGER.log(Level.SEVERE, "Unexpected exception in refreshCasesTable", ex); //NON-NLS - } + }.execute(); } /** diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java b/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java index 3f92a97760..060061e205 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java @@ -32,7 +32,6 @@ import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.StartupWindowProvider; import org.sleuthkit.autopsy.core.UserPreferences; import static org.sleuthkit.autopsy.core.UserPreferences.SETTINGS_PROPERTIES; -import static org.sleuthkit.autopsy.core.UserPreferences.setMode; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; @@ -74,13 +73,18 @@ public class Installer extends ModuleInstall { super.uninstalled(); } + /** + * If the mode in the configuration file is 'REVIEW' (2, now invalid), this + * method will set it to 'STANDALONE' (0) and disable auto ingest. + */ private void updateConfig() { - // If mode is 'REVIEW' (2, now invalid), set it to 'STANDALONE' (0). - int ordinal = Integer.parseInt(ModuleSettings.getConfigSetting(SETTINGS_PROPERTIES, "AutopsyMode")); - if(ordinal > 1) { - setMode(UserPreferences.SelectedMode.STANDALONE); - ModuleSettings.setConfigSetting(UserPreferences.SETTINGS_PROPERTIES, "JoinAutoModeCluster", Boolean.toString(false)); - ordinal = 0; + String mode = ModuleSettings.getConfigSetting(SETTINGS_PROPERTIES, "AutopsyMode"); + if(mode != null) { + int ordinal = Integer.parseInt(mode); + if(ordinal > 1) { + UserPreferences.setMode(UserPreferences.SelectedMode.STANDALONE); + ModuleSettings.setConfigSetting(UserPreferences.SETTINGS_PROPERTIES, "JoinAutoModeCluster", Boolean.toString(false)); + } } } From 13f16c417de559662561418861ab87863d315f2d Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 27 Oct 2017 13:44:28 -0400 Subject: [PATCH 025/115] 3153 - sort Priority column in descending order --- .../experimental/autoingest/AutoIngestControlPanel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java index 26dcabff58..25b29e3665 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java @@ -1862,8 +1862,8 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { @Override public void toggleSortOrder(int column) { - if (!this.getModel().getColumnClass(column).equals(Date.class)) { - super.toggleSortOrder(column); //if it isn't a date perform the regular sorting + if (!this.getModel().getColumnClass(column).equals(Date.class) && !(this.getModel().getColumnName(column).equals(JobsTableModelColumns.PRIORITY.getColumnHeader()))) { + super.toggleSortOrder(column); //if it isn't a date or the Priority column perform the regular sorting } else { ArrayList sortKeys = new ArrayList<>(getSortKeys()); if (sortKeys.isEmpty() || sortKeys.get(0).getColumn() != column) { //sort descending From 6e6db52632294926498e50753b7e6b2aaf7240e3 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Fri, 27 Oct 2017 16:41:29 -0400 Subject: [PATCH 026/115] Chnages according to latest design --- .../autoingest/AddArchiveTask.java | 98 ++++++++++++------- 1 file changed, 63 insertions(+), 35 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index 80c4bb958e..c46067576a 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.experimental.autoingest; +import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -25,7 +26,10 @@ import java.util.List; import java.util.Map; import java.util.UUID; import java.util.logging.Level; +import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.LocalDiskDSProcessor; import org.sleuthkit.autopsy.casemodule.LocalFilesDSProcessor; @@ -89,7 +93,7 @@ class AddArchiveTask implements Runnable { } // extract the archive and pass the extracted folder as input - UUID taskId = UUID.randomUUID(); // ELTODO: do we want to come with a way to re-use task id? + UUID taskId = UUID.randomUUID(); if (callback instanceof AddDataSourceCallback) { // if running as part of automated ingest - re-use the task ID taskId = ((AddDataSourceCallback) callback).getTaskId(); @@ -97,12 +101,9 @@ class AddArchiveTask implements Runnable { try { Case currentCase = Case.getCurrentCase(); - // get file name without full path or extension - String dataSourceFileNameNoExt = FilenameUtils.getBaseName(archivePath); - // create folder to extract archive to - Path destinationFolder = Paths.get(currentCase.getModuleDirectory(), ARCHIVE_EXTRACTOR_MODULE_OUTPUT_DIR, dataSourceFileNameNoExt + "_" + TimeStampUtils.createTimeStamp()); - if (destinationFolder.toFile().mkdirs() == false) { + Path destinationFolder = createDirectoryForFile(archivePath, currentCase.getModuleDirectory()); + if (destinationFolder.toString().isEmpty()) { // unable to create directory criticalErrorOccurred = true; errorMessages.add("Unable to create directory for archive extraction " + destinationFolder.toString()); @@ -117,10 +118,9 @@ class AddArchiveTask implements Runnable { Map validDataSourceProcessorsMap; for (String file : extractedFiles) { progressMonitor.setProgressText(String.format("Adding: %s", file)); - Path filePath = Paths.get(file); // identify DSP for this file // lookup all AutomatedIngestDataSourceProcessors and poll which ones are able to process the current data source - validDataSourceProcessorsMap = DataSourceProcessorUtility.getDataSourceProcessor(filePath); + validDataSourceProcessorsMap = DataSourceProcessorUtility.getDataSourceProcessor(Paths.get(file)); if (validDataSourceProcessorsMap.isEmpty()) { continue; } @@ -138,14 +138,32 @@ class AddArchiveTask implements Runnable { if (selectedProcessor instanceof LocalFilesDSProcessor) { continue; } + // also skip nested archive files, those will be ingested as logical files and extracted during ingest + if (selectedProcessor instanceof ArchiveExtractorDSProcessor) { + continue; + } + + // identified a "valid" data source within the archive. + // Move it to a different folder + Path newFolder = createDirectoryForFile(file, currentCase.getModuleDirectory()); + if (newFolder.toString().isEmpty()) { + // unable to create directory + criticalErrorOccurred = true; + errorMessages.add("Unable to create directory for archive extraction " + newFolder.toString()); + logger.log(Level.SEVERE, "Unable to create directory for archive extraction {0}", newFolder.toString()); + return; + } + + FileUtils.moveFileToDirectory(new File(file), newFolder.toFile(), false); + Path newFilePath = Paths.get(newFolder.toString(), FilenameUtils.getName(file)); //jobLogger.logDataSourceProcessorSelected(selectedProcessor.getDataSourceType()); //SYS_LOGGER.log(Level.INFO, "Identified data source type for {0} as {1}", new Object[]{manifestPath, selectedProcessor.getDataSourceType()}); synchronized (archiveDspLock) { try { - DataSource internalDataSource = new DataSource(deviceId, filePath); + DataSource internalDataSource = new DataSource(deviceId, newFilePath); DataSourceProcessorCallback internalArchiveDspCallBack = new AddDataSourceCallback(currentCase, internalDataSource, taskId, archiveDspLock); - selectedProcessor.process(deviceId, filePath, progressMonitor, internalArchiveDspCallBack); + selectedProcessor.process(deviceId, newFilePath, progressMonitor, internalArchiveDspCallBack); archiveDspLock.wait(); // at this point we got the content object(s) from the current DSP @@ -161,37 +179,33 @@ class AddArchiveTask implements Runnable { //jobLogger.logDataSourceProcessorError(selectedProcessor.getDataSourceType()); criticalErrorOccurred = true; errorMessages.add(ex.getMessage()); - logger.log(Level.SEVERE, "Exception while processing {0} with data source processor {1}", new Object[]{file, selectedProcessor.getDataSourceType()}); + logger.log(Level.SEVERE, "Exception while processing {0} with data source processor {1}", new Object[]{newFilePath.toString(), selectedProcessor.getDataSourceType()}); } } } } - // after all archive contents have been ingested - all the archive itself as a logical file - progressMonitor.setProgressText(String.format("Adding: %s", archivePath)); - LocalFilesDSProcessor localFilesDSP = new LocalFilesDSProcessor(); + // after all archive contents have been examined, add remaining extracted contents as one logical file set + progressMonitor.setProgressText(String.format("Adding: %s", destinationFolder.toString())); synchronized (archiveDspLock) { - try { - Path filePath = Paths.get(archivePath); - DataSource internalDataSource = new DataSource(deviceId, filePath); - DataSourceProcessorCallback internalArchiveDspCallBack = new AddDataSourceCallback(currentCase, internalDataSource, taskId, archiveDspLock); - localFilesDSP.process(deviceId, filePath, progressMonitor, internalArchiveDspCallBack); - archiveDspLock.wait(); - - // at this point we got the content object(s) from the current DSP - newDataSources.addAll(internalDataSource.getContent()); - } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) { - // Log that the current DSP failed and set the error flag. We consider it an error - // if a DSP fails even if a later one succeeds since we expected to be able to process - // the data source which each DSP on the list. - //AutoIngestAlertFile.create(caseDirectoryPath); - //currentJob.setErrorsOccurred(true); - //jobLogger.logDataSourceProcessorError(selectedProcessor.getDataSourceType()); - criticalErrorOccurred = true; - errorMessages.add(ex.getMessage()); - logger.log(Level.SEVERE, "Exception while processing {0} with data source processor {1}", new Object[]{archivePath, localFilesDSP.getDataSourceType()}); - } - } + DataSource internalDataSource = new DataSource(deviceId, destinationFolder); + DataSourceProcessorCallback internalArchiveDspCallBack = new AddDataSourceCallback(currentCase, internalDataSource, taskId, archiveDspLock); + + // folder where archive was extracted to + List pathsList = new ArrayList<>(); + pathsList.add(destinationFolder.toString()); + + // use archive file name as the name of the logical file set + String archiveFileName = FilenameUtils.getName(archivePath); + + LocalFilesDSProcessor localFilesDSP = new LocalFilesDSProcessor(); + localFilesDSP.run(deviceId, archiveFileName, pathsList, progressMonitor, internalArchiveDspCallBack); + + archiveDspLock.wait(); + + // at this point we got the content object(s) from the current DSP + newDataSources.addAll(internalDataSource.getContent()); + } } catch (Exception ex) { criticalErrorOccurred = true; errorMessages.add(ex.getMessage()); @@ -208,6 +222,20 @@ class AddArchiveTask implements Runnable { callback.done(result, errorMessages, newDataSources); } } + + + private Path createDirectoryForFile(String fileName, String baseDirectory) { + // get file name without full path or extension + String fileNameNoExt = FilenameUtils.getBaseName(fileName); + + // create folder to extract archive to + Path newFolder = Paths.get(baseDirectory, ARCHIVE_EXTRACTOR_MODULE_OUTPUT_DIR, fileNameNoExt + "_" + TimeStampUtils.createTimeStamp()); + if (newFolder.toFile().mkdirs() == false) { + // unable to create directory + return Paths.get(""); + } + return newFolder; + } /* * Attempts to cancel adding the archive to the case database. From 2b59bf85648baef4751afb5fd7083b781a0c13c5 Mon Sep 17 00:00:00 2001 From: esaunders Date: Mon, 30 Oct 2017 16:35:21 -0400 Subject: [PATCH 027/115] Update comment to hopefully clear up why all keyword hits are processed in loadPageInfoFromHits() --- .../sleuthkit/autopsy/keywordsearch/HighlightedText.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedText.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedText.java index b8bb93b240..57e8aa91c4 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedText.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedText.java @@ -205,7 +205,13 @@ class HighlightedText implements IndexedText { */ synchronized private void loadPageInfoFromHits() { isLiteral = hits.getQuery().isLiteral(); - //organize the hits by page, filter as needed + + /** + * Organize the hits by page, filter as needed. + * We process *every* keyword here because in the case of a regular + * expression search there may be multiple different keyword + * hits located in different chunks for the same file/artifact. + */ for (Keyword k : hits.getKeywords()) { for (KeywordHit hit : hits.getResults(k)) { int chunkID = hit.getChunkId(); From 4a17cf3f75f7aa0d25fc23599d5750d886c48791 Mon Sep 17 00:00:00 2001 From: esaunders Date: Mon, 30 Oct 2017 16:39:55 -0400 Subject: [PATCH 028/115] Don't store document id string in the hit. --- .../src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java index e51c1c2620..196e0e7c39 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java @@ -38,7 +38,6 @@ class KeywordHit implements Comparable { private static final String GET_CONTENT_ID_FROM_ARTIFACT_ID = "SELECT obj_id FROM blackboard_artifacts WHERE artifact_id = "; - private final String solrDocumentId; private final long solrObjectId; private final int chunkId; private final String snippet; @@ -63,7 +62,6 @@ class KeywordHit implements Comparable { KeywordHit(String solrDocumentId, String snippet, String hit) throws TskCoreException { this.snippet = StringUtils.stripToEmpty(snippet); this.hit = hit; - this.solrDocumentId = solrDocumentId; /* * Parse the Solr document id to get the Solr object id and chunk id. @@ -112,7 +110,7 @@ class KeywordHit implements Comparable { } String getSolrDocumentId() { - return this.solrDocumentId; + return Long.toString(solrObjectId) + Server.CHUNK_ID_SEPARATOR + Long.toString(chunkId); } long getSolrObjectId() { From 5d2a632011c95d6da9e487c30a1491523948363a Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 30 Oct 2017 16:39:58 -0400 Subject: [PATCH 029/115] Improvements --- .../autoingest/AddArchiveTask.java | 96 +++++++++++-------- 1 file changed, 56 insertions(+), 40 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index c46067576a..0b121c902c 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -28,8 +28,6 @@ import java.util.UUID; import java.util.logging.Level; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; -import org.openide.filesystems.FileObject; -import org.openide.filesystems.FileUtil; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.LocalDiskDSProcessor; import org.sleuthkit.autopsy.casemodule.LocalFilesDSProcessor; @@ -40,8 +38,8 @@ import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; import org.sleuthkit.datamodel.Content; /* - * A runnable that adds an archive data source as well as data sources - * contained in the archive to the case database. + * A runnable that adds an archive data source as well as data sources contained + * in the archive to the case database. */ class AddArchiveTask implements Runnable { @@ -59,13 +57,13 @@ class AddArchiveTask implements Runnable { * Constructs a runnable task that adds an archive as well as data sources * contained in the archive to the case database. * - * @param deviceId An ASCII-printable identifier for the device associated - * with the data source that is intended to be unique across multiple cases - * (e.g., a UUID). - * @param archivePath Path to the archive file. + * @param deviceId An ASCII-printable identifier for the device + * associated with the data source that is intended + * to be unique across multiple cases (e.g., a UUID). + * @param archivePath Path to the archive file. * @param progressMonitor Progress monitor to report progress during - * processing. - * @param callback Callback to call when processing is done. + * processing. + * @param callback Callback to call when processing is done. */ AddArchiveTask(String deviceId, String archivePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { this.deviceId = deviceId; @@ -106,8 +104,8 @@ class AddArchiveTask implements Runnable { if (destinationFolder.toString().isEmpty()) { // unable to create directory criticalErrorOccurred = true; - errorMessages.add("Unable to create directory for archive extraction " + destinationFolder.toString()); - logger.log(Level.SEVERE, "Unable to create directory for archive extraction {0}", destinationFolder.toString()); + errorMessages.add(String.format("Unable to create directory {0} to extract archive {1} ", new Object[]{destinationFolder.toString(), archivePath})); + logger.log(Level.SEVERE, String.format("Unable to create directory {0} to extract archive {1} ", new Object[]{destinationFolder.toString(), archivePath})); return; } @@ -117,11 +115,19 @@ class AddArchiveTask implements Runnable { // do processing Map validDataSourceProcessorsMap; for (String file : extractedFiles) { - progressMonitor.setProgressText(String.format("Adding: %s", file)); + // identify DSP for this file - // lookup all AutomatedIngestDataSourceProcessors and poll which ones are able to process the current data source - validDataSourceProcessorsMap = DataSourceProcessorUtility.getDataSourceProcessor(Paths.get(file)); - if (validDataSourceProcessorsMap.isEmpty()) { + try { + // lookup all AutomatedIngestDataSourceProcessors and poll which ones are able to process the current data source + validDataSourceProcessorsMap = DataSourceProcessorUtility.getDataSourceProcessor(Paths.get(file)); + if (validDataSourceProcessorsMap.isEmpty()) { + continue; + } + } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) { + criticalErrorOccurred = true; + errorMessages.add(ex.getMessage()); + logger.log(Level.SEVERE, String.format("Critical error occurred while extracting archive %s", archivePath), ex); //NON-NLS + // continue to next extracted file continue; } @@ -130,7 +136,7 @@ class AddArchiveTask implements Runnable { // Try each DSP in decreasing order of confidence for (AutoIngestDataSourceProcessor selectedProcessor : validDataSourceProcessors) { - + // skip local files and local disk DSPs, only looking for "valid" data sources if (selectedProcessor instanceof LocalDiskDSProcessor) { continue; @@ -142,23 +148,35 @@ class AddArchiveTask implements Runnable { if (selectedProcessor instanceof ArchiveExtractorDSProcessor) { continue; } - - // identified a "valid" data source within the archive. - // Move it to a different folder + + // identified a "valid" data source within the archive + progressMonitor.setProgressText(String.format("Adding: %s", file)); + + /* + * NOTE: we have to move the valid data sources to a + * separate folder and then add the data source from that + * folder. This is necessary because after all valid data + * sources have been identified, we are going to add the + * remaining extracted contents of the archive as a single + * logacl file set. Hence, if we do not move the data + * sources out of the extracted contents folder, those data + * source files will get added twice and can potentially + * result in duplicate keyword hits. + */ Path newFolder = createDirectoryForFile(file, currentCase.getModuleDirectory()); if (newFolder.toString().isEmpty()) { // unable to create directory criticalErrorOccurred = true; - errorMessages.add("Unable to create directory for archive extraction " + newFolder.toString()); - logger.log(Level.SEVERE, "Unable to create directory for archive extraction {0}", newFolder.toString()); + errorMessages.add(String.format("Unable to create directory {0} to extract content of archive {1} ", new Object[]{newFolder.toString(), archivePath})); + logger.log(Level.SEVERE, String.format("Unable to create directory {0} to extract content of archive {1} ", new Object[]{newFolder.toString(), archivePath})); return; } - + + // Move it to a different folder FileUtils.moveFileToDirectory(new File(file), newFolder.toFile(), false); Path newFilePath = Paths.get(newFolder.toString(), FilenameUtils.getName(file)); - - //jobLogger.logDataSourceProcessorSelected(selectedProcessor.getDataSourceType()); - //SYS_LOGGER.log(Level.INFO, "Identified data source type for {0} as {1}", new Object[]{manifestPath, selectedProcessor.getDataSourceType()}); + + // ELTBD - do we want to log this in case log and/or system admin log? synchronized (archiveDspLock) { try { DataSource internalDataSource = new DataSource(deviceId, newFilePath); @@ -169,14 +187,12 @@ class AddArchiveTask implements Runnable { // at this point we got the content object(s) from the current DSP newDataSources.addAll(internalDataSource.getContent()); - break; // skip all other DSPs for this file + // skip all other DSPs for this data source + break; } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) { // Log that the current DSP failed and set the error flag. We consider it an error // if a DSP fails even if a later one succeeds since we expected to be able to process // the data source which each DSP on the list. - //AutoIngestAlertFile.create(caseDirectoryPath); - //currentJob.setErrorsOccurred(true); - //jobLogger.logDataSourceProcessorError(selectedProcessor.getDataSourceType()); criticalErrorOccurred = true; errorMessages.add(ex.getMessage()); logger.log(Level.SEVERE, "Exception while processing {0} with data source processor {1}", new Object[]{newFilePath.toString(), selectedProcessor.getDataSourceType()}); @@ -184,25 +200,26 @@ class AddArchiveTask implements Runnable { } } } - - // after all archive contents have been examined, add remaining extracted contents as one logical file set + + // after all archive contents have been examined (and moved to separate folders if necessary), + // add remaining extracted contents as one logical file set progressMonitor.setProgressText(String.format("Adding: %s", destinationFolder.toString())); synchronized (archiveDspLock) { - DataSource internalDataSource = new DataSource(deviceId, destinationFolder); + DataSource internalDataSource = new DataSource(deviceId, destinationFolder); DataSourceProcessorCallback internalArchiveDspCallBack = new AddDataSourceCallback(currentCase, internalDataSource, taskId, archiveDspLock); - + // folder where archive was extracted to List pathsList = new ArrayList<>(); pathsList.add(destinationFolder.toString()); - + // use archive file name as the name of the logical file set String archiveFileName = FilenameUtils.getName(archivePath); - + LocalFilesDSProcessor localFilesDSP = new LocalFilesDSProcessor(); localFilesDSP.run(deviceId, archiveFileName, pathsList, progressMonitor, internalArchiveDspCallBack); - + archiveDspLock.wait(); - + // at this point we got the content object(s) from the current DSP newDataSources.addAll(internalDataSource.getContent()); } @@ -222,8 +239,7 @@ class AddArchiveTask implements Runnable { callback.done(result, errorMessages, newDataSources); } } - - + private Path createDirectoryForFile(String fileName, String baseDirectory) { // get file name without full path or extension String fileNameNoExt = FilenameUtils.getBaseName(fileName); From 988fc1b40bcda1264f2a7b714b6db41e6ef26f57 Mon Sep 17 00:00:00 2001 From: esaunders Date: Mon, 30 Oct 2017 17:00:35 -0400 Subject: [PATCH 030/115] Removed contentID and isArtifactHit from KeywordHit. --- .../autopsy/keywordsearch/KeywordHit.java | 66 ++++++++++--------- .../autopsy/keywordsearch/RegexQuery.java | 4 +- .../keywordsearch/TermsComponentQuery.java | 2 +- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java index 196e0e7c39..f9284e81d9 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java @@ -41,8 +41,6 @@ class KeywordHit implements Comparable { private final long solrObjectId; private final int chunkId; private final String snippet; - private final long contentID; - private final boolean hitOnArtifact; private final String hit; /** @@ -55,11 +53,8 @@ class KeywordHit implements Comparable { * For some searches (ie substring, regex) this will be * different than the search term. * - * @throws TskCoreException If there is a problem getting the underlying - * content associated with a hit on the text of an - * artifact. */ - KeywordHit(String solrDocumentId, String snippet, String hit) throws TskCoreException { + KeywordHit(String solrDocumentId, String snippet, String hit) { this.snippet = StringUtils.stripToEmpty(snippet); this.hit = hit; @@ -81,28 +76,6 @@ class KeywordHit implements Comparable { this.solrObjectId = Long.parseLong(split[0]); this.chunkId = Integer.parseInt(split[1]); } - - //artifacts have negative obj ids - hitOnArtifact = this.solrObjectId < 0; - - if (hitOnArtifact) { - // If the hit was in an artifact, look up the source content for the artifact. - SleuthkitCase caseDb = Case.getCurrentCase().getSleuthkitCase(); - try (SleuthkitCase.CaseDbQuery executeQuery = - caseDb.executeQuery(GET_CONTENT_ID_FROM_ARTIFACT_ID + this.solrObjectId); - ResultSet resultSet = executeQuery.getResultSet();) { - if (resultSet.next()) { - contentID = resultSet.getLong("obj_id"); - } else { - throw new TskCoreException("Failed to get obj_id for artifact with artifact_id =" + this.solrObjectId + ". No matching artifact was found."); - } - } catch (SQLException ex) { - throw new TskCoreException("Error getting obj_id for artifact with artifact_id =" + this.solrObjectId, ex); - } - } else { - //else the object id is for content. - contentID = this.solrObjectId; - } } String getHit() { @@ -129,8 +102,36 @@ class KeywordHit implements Comparable { return this.snippet; } - long getContentID() { - return this.contentID; + /** + * Get the content id associated with the content underlying hit. + * For hits on files this will be the same as the object id associated + * with the file. For hits on artifacts we look up the id of the object + * that produced the artifact. + * + * @return The id of the underlying content associated with the hit. + * @throws TskCoreException If there is a problem getting the underlying + * content associated with a hit on the text of an + * artifact. + */ + long getContentID() throws TskCoreException { + if (isArtifactHit()) { + // If the hit was in an artifact, look up the source content for the artifact. + SleuthkitCase caseDb = Case.getCurrentCase().getSleuthkitCase(); + try (SleuthkitCase.CaseDbQuery executeQuery = + caseDb.executeQuery(GET_CONTENT_ID_FROM_ARTIFACT_ID + this.solrObjectId); + ResultSet resultSet = executeQuery.getResultSet();) { + if (resultSet.next()) { + return resultSet.getLong("obj_id"); + } else { + throw new TskCoreException("Failed to get obj_id for artifact with artifact_id =" + this.solrObjectId + ". No matching artifact was found."); + } + } catch (SQLException ex) { + throw new TskCoreException("Error getting obj_id for artifact with artifact_id =" + this.solrObjectId, ex); + } + } else { + //else the object id is for content. + return this.solrObjectId; + } } /** @@ -139,7 +140,8 @@ class KeywordHit implements Comparable { * @return */ boolean isArtifactHit() { - return hitOnArtifact; + // artifacts have negative obj ids + return this.solrObjectId < 0; } /** @@ -148,7 +150,7 @@ class KeywordHit implements Comparable { * @return The artifact whose indexed text this hit is in. */ Optional getArtifactID() { - if (hitOnArtifact) { + if (isArtifactHit()) { return Optional.of(solrObjectId); } else { return Optional.empty(); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java index 392a5e8bc8..6f1a574451 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java @@ -316,8 +316,6 @@ final class RegexQuery implements KeywordSearchQuery { } } - } catch (TskCoreException ex) { - throw ex; } catch (Throwable error) { /* * NOTE: Matcher.find() is known to throw StackOverflowError in rare @@ -447,7 +445,7 @@ final class RegexQuery implements KeywordSearchQuery { if (hit.isArtifactHit()) { LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for artifact keyword hit: term = %s, snippet = '%s', artifact id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getArtifactID().get())); //NON-NLS } else { - LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getContentID())); //NON-NLS + LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getSolrObjectId())); //NON-NLS } return null; } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermsComponentQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermsComponentQuery.java index 58087c4590..5953f6f35f 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermsComponentQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermsComponentQuery.java @@ -366,7 +366,7 @@ final class TermsComponentQuery implements KeywordSearchQuery { if (hit.isArtifactHit()) { LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for artifact keyword hit: term = %s, snippet = '%s', artifact id = %d", searchTerm, hit.getSnippet(), hit.getArtifactID().get())); //NON-NLS } else { - LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", searchTerm, hit.getSnippet(), hit.getContentID())); //NON-NLS + LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", searchTerm, hit.getSnippet(), hit.getSolrObjectId())); //NON-NLS } return null; } From 33a72835a4ae713e10864877db232e4316a9f52f Mon Sep 17 00:00:00 2001 From: esaunders Date: Mon, 30 Oct 2017 17:17:45 -0400 Subject: [PATCH 031/115] Reduce number of string instances created by re-using existing hit string for both the Keyword and KeywordHit instances. --- .../autopsy/keywordsearch/RegexQuery.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java index 6f1a574451..acefc554a4 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java @@ -100,6 +100,16 @@ final class RegexQuery implements KeywordSearchQuery { private String escapedQuery; private String field = Server.Schema.CONTENT_STR.toString(); + /** + * The following map is an optimization to ensure that we are referencing + * the same keyword hit String object in both the KeywordHit instance and + * it's associated Keyword instance. Even though we benefit from G1GC + * String deduplication, the overhead associated with both Keyword and + * KeywordHit maintaining their own reference can be significant when the + * number of hits gets large. + */ + private final HashMap keywordsFoundAcrossAllDocuments; + /** * Constructor with query to process. * @@ -113,6 +123,7 @@ final class RegexQuery implements KeywordSearchQuery { this.queryStringContainsWildcardPrefix = this.keywordString.startsWith(".*"); this.queryStringContainsWildcardSuffix = this.keywordString.endsWith(".*"); + this.keywordsFoundAcrossAllDocuments = new HashMap<>(); } @Override @@ -273,6 +284,14 @@ final class RegexQuery implements KeywordSearchQuery { hit = hit.replaceAll("[^0-9]$", ""); } + // Optimization to reduce the number of String objects created. + if (keywordsFoundAcrossAllDocuments.containsKey(hit)) { + // Use an existing String reference if it exists. + hit = keywordsFoundAcrossAllDocuments.get(hit); + } else { + keywordsFoundAcrossAllDocuments.put(hit, hit); + } + if (artifactAttributeType == null) { hits.add(new KeywordHit(docId, makeSnippet(content, hitMatcher, hit), hit)); } else { @@ -303,7 +322,7 @@ final class RegexQuery implements KeywordSearchQuery { final String group = ccnMatcher.group("ccn"); if (CreditCardValidator.isValidCCN(group)) { hits.add(new KeywordHit(docId, makeSnippet(content, hitMatcher, hit), hit)); - }; + } } } From b4456ff85355a3f08933c25afea40fbbeb0a4940 Mon Sep 17 00:00:00 2001 From: esaunders Date: Mon, 30 Oct 2017 17:21:58 -0400 Subject: [PATCH 032/115] Provided a more accurate comment for the keywordsFoundAcrossAllDocuments member. --- .../sleuthkit/autopsy/keywordsearch/RegexQuery.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java index acefc554a4..9c92cdea5d 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java @@ -101,12 +101,11 @@ final class RegexQuery implements KeywordSearchQuery { private String field = Server.Schema.CONTENT_STR.toString(); /** - * The following map is an optimization to ensure that we are referencing - * the same keyword hit String object in both the KeywordHit instance and - * it's associated Keyword instance. Even though we benefit from G1GC - * String deduplication, the overhead associated with both Keyword and - * KeywordHit maintaining their own reference can be significant when the - * number of hits gets large. + * The following map is an optimization to ensure that we reuse + * the same keyword hit String object across all hits. Even though we + * benefit from G1GC String deduplication, the overhead associated with + * creating a new String object for every KeywordHit can be significant + * when the number of hits gets large. */ private final HashMap keywordsFoundAcrossAllDocuments; From 761884534a36da52060c164e084b25f20451ff71 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Thu, 28 Sep 2017 11:58:33 -0400 Subject: [PATCH 033/115] 3095: Expanding Data Sources Node in nightly test --- .../autopsy/testing/AutopsyTestCases.java | 24 +++++++++++++++++++ .../autopsy/testing/RegressionTest.java | 5 ++++ 2 files changed, 29 insertions(+) diff --git a/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java b/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java index 672ca5b22b..c716081672 100755 --- a/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java +++ b/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java @@ -36,6 +36,7 @@ import java.util.logging.Logger; import javax.imageio.ImageIO; import javax.swing.JDialog; import javax.swing.text.JTextComponent; +import javax.swing.tree.TreePath; import org.netbeans.jellytools.MainWindowOperator; import org.netbeans.jellytools.NbDialogOperator; import org.netbeans.jellytools.WizardOperator; @@ -53,6 +54,8 @@ import org.netbeans.jemmy.operators.JTabbedPaneOperator; import org.netbeans.jemmy.operators.JTableOperator; import org.netbeans.jemmy.operators.JTextFieldOperator; import org.netbeans.jemmy.operators.JToggleButtonOperator; +import org.netbeans.jemmy.operators.JTreeOperator; +import org.netbeans.jemmy.operators.JTreeOperator.NoSuchPathException; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.core.UserPreferencesException; import org.sleuthkit.autopsy.events.MessageServiceConnectionInfo; @@ -290,6 +293,16 @@ public class AutopsyTestCases { } + public void testExpandDataSourcesTree() { + logger.info("Data Sources Node"); + MainWindowOperator mwo = MainWindowOperator.getDefault(); + JTreeOperator jto = new JTreeOperator(mwo, "Data Sources"); + String [] nodeNames = {"Data Sources"}; + TreePath tp = jto.findPath(nodeNames); + expandNodes(jto, tp); + screenshot("Data Sources Tree"); + } + public void testGenerateReportToolbar() { logger.info("Generate Report Toolbars"); MainWindowOperator mwo = MainWindowOperator.getDefault(); @@ -380,4 +393,15 @@ public class AutopsyTestCases { logger.log(Level.SEVERE, "Error saving messaging service connection info", ex); //NON-NLS } } + + private void expandNodes (JTreeOperator jto, TreePath tp) { + try { + jto.expandPath(tp); + for (TreePath t : jto.getChildPaths(tp)) { + expandNodes(jto, t); + } + } catch (NoSuchPathException ne) { + logger.log(Level.SEVERE, "Error expanding tree path", ne); + } + } } diff --git a/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java b/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java index 674395e0f1..0518da865b 100755 --- a/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java +++ b/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java @@ -69,6 +69,7 @@ public class RegressionTest extends TestCase { "testConfigureSearch", "testAddSourceWizard1", "testIngest", + "testExpandDataSourcesTree", //After do ingest, before generate report, we expand Data Sources node "testGenerateReportToolbar", "testGenerateReportButton"); } @@ -83,6 +84,7 @@ public class RegressionTest extends TestCase { "testConfigureSearch", "testAddSourceWizard1", "testIngest", + "testExpandDataSourcesTree", "testGenerateReportToolbar", "testGenerateReportButton"); } @@ -147,6 +149,9 @@ public class RegressionTest extends TestCase { autopsyTests.testIngest(); } + public void testExpandDataSourcesTree() { + autopsyTests.testExpandDataSourcesTree(); + } public void testGenerateReportToolbar() { autopsyTests.testGenerateReportToolbar(); } From d480a08bf100443f102f60946336c4ea5b7fa8bf Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 31 Oct 2017 16:32:21 -0400 Subject: [PATCH 034/115] Removal of examiner mode. --- .../AutoIngestCasePanelInterface.java | 29 - .../autopsy/casemodule/Bundle.properties | 33 +- .../autopsy/casemodule/Bundle_ja.properties | 9 +- .../autopsy/casemodule/CaseDeleteAction.java | 3 +- .../autopsy/casemodule/CaseOpenAction.java | 2 +- .../casemodule/CaseOpenMultiUserAction.java | 104 +++ .../autopsy/casemodule/CueBannerPanel.form | 20 +- .../autopsy/casemodule/CueBannerPanel.java | 94 +- .../autopsy/casemodule/MultiUserCase.java | 286 ++++++ .../casemodule/MultiUserCaseManager.java | 136 +++ .../casemodule/MultiUserCasesDialog.java | 81 ++ .../casemodule/MultiUserCasesPanel.form | 20 +- .../casemodule/MultiUserCasesPanel.java | 407 ++++---- .../autopsy/core/UserPreferences.java | 6 +- Core/src/org/sleuthkit/autopsy/core/layer.xml | 8 +- .../autopsy/corecomponents/Installer.java | 19 + .../CaseStatusIconCellRenderer.java | 11 +- .../coreutils}/GrayableCellRenderer.java | 8 +- .../coreutils}/LongDateCellRenderer.java | 6 +- .../autopsy/coreutils}/TimeStampUtils.java | 4 +- .../autoingest/AddArchiveTask.java | 1 + .../autoingest/AutoIngestCase.java | 189 ---- .../autoingest/AutoIngestCaseManager.java | 162 ---- .../autoingest/AutoIngestCaseOpenAction.java | 99 -- .../autoingest/AutoIngestControlPanel.java | 2 + .../autoingest/AutoIngestDashboard.java | 2 + .../AutoIngestDashboardOpenAction.java | 4 +- .../autoingest/AutoIngestManager.java | 4 +- .../experimental/autoingest/Bundle.properties | 11 +- .../autoingest/CaseImportPanel.java | 1 - .../CenteredGrayableCellRenderer.java | 3 +- .../autoingest/DurationCellRenderer.java | 24 + .../experimental/autoingest/PathUtils.java | 1 + .../autoingest/ShortDateCellRenderer.java | 24 + .../autoingest/SingleUserCaseImporter.java | 1 + .../AutoIngestSettingsPanel.form | 884 +++++++----------- .../AutoIngestSettingsPanel.java | 745 ++++++--------- .../configuration/Bundle.properties | 29 +- 38 files changed, 1589 insertions(+), 1883 deletions(-) delete mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/AutoIngestCasePanelInterface.java create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesDialog.java rename Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.form => Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.form (84%) rename Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java => Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java (64%) rename {Experimental/src/org/sleuthkit/autopsy/experimental/autoingest => Core/src/org/sleuthkit/autopsy/coreutils}/CaseStatusIconCellRenderer.java (82%) rename {Experimental/src/org/sleuthkit/autopsy/experimental/autoingest => Core/src/org/sleuthkit/autopsy/coreutils}/GrayableCellRenderer.java (91%) rename {Experimental/src/org/sleuthkit/autopsy/experimental/autoingest => Core/src/org/sleuthkit/autopsy/coreutils}/LongDateCellRenderer.java (91%) rename {Experimental/src/org/sleuthkit/autopsy/experimental/autoingest => Core/src/org/sleuthkit/autopsy/coreutils}/TimeStampUtils.java (97%) delete mode 100755 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCase.java delete mode 100755 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseManager.java delete mode 100755 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseOpenAction.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AutoIngestCasePanelInterface.java b/Core/src/org/sleuthkit/autopsy/casemodule/AutoIngestCasePanelInterface.java deleted file mode 100755 index 795b636b35..0000000000 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AutoIngestCasePanelInterface.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2017 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.casemodule; - -import javax.swing.JDialog; - -/** - * Interface for startup window implementations - */ -public interface AutoIngestCasePanelInterface { - - public void addWindowStateListener(JDialog parent); -} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 25b43a423a..5b80fd80ba 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -1,10 +1,10 @@ -CTL_AddImage=Add Data Source... +CTL_AddImage=Add Data Source CTL_AddImageButton=Add Data Source CTL_CaseCloseAct=Close Case -CTL_CaseNewAction=New Case... -CTL_CasePropertiesAction=Case Properties... +CTL_CaseNewAction=New Case +CTL_CasePropertiesAction=Case Properties CTL_CaseDeleteAction=Delete Case -CTL_OpenAction=Open Case... +CTL_OpenAction=Open Case Menu/Case/OpenRecentCase=Open Recent Case CTL_CaseDeleteAction=Delete Case OpenIDE-Module-Name=Case @@ -210,11 +210,32 @@ CasePropertiesPanel.lbDbName.text=Database Name: CasePropertiesPanel.lbDbType.text=Case Type: CasePropertiesPanel.caseNumberLabel.text=Case Number: LocalDiskPanel.changeDatabasePathCheckbox.text=Update case to use VHD file upon completion -CueBannerPanel.openAutoIngestCaseButton.text= +CueBannerPanel.openMultiUserCaseButton.text= CueBannerPanel.openExistingCaseButton.text= CueBannerPanel.openRecentCaseButton.text= CueBannerPanel.createNewCaseButton.text= CueBannerPanel.createNewCaseLabel.text=Create New Case CueBannerPanel.openRecentCaseLabel.text=Open Recent Case CueBannerPanel.openExistingCaseLabel.text=Open Existing Case -CueBannerPanel.openAutoIngestCaseLabel.text=Open Auto Ingest Case \ No newline at end of file +CueBannerPanel.openMultiUserCaseLabel.text=Open Multi-User Case +ReviewModeCasePanel.cannotOpenCase=Cannot Open Case +ReviewModeCasePanel.casePathNotFound=Case path not found +ReviewModeCasePanel.caseIsLocked=Single-user case is locked. +ReviewModeCasePanel.CaseHeaderText=Case +ReviewModeCasePanel.CreatedTimeHeaderText=Created Time +ReviewModeCasePanel.StatusIconHeaderText=Status +ReviewModeCasePanel.OutputFolderHeaderText=Output Folder +ReviewModeCasePanel.LastAccessedTimeHeaderText=Last Accessed Time +ReviewModeCasePanel.MetadataFileHeaderText=Metadata File +OpenMultiUserCasePanel.jLabel1.text=Recent Cases +OpenMultiUserCasePanel.openButton.text=Open +OpenMultiUserCasePanel.cancelButton.text=Cancel +MultiUserCasesPanel.rbWeeks.text=Weeks +MultiUserCasesPanel.rbDays.text=Days +MultiUserCasesPanel.bnShowLog.toolTipText=Display case log file for selected case +MultiUserCasesPanel.bnShowLog.text=&Show Auto Ingest Case Log +MultiUserCasesPanel.rbAllCases.text=Everything +MultiUserCasesPanel.bnRefresh.text=&Refresh +MultiUserCasesPanel.bnOpen.text=&Open +MultiUserCasesPanel.rbGroupLabel.text=Show cases accessed in the last 10: +MultiUserCasesPanel.rbMonths.text=Months diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties index e212a125e9..de333e790f 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties @@ -1,9 +1,9 @@ CTL_AddImageButton=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u3092\u8ffd\u52a0 CTL_CaseCloseAct=\u30b1\u30fc\u30b9\u3092\u9589\u3058\u308b -CTL_CaseNewAction=\u65b0\u898f\u30b1\u30fc\u30b9... -CTL_CasePropertiesAction=\u30b1\u30fc\u30b9\u30d7\u30ed\u30d1\u30c6\u30a3... +CTL_CaseNewAction=\u65b0\u898f\u30b1\u30fc\u30b9 +CTL_CasePropertiesAction=\u30b1\u30fc\u30b9\u30d7\u30ed\u30d1\u30c6\u30a3 CTL_CaseDeleteAction=\u30b1\u30fc\u30b9\u3092\u524a\u9664 -CTL_OpenAction=\u30b1\u30fc\u30b9\u3092\u958b\u304f... +CTL_CaseOpenAction=\u30b1\u30fc\u30b9\u3092\u958b\u304f Menu/Case/OpenRecentCase=\u6700\u8fd1\u958b\u3044\u305f\u30b1\u30fc\u30b9\u3092\u958b\u304f CTL_CaseDeleteAction=\u30b1\u30fc\u30b9\u3092\u524a\u9664 OpenIDE-Module-Name=\u30b1\u30fc\u30b9 @@ -194,3 +194,6 @@ CueBannerPanel.createNewCaseLabel.text=\u65b0\u898f\u30b1\u30fc\u30b9\u3092\u4f5 CueBannerPanel.openRecentCaseLabel.text=\u6700\u8fd1\u958b\u3044\u305f\u30b1\u30fc\u30b9\u3092\u958b\u304f CueBannerPanel.openExistingCaseLabel.text=\u65e2\u5b58\u30b1\u30fc\u30b9\u3092\u958b\u304f CueBannerPanel.openAutoIngestCaseLabel.text=\u65e2\u5b58\u30b1\u30fc\u30b9\u3092\u958b\u304f +OpenMultiUserCasePanel.openButton.text=\u958b\u304f +OpenMultiUserCasePanel.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb +OpenMultiUserCasePanel.jLabel1.text=\u6700\u8fd1\u958b\u3044\u305f\u30d5\u30a1\u30a4\u30eb diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java index 3ef30f2594..b95ad78edf 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java @@ -33,7 +33,6 @@ import org.openide.util.HelpCtx; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; -import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; /** @@ -51,7 +50,7 @@ final class CaseDeleteAction extends CallableSystemAction { putValue(Action.NAME, NbBundle.getMessage(CaseDeleteAction.class, "CTL_CaseDeleteAction")); this.setEnabled(false); Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> { - setEnabled(null != evt.getNewValue() && UserPreferences.getMode() != UserPreferences.SelectedMode.REVIEW); + setEnabled(null != evt.getNewValue()); }); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java index 533cab58c5..e4ed92d897 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java @@ -141,7 +141,7 @@ public final class CaseOpenAction extends CallableSystemAction implements Action @Override public String getName() { - return NbBundle.getMessage(CaseOpenAction.class, "CTL_OpenAction"); + return NbBundle.getMessage(CaseOpenAction.class, "CTL_CaseOpenAction"); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java new file mode 100755 index 0000000000..76607210c5 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java @@ -0,0 +1,104 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.casemodule; + +import java.awt.Dialog; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.KeyStroke; +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.NetworkUtils; + +/** + * The action associated with the Open Multi-User Case menu item via the + * layer.xml file. + * + * This action should only be invoked in the event dispatch thread (EDT). + */ +@ActionID(category = "Case", id = "org.sleuthkit.autopsy.casemodule.CaseOpenMultiUserAction") +@ActionReference(path = "Menu/Case", position = 102) +@ActionRegistration(displayName = "#CTL_CaseOpenMultiUserAction", lazy = false) +@NbBundle.Messages({"CTL_CaseOpenMultiUserAction=Open Multi-User Case"}) +public final class CaseOpenMultiUserAction extends CallableSystemAction implements ActionListener { + + private static final long serialVersionUID = 1L; + private static JDialog multiUserCaseWindow; + + private static final String DISPLAY_NAME = Bundle.CTL_CaseOpenMultiUserAction(); + private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName(); + private static final String REVIEW_MODE_TITLE = "Open Multi-User Case (" + LOCAL_HOST_NAME + ")"; + + public CaseOpenMultiUserAction() {} + + public static void closeMultiUserCasesWindow() { + if (null != multiUserCaseWindow) { + multiUserCaseWindow.setVisible(false); + } + } + + @Override + public boolean isEnabled() { + return UserPreferences.getIsMultiUserModeEnabled(); + } + + /** + * Pops up a case selection panel to allow the user to selecte a multi-user + * case to open. + * + * @param e The action event. + */ + @Override + public void actionPerformed(ActionEvent event) { + if(multiUserCaseWindow == null) { + multiUserCaseWindow = MultiUserCasesDialog.getInstance(); + } + multiUserCaseWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); + multiUserCaseWindow.setVisible(true); + } + + @Override + public void performAction() { + actionPerformed(null); + } + + @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/casemodule/CueBannerPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.form index 75819e41d0..0d6525db8b 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.form @@ -28,14 +28,14 @@ - + - + @@ -66,9 +66,9 @@ - + - + @@ -216,13 +216,13 @@ - + - + @@ -237,18 +237,18 @@ - + - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java index 2d7b17458e..c4c15fdd91 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java @@ -26,14 +26,11 @@ import java.awt.event.KeyEvent; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JDialog; -import javax.swing.JPanel; import javax.swing.KeyStroke; import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.casemodule.AutoIngestCasePanelInterface; import org.sleuthkit.autopsy.core.UserPreferences; -import org.sleuthkit.autopsy.coreutils.NetworkUtils; /* * The panel in the default Autopsy startup window. @@ -41,14 +38,13 @@ import org.sleuthkit.autopsy.coreutils.NetworkUtils; public class CueBannerPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; - private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName(); - private static final String REVIEW_MODE_TITLE = "Cases" + " (" + LOCAL_HOST_NAME + ")"; + private static final String REVIEW_MODE_TITLE = "Open Multi-User Case"; /* * This is field is static for the sake of the closeOpenRecentCasesWindow * method. */ private static JDialog recentCasesWindow; - private static JDialog autoIngestCasePanelWindow; + private static JDialog multiUserCaseWindow; public static void closeOpenRecentCasesWindow() { if (null != recentCasesWindow) { @@ -56,9 +52,9 @@ public class CueBannerPanel extends javax.swing.JPanel { } } - public static void closeAutoIngestCasesWindow() { - if (null != autoIngestCasePanelWindow) { - autoIngestCasePanelWindow.setVisible(false); + public static void closeMultiUserCasesWindow() { + if (null != multiUserCaseWindow) { + multiUserCaseWindow.setVisible(false); } } @@ -93,7 +89,6 @@ public class CueBannerPanel extends javax.swing.JPanel { private void customizeComponents() { initRecentCasesWindow(); - initAutoIngestCasesWindow(); } private void initRecentCasesWindow() { @@ -118,39 +113,15 @@ public class CueBannerPanel extends javax.swing.JPanel { recentCasesWindow.pack(); recentCasesWindow.setResizable(false); } - - private void initAutoIngestCasesWindow() { - autoIngestCasePanelWindow = new JDialog( - WindowManager.getDefault().getMainWindow(), - REVIEW_MODE_TITLE, - Dialog.ModalityType.APPLICATION_MODAL); - autoIngestCasePanelWindow.getRootPane().registerKeyboardAction( - e -> { - autoIngestCasePanelWindow.setVisible(false); - }, - KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); - OpenRecentCasePanel recentCasesPanel = OpenRecentCasePanel.getInstance(); - recentCasesPanel.setCloseButtonActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - autoIngestCasePanelWindow.setVisible(false); - } - }); - AutoIngestCasePanelInterface autoIngestCasePanel = Lookup.getDefault().lookup(AutoIngestCasePanelInterface.class); - autoIngestCasePanel.addWindowStateListener(autoIngestCasePanelWindow); - autoIngestCasePanelWindow.add((JPanel)autoIngestCasePanel); - autoIngestCasePanelWindow.pack(); - autoIngestCasePanelWindow.setResizable(false); - } private void enableComponents() { boolean enableOpenRecentCaseButton = (RecentCases.getInstance().getTotalRecentCases() > 0); openRecentCaseButton.setEnabled(enableOpenRecentCaseButton); openRecentCaseLabel.setEnabled(enableOpenRecentCaseButton); - boolean showOpenAutoIngestCaseButton = (UserPreferences.getMode() == UserPreferences.SelectedMode.REVIEW); - openAutoIngestCaseButton.setVisible(showOpenAutoIngestCaseButton); - openAutoIngestCaseLabel.setVisible(showOpenAutoIngestCaseButton); + boolean enableOpenMultiUserCaseButton = UserPreferences.getIsMultiUserModeEnabled(); + openMultiUserCaseButton.setEnabled(enableOpenMultiUserCaseButton); + openMultiUserCaseLabel.setEnabled(enableOpenMultiUserCaseButton); } /** @@ -172,8 +143,8 @@ public class CueBannerPanel extends javax.swing.JPanel { openExistingCaseLabel = new javax.swing.JLabel(); closeButton = new javax.swing.JButton(); jSeparator1 = new javax.swing.JSeparator(); - openAutoIngestCaseButton = new javax.swing.JButton(); - openAutoIngestCaseLabel = new javax.swing.JLabel(); + openMultiUserCaseButton = new javax.swing.JButton(); + openMultiUserCaseLabel = new javax.swing.JLabel(); autopsyLogo.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/welcome_logo.png"))); // NOI18N autopsyLogo.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.autopsyLogo.text")); // NOI18N @@ -229,21 +200,21 @@ public class CueBannerPanel extends javax.swing.JPanel { jSeparator1.setOrientation(javax.swing.SwingConstants.VERTICAL); - openAutoIngestCaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/btn_icon_open_existing.png"))); // NOI18N - openAutoIngestCaseButton.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openAutoIngestCaseButton.text")); // NOI18N - openAutoIngestCaseButton.setBorder(null); - openAutoIngestCaseButton.setBorderPainted(false); - openAutoIngestCaseButton.setContentAreaFilled(false); - openAutoIngestCaseButton.setMargin(new java.awt.Insets(1, 1, 1, 1)); - openAutoIngestCaseButton.setPreferredSize(new java.awt.Dimension(64, 64)); - openAutoIngestCaseButton.addActionListener(new java.awt.event.ActionListener() { + openMultiUserCaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/btn_icon_open_existing.png"))); // NOI18N + openMultiUserCaseButton.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openMultiUserCaseButton.text")); // NOI18N + openMultiUserCaseButton.setBorder(null); + openMultiUserCaseButton.setBorderPainted(false); + openMultiUserCaseButton.setContentAreaFilled(false); + openMultiUserCaseButton.setMargin(new java.awt.Insets(1, 1, 1, 1)); + openMultiUserCaseButton.setPreferredSize(new java.awt.Dimension(64, 64)); + openMultiUserCaseButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - openAutoIngestCaseButtonActionPerformed(evt); + openMultiUserCaseButtonActionPerformed(evt); } }); - openAutoIngestCaseLabel.setFont(openAutoIngestCaseLabel.getFont().deriveFont(openAutoIngestCaseLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 13)); - openAutoIngestCaseLabel.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openAutoIngestCaseLabel.text")); // NOI18N + openMultiUserCaseLabel.setFont(openMultiUserCaseLabel.getFont().deriveFont(openMultiUserCaseLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 13)); + openMultiUserCaseLabel.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openMultiUserCaseLabel.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -261,13 +232,13 @@ public class CueBannerPanel extends javax.swing.JPanel { .addComponent(createNewCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(openRecentCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(openExistingCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(openAutoIngestCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(openMultiUserCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(createNewCaseLabel) .addComponent(openRecentCaseLabel) .addComponent(openExistingCaseLabel) - .addComponent(openAutoIngestCaseLabel))) + .addComponent(openMultiUserCaseLabel))) .addComponent(closeButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 73, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap()) ); @@ -290,9 +261,9 @@ public class CueBannerPanel extends javax.swing.JPanel { .addComponent(openExistingCaseLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(openAutoIngestCaseButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 58, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(openMultiUserCaseButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 58, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(openAutoIngestCaseLabel) + .addComponent(openMultiUserCaseLabel) .addGap(20, 20, 20)))) .addComponent(jSeparator1) .addComponent(autopsyLogo, javax.swing.GroupLayout.PREFERRED_SIZE, 257, javax.swing.GroupLayout.PREFERRED_SIZE)) @@ -316,10 +287,13 @@ public class CueBannerPanel extends javax.swing.JPanel { recentCasesWindow.setVisible(true); }//GEN-LAST:event_openRecentCaseButtonActionPerformed - private void openAutoIngestCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openAutoIngestCaseButtonActionPerformed - autoIngestCasePanelWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); - autoIngestCasePanelWindow.setVisible(true); - }//GEN-LAST:event_openAutoIngestCaseButtonActionPerformed + private void openMultiUserCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openMultiUserCaseButtonActionPerformed + if(multiUserCaseWindow == null) { + multiUserCaseWindow = MultiUserCasesDialog.getInstance(); + } + multiUserCaseWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); + multiUserCaseWindow.setVisible(true); + }//GEN-LAST:event_openMultiUserCaseButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel autopsyLogo; @@ -327,8 +301,8 @@ public class CueBannerPanel extends javax.swing.JPanel { private javax.swing.JButton createNewCaseButton; private javax.swing.JLabel createNewCaseLabel; private javax.swing.JSeparator jSeparator1; - private javax.swing.JButton openAutoIngestCaseButton; - private javax.swing.JLabel openAutoIngestCaseLabel; + private javax.swing.JButton openMultiUserCaseButton; + private javax.swing.JLabel openMultiUserCaseLabel; private javax.swing.JButton openExistingCaseButton; private javax.swing.JLabel openExistingCaseLabel; private javax.swing.JButton openRecentCaseButton; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java new file mode 100755 index 0000000000..502ff260b1 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java @@ -0,0 +1,286 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015-2017 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.casemodule; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Comparator; +import java.util.Date; +import java.util.Objects; +import java.util.logging.Level; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.TimeStampUtils; + +/** + * A representation of a case created by automated ingest. + */ +class MultiUserCase implements Comparable { + + private static final Logger logger = Logger.getLogger(MultiUserCase.class.getName()); + private final Path caseDirectoryPath; + private final String caseDisplayName; + private final String metadataFileName; + private final Date createDate; + private final Date lastAccessedDate; + + /** + * Constructs a representation of case created by automated ingest. + * + * @param caseDirectoryPath The case directory path. + * + * @throws CaseMetadata.CaseMetadataException If the CaseMetadata object + * cannot be constructed for the + * case display name. + * @throws MultiUserCaseException If no case metadata (.aut) + * file is found in the case + * directory. + */ + MultiUserCase(Path caseDirectoryPath) throws CaseMetadata.CaseMetadataException, MultiUserCaseException { + CaseMetadata caseMetadata = null; + + try { + caseMetadata = getCaseMetadataFromCaseDirectoryPath(caseDirectoryPath); + } catch (CaseMetadata.CaseMetadataException ex) { + logger.log(Level.SEVERE, String.format("Error reading the case metadata for %s.", caseDirectoryPath), ex); + throw ex; + } + + this.caseDirectoryPath = caseDirectoryPath; + caseDisplayName = caseMetadata.getCaseDisplayName(); + metadataFileName = caseMetadata.getFilePath().getFileName().toString(); + BasicFileAttributes fileAttrs = null; + try { + fileAttrs = Files.readAttributes(Paths.get(caseDirectoryPath.toString(), metadataFileName), BasicFileAttributes.class); + } catch (IOException ex) { + logger.log(Level.SEVERE, String.format("Error reading file attributes of case metadata file in %s, will use current time for case createDate/lastModfiedDate", caseDirectoryPath), ex); + } + if (null != fileAttrs) { + createDate = new Date(fileAttrs.creationTime().toMillis()); + lastAccessedDate = new Date(fileAttrs.lastAccessTime().toMillis()); + } else { + createDate = new Date(); + lastAccessedDate = new Date(); + } + } + + /** + * Gets the case directory path. + * + * @return The case directory path. + */ + Path getCaseDirectoryPath() { + return this.caseDirectoryPath; + } + + /** + * Gets the case display name. This may differ from the name supplied to the + * directory or metadata file names if a case has been renamed. + * + * @return The case display name. + */ + String getCaseDisplayName() { + return this.caseDisplayName; + } + + /** + * Gets the creation date for the case, defined as the create time of the + * case metadata file. + * + * @return The case creation date. + */ + Date getCreationDate() { + return this.createDate; + } + + /** + * Gets the last accessed date for the case, defined as the last accessed + * time of the case metadata file. + * + * @return The last accessed date. + */ + Date getLastAccessedDate() { + return this.lastAccessedDate; + } + + /** + * Gets metadata (.aut) file name. + * + * @return The metadata file name. + */ + String getMetadataFileName() { + return this.metadataFileName; + } + + /** + * Gets the status of this case based on the auto ingest result file in the + * case directory. + * + * @return See CaseStatus enum definition. + */ + CaseStatus getStatus() { + if(caseDirectoryPath.resolve("autoingest.alert").toFile().exists()) { + return CaseStatus.ALERT; + } else { + return CaseStatus.OK; + } + } + + /** + * Gets the case metadata from a case directory path. + * + * @param caseDirectoryPath The case directory path. + * + * @return Case metadata. + * + * @throws CaseMetadata.CaseMetadataException If the CaseMetadata object + * cannot be constructed. + * @throws MultiUserCaseException If no case metadata (.aut) + * file is found in the case + * directory. + */ + private static CaseMetadata getCaseMetadataFromCaseDirectoryPath(Path caseDirectoryPath) throws CaseMetadata.CaseMetadataException, MultiUserCaseException { + CaseMetadata caseMetadata = null; + + File directory = new File(caseDirectoryPath.toString()); + if (directory.isDirectory()) { + File autFile = null; + + /* + * Attempt to find an AUT file via a directory scan. + */ + for (File file : directory.listFiles()) { + if (file.getName().toLowerCase().endsWith(CaseMetadata.getFileExtension()) && file.isFile()) { + autFile = file; + break; + } + } + + if(autFile == null || !autFile.isFile()) { + throw new MultiUserCaseException(String.format("No case metadata (.aut) file found in the case directory '%s'.", caseDirectoryPath.toString())); + } + + caseMetadata = new CaseMetadata(Paths.get(autFile.getAbsolutePath())); + } + + return caseMetadata; + } + + /** + * Indicates whether or not some other object is "equal to" this + * MultiUserCase object. + * + * @param other The other object. + * + * @return True or false. + */ + @Override + public boolean equals(Object other) { + if (!(other instanceof MultiUserCase)) { + return false; + } + if (other == this) { + return true; + } + return this.caseDirectoryPath.toString().equals(((MultiUserCase) other).caseDirectoryPath.toString()); + } + + /** + * Returns a hash code value for this MultiUserCase object. + * + * @return The has code. + */ + @Override + public int hashCode() { + int hash = 7; + hash = 71 * hash + Objects.hashCode(this.caseDirectoryPath); + hash = 71 * hash + Objects.hashCode(this.createDate); + hash = 71 * hash + Objects.hashCode(this.caseDisplayName); + return hash; + } + + /** + * Compares this AutopIngestCase object with abnother MultiUserCase object + * for order. + */ + @Override + public int compareTo(MultiUserCase other) { + return -this.lastAccessedDate.compareTo(other.getLastAccessedDate()); + } + + /** + * Comparator for a descending order sort on date created. + */ + static class LastAccessedDateDescendingComparator implements Comparator { + + /** + * Compares two MultiUserCase objects for order based on last accessed + * date (descending). + * + * @param object The first MultiUserCase object + * @param otherObject The second AuotIngestCase object. + * + * @return A negative integer, zero, or a positive integer as the first + * argument is less than, equal to, or greater than the second. + */ + @Override + public int compare(MultiUserCase object, MultiUserCase otherObject) { + return -object.getLastAccessedDate().compareTo(otherObject.getLastAccessedDate()); + } + } + + /** + * Exception thrown when there is a problem creating a multi-user case. + */ + final static class MultiUserCaseException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructs an exception to throw when there is a problem creating a + * multi-user case. + * + * @param message The exception message. + */ + private MultiUserCaseException(String message) { + super(message); + } + + /** + * Constructs an exception to throw when there is a problem creating a + * multi-user case. + * + * @param message The exception message. + * @param cause The cause of the exception, if it was an exception. + */ + private MultiUserCaseException(String message, Throwable cause) { + super(message, cause); + } + } + + enum CaseStatus { + + OK, + ALERT + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java new file mode 100755 index 0000000000..3101461443 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java @@ -0,0 +1,136 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.casemodule; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import org.sleuthkit.autopsy.coordinationservice.CoordinationService; +import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; + +/** + * Handles locating and opening multi-user cases. + */ +final class MultiUserCaseManager { + + private static MultiUserCaseManager instance; + + private CoordinationService coordinationService; + + /** + * Gets the multi-user case manager. + * + * @return The multi-user case manager singleton. + * + * @throws MultiUserCaseManagerException + */ + synchronized static MultiUserCaseManager getInstance() throws MultiUserCaseManager.MultiUserCaseManagerException { + if (null == instance) { + instance = new MultiUserCaseManager(); + } + return instance; + } + + /** + * Constructs an object that handles locating and opening multi-user cases. + * + * @throws MultiUserCaseManagerException + */ + private MultiUserCaseManager() throws MultiUserCaseManagerException { + try { + coordinationService = CoordinationService.getInstance(); + } catch (CoordinationServiceException ex) { + throw new MultiUserCaseManager.MultiUserCaseManagerException("Failed to get the coordination service.", ex); + } + } + + /** + * Gets a list of the cases in the top level case folder + * + * @return List of cases. + * + * @throws CoordinationServiceException + */ + List getCases() throws CoordinationServiceException { + List cases = new ArrayList<>(); + List nodeList = coordinationService.getNodeList(CoordinationService.CategoryNode.CASES); + for (String node : nodeList) { + Path casePath = Paths.get(node); + File caseFolder = casePath.toFile(); + if(caseFolder.exists()) { + File[] autFiles = caseFolder.listFiles((dir, name) -> name.toLowerCase().endsWith(".aut")); + if(autFiles != null && autFiles.length > 0) { + try { + cases.add(new MultiUserCase(casePath)); + } catch (CaseMetadata.CaseMetadataException | MultiUserCase.MultiUserCaseException ex) { + // Ignore and continue. + } + } + } + } + return cases; + } + + /** + * Opens a multi-user case. + * + * @param caseMetadataFilePath Path to the case metadata file. + * + * @throws CaseActionException + */ + synchronized void openCase(Path caseMetadataFilePath) throws CaseActionException { + /* + * Open the case. + */ + Case.openAsCurrentCase(caseMetadataFilePath.toString()); + } + + /** + * Exception type thrown when there is an error completing a multi-user case + * manager operation. + */ + static final class MultiUserCaseManagerException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructs an instance of the exception type thrown when there is an + * error completing a multi-user case manager operation. + * + * @param message The exception message. + */ + private MultiUserCaseManagerException(String message) { + super(message); + } + + /** + * Constructs an instance of the exception type thrown when there is an + * error completing a multi-user case manager operation. + * + * @param message The exception message. + * @param cause A Throwable cause for the error. + */ + private MultiUserCaseManagerException(String message, Throwable cause) { + super(message, cause); + } + + } +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesDialog.java new file mode 100755 index 0000000000..b6d9feeb7e --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesDialog.java @@ -0,0 +1,81 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.casemodule; + +import java.awt.Dialog; +import java.awt.event.KeyEvent; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.KeyStroke; +import org.openide.windows.WindowManager; + +/** + * This class extends a JDialog and maintains the MultiUserCasesPanel. + */ +public class MultiUserCasesDialog extends JDialog { + private static final String REVIEW_MODE_TITLE = "Open Multi-User Case"; + private final MultiUserCasesPanel multiUserCasesPanel; + private static MultiUserCasesDialog instance; + + /** + * Gets the instance of the MultiuserCasesDialog. + * + * @return The instance. + */ + static public MultiUserCasesDialog getInstance() { + if(instance == null) { + instance = new MultiUserCasesDialog(); + } + return instance; + } + + /** + * Constructs a MultiUserCasesDialog object. + */ + MultiUserCasesDialog() { + super(WindowManager.getDefault().getMainWindow(), + REVIEW_MODE_TITLE, + Dialog.ModalityType.APPLICATION_MODAL); + + getRootPane().registerKeyboardAction( + e -> { + setVisible(false); + }, + KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); + + multiUserCasesPanel = new MultiUserCasesPanel(); + add(multiUserCasesPanel); + pack(); + setResizable(false); + } + + /** + * Set the dialog visibility. When setting it to visible, the contents will + * refresh. + * + * @param value True or false. + */ + @Override + public void setVisible(boolean value) { + if(value) { + multiUserCasesPanel.refreshCasesTable(); + } + super.setVisible(value); + } +} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.form similarity index 84% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.form rename to Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.form index cb0f275809..179bc23bb8 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.form @@ -45,7 +45,7 @@ - + @@ -82,7 +82,7 @@ - + @@ -118,7 +118,7 @@ - + @@ -153,7 +153,7 @@ - + @@ -165,10 +165,10 @@ - + - + @@ -182,7 +182,7 @@ - + @@ -196,7 +196,7 @@ - + @@ -209,7 +209,7 @@ - + @@ -222,7 +222,7 @@ - + diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java similarity index 64% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java rename to Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java index 2bcd335916..bce0a33602 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java @@ -16,52 +16,38 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.casemodule; import java.awt.Cursor; import java.awt.Desktop; import java.awt.EventQueue; -import java.awt.event.ActionEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Date; import java.util.List; import java.util.concurrent.ExecutionException; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; import java.util.logging.Level; -import javax.swing.JDialog; import javax.swing.JOptionPane; -import javax.swing.JPanel; import javax.swing.SwingWorker; import javax.swing.event.ListSelectionEvent; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableColumn; -import org.openide.util.NbBundle; -import org.openide.util.lookup.ServiceProvider; -import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.casemodule.CaseActionCancelledException; -import org.sleuthkit.autopsy.casemodule.CaseMetadata; -import org.sleuthkit.autopsy.casemodule.StartupWindowProvider; +import org.sleuthkit.autopsy.coreutils.CaseStatusIconCellRenderer; +import org.sleuthkit.autopsy.coreutils.GrayableCellRenderer; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.LongDateCellRenderer; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.casemodule.AutoIngestCasePanelInterface; -import org.sleuthkit.autopsy.casemodule.CueBannerPanel; -import org.sleuthkit.autopsy.coreutils.NetworkUtils; -import org.sleuthkit.autopsy.experimental.configuration.StartupWindow; /** * A panel that allows a user to open cases created by auto ingest. */ -@ServiceProvider(service = AutoIngestCasePanelInterface.class) -public final class AutoIngestCasePanel extends JPanel implements AutoIngestCasePanelInterface { +public class MultiUserCasesPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; - private static final Logger logger = Logger.getLogger(AutoIngestCasePanel.class.getName()); - private static final AutoIngestCase.LastAccessedDateDescendingComparator reverseDateModifiedComparator = new AutoIngestCase.LastAccessedDateDescendingComparator(); + private static final Logger LOGGER = Logger.getLogger(MultiUserCasesPanel.class.getName()); + private static final String LOG_FILE_NAME = "auto_ingest_log.txt"; + private static final MultiUserCase.LastAccessedDateDescendingComparator REVERSE_DATE_MODIFIED_COMPARATOR = new MultiUserCase.LastAccessedDateDescendingComparator(); private static final int CASE_COL_MIN_WIDTH = 30; private static final int CASE_COL_MAX_WIDTH = 2000; private static final int CASE_COL_PREFERRED_WIDTH = 300; @@ -71,9 +57,6 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP private static final int STATUS_COL_MIN_WIDTH = 55; private static final int STATUS_COL_MAX_WIDTH = 250; private static final int STATUS_COL_PREFERRED_WIDTH = 60; - private static final int MILLIS_TO_WAIT_BEFORE_STARTING = 500; - private static final int MILLIS_TO_WAIT_BETWEEN_UPDATES = 300000; - private ScheduledThreadPoolExecutor casesTableRefreshExecutor; /* * The JTable table model for the cases table presented by this view is @@ -82,11 +65,12 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP * TODO (RC): Consider unifying this stuff in an enum as in * AutoIngestDashboard to make it less error prone. */ - private static final String CASE_HEADER = org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "ReviewModeCasePanel.CaseHeaderText"); - private static final String CREATEDTIME_HEADER = org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "ReviewModeCasePanel.CreatedTimeHeaderText"); - private static final String COMPLETEDTIME_HEADER = org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "ReviewModeCasePanel.LastAccessedTimeHeaderText"); - private static final String STATUS_ICON_HEADER = org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "ReviewModeCasePanel.StatusIconHeaderText"); - private static final String OUTPUT_FOLDER_HEADER = org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "ReviewModeCasePanel.OutputFolderHeaderText"); + private static final String CASE_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.CaseHeaderText"); + private static final String CREATEDTIME_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.CreatedTimeHeaderText"); + private static final String COMPLETEDTIME_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.LastAccessedTimeHeaderText"); + private static final String STATUS_ICON_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.StatusIconHeaderText"); + private static final String OUTPUT_FOLDER_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.OutputFolderHeaderText"); + private static final String METADATA_FILE_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.MetadataFileHeaderText"); enum COLUMN_HEADERS { @@ -94,51 +78,18 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP CREATEDTIME, COMPLETEDTIME, STATUS_ICON, - OUTPUTFOLDER + OUTPUTFOLDER, + METADATA_FILE } - private final String[] columnNames = {CASE_HEADER, CREATEDTIME_HEADER, COMPLETEDTIME_HEADER, STATUS_ICON_HEADER, OUTPUT_FOLDER_HEADER}; + private final String[] columnNames = {CASE_HEADER, CREATEDTIME_HEADER, COMPLETEDTIME_HEADER, STATUS_ICON_HEADER, OUTPUT_FOLDER_HEADER, METADATA_FILE_HEADER}; private DefaultTableModel caseTableModel; private Path currentlySelectedCase = null; - - public AutoIngestCasePanel() { - init(null); - } - - @Override - public void addWindowStateListener(JDialog parent) { - /* - * Add a window state listener that starts and stops refreshing of the - * cases table. - */ - parent.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - stopCasesTableRefreshes(); - } - - @Override - public void windowActivated(WindowEvent e) { - startCasesTableRefreshes(); - } - - @Override - public void windowClosed(WindowEvent e) { - stopCasesTableRefreshes(); - } - }); - } /** * Constructs a panel that allows a user to open cases created by automated * ingest. - * - * @param parent The parent dialog for this panel. */ - public AutoIngestCasePanel(JDialog parent) { - init(parent); - } - - public void init(JDialog parent) { + MultiUserCasesPanel() { caseTableModel = new DefaultTableModel(columnNames, 0) { private static final long serialVersionUID = 1L; @@ -146,6 +97,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP public boolean isCellEditable(int row, int column) { return false; } + @Override public Class getColumnClass(int col) { if (this.getColumnName(col).equals(CREATEDTIME_HEADER) || this.getColumnName(col).equals(COMPLETEDTIME_HEADER)) { @@ -191,6 +143,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP theColumn.setWidth(STATUS_COL_PREFERRED_WIDTH); casesTable.removeColumn(casesTable.getColumn(OUTPUT_FOLDER_HEADER)); + casesTable.removeColumn(casesTable.getColumn(METADATA_FILE_HEADER)); /* * Listen for row selection changes and set button state for the current @@ -203,76 +156,58 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP } setButtons(); }); - - /* - * Add a window state listener that starts and stops refreshing of the - * cases table. - */ - if (parent != null) { - parent.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - stopCasesTableRefreshes(); - } - - @Override - public void windowActivated(WindowEvent e) { - startCasesTableRefreshes(); - } - - @Override - public void windowClosed(WindowEvent e) { - stopCasesTableRefreshes(); - } - }); - } - } - - /** - * Start doing periodic refreshes of the cases table. - */ - private void startCasesTableRefreshes() { - if (null == casesTableRefreshExecutor) { - casesTableRefreshExecutor = new ScheduledThreadPoolExecutor(1); - this.casesTableRefreshExecutor.scheduleAtFixedRate(() -> { - refreshCasesTable(); - }, MILLIS_TO_WAIT_BEFORE_STARTING, MILLIS_TO_WAIT_BETWEEN_UPDATES, TimeUnit.MILLISECONDS); - } - } - - /** - * Stop doing periodic refreshes of the cases table. - */ - private void stopCasesTableRefreshes() { - if (null != casesTableRefreshExecutor) { - casesTableRefreshExecutor.shutdown(); - } - this.casesTableRefreshExecutor = null; - } - - /* - * Updates the view presented by the panel. - */ - public void updateView() { - Thread thread = new Thread(() -> { - refreshCasesTable(); - }); - thread.start(); } /** * Gets the list of cases known to the review mode cases manager and * refreshes the cases table. */ - private void refreshCasesTable() { - try { - currentlySelectedCase = getSelectedCase(); - AutoIngestCaseManager manager = AutoIngestCaseManager.getInstance(); - List theModel = manager.getCases(); - EventQueue.invokeLater(new CaseTableRefreshTask(theModel)); - } catch (Exception ex) { - logger.log(Level.SEVERE, "Unexpected exception in refreshCasesTable", ex); //NON-NLS - } + void refreshCasesTable() { + EventQueue.invokeLater(() -> { + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + }); + + new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + try { + currentlySelectedCase = getSelectedCase(); + MultiUserCaseManager manager = MultiUserCaseManager.getInstance(); + List cases = manager.getCases(); + cases.sort(REVERSE_DATE_MODIFIED_COMPARATOR); + caseTableModel.setRowCount(0); + long now = new Date().getTime(); + for (MultiUserCase autoIngestCase : cases) { + if (passesTimeFilter(now, autoIngestCase.getLastAccessedDate().getTime())) { + caseTableModel.addRow(new Object[]{ + autoIngestCase.getCaseDisplayName(), + autoIngestCase.getCreationDate(), + autoIngestCase.getLastAccessedDate(), + (MultiUserCase.CaseStatus.OK != autoIngestCase.getStatus()), + autoIngestCase.getCaseDirectoryPath().toString(), + autoIngestCase.getMetadataFileName()}); + } + } + setSelectedCase(currentlySelectedCase); + setButtons(); + } catch (Exception ex) { + LOGGER.log(Level.SEVERE, "Unexpected exception while refreshing the table.", ex); //NON-NLS + } + return null; + } + + @Override + protected void done() { + super.done(); + setCursor(null); + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + LOGGER.log(Level.SEVERE, "Unexpected exception while refreshing the table.", ex); //NON-NLS + } + } + }.execute(); } /** @@ -320,9 +255,30 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP * in the cases table. */ private void setButtons() { - boolean enabled = casesTable.getSelectedRow() >= 0 && casesTable.getSelectedRow() < casesTable.getRowCount(); - bnOpen.setEnabled(enabled); - bnShowLog.setEnabled(enabled); + boolean openEnabled = casesTable.getSelectedRow() >= 0 && casesTable.getSelectedRow() < casesTable.getRowCount(); + bnOpen.setEnabled(openEnabled); + + Path pathToLog = getSelectedCaseLogFilePath(); + boolean showLogEnabled = openEnabled && pathToLog != null && pathToLog.toFile().exists(); + bnShowLog.setEnabled(showLogEnabled); + } + + /** + * Retrieves the log file path for the selected case in the cases table. + * + * @return The case log path. + */ + private Path getSelectedCaseLogFilePath() { + Path retValue = null; + + int selectedRow = casesTable.getSelectedRow(); + int rowCount = casesTable.getRowCount(); + if (selectedRow >= 0 && selectedRow < rowCount) { + String caseDirectory = (String) caseTableModel.getValueAt(casesTable.convertRowIndexToModel(selectedRow), COLUMN_HEADERS.OUTPUTFOLDER.ordinal()); + retValue = Paths.get(caseDirectory, LOG_FILE_NAME); + } + + return retValue; } /** @@ -332,91 +288,44 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP */ private void openCase(Path caseMetadataFilePath) { setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - new SwingWorker() { - - @Override - protected Void doInBackground() throws Exception { - AutoIngestCaseManager.getInstance().openCase(caseMetadataFilePath); - stopCasesTableRefreshes(); - StartupWindowProvider.getInstance().close(); - CueBannerPanel.closeAutoIngestCasesWindow(); - return null; + try { + StartupWindowProvider.getInstance().close(); + CueBannerPanel.closeMultiUserCasesWindow(); + CaseOpenMultiUserAction.closeMultiUserCasesWindow(); + MultiUserCaseManager.getInstance().openCase(caseMetadataFilePath); + } catch (CaseActionException | MultiUserCaseManager.MultiUserCaseManagerException ex) { + if (null != ex.getCause() && !(ex.getCause() instanceof CaseActionCancelledException)) { + LOGGER.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", caseMetadataFilePath), ex); //NON-NLS + MessageNotifyUtil.Message.error(ex.getCause().getLocalizedMessage()); } - - @Override - protected void done() { - try { - get(); - } catch (InterruptedException | ExecutionException ex) { - if (null != ex.getCause() && !(ex.getCause() instanceof CaseActionCancelledException)) { - logger.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", caseMetadataFilePath), ex); //NON-NLS - MessageNotifyUtil.Message.error(ex.getCause().getLocalizedMessage()); - } - StartupWindowProvider.getInstance().open(); - } finally { - setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - } - } - }.execute(); + StartupWindowProvider.getInstance().open(); + } finally { + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } } /** - * A task that refreshes the cases table using a list of auto ingest cases. + * Indicates whether or not a time satisfies a time filter defined by this + * panel's time filter radio buttons. + * + * @param currentTime The current date and time in milliseconds from the + * Unix epoch. + * @param inputTime The date and time to be tested as milliseconds from + * the Unix epoch. */ - private class CaseTableRefreshTask implements Runnable { - - private final List cases; - - CaseTableRefreshTask(List cases) { - setButtons(); - this.cases = cases; + private boolean passesTimeFilter(long currentTime, long inputTime) { + long numberOfUnits = 10; + long multiplier = 1; + if (rbAllCases.isSelected()) { + return true; + } else if (rbMonths.isSelected()) { + multiplier = 31; + } else if (rbWeeks.isSelected()) { + multiplier = 7; + } else if (rbDays.isSelected()) { + multiplier = 1; } - - /** - * @inheritDoc - */ - @Override - public void run() { - cases.sort(reverseDateModifiedComparator); - caseTableModel.setRowCount(0); - long now = new Date().getTime(); - for (AutoIngestCase autoIngestCase : cases) { - if (passesTimeFilter(now, autoIngestCase.getLastAccessedDate().getTime())) { - caseTableModel.addRow(new Object[]{ - autoIngestCase.getCaseName(), - autoIngestCase.getCreationDate(), - autoIngestCase.getLastAccessedDate(), - (AutoIngestCase.CaseStatus.OK != autoIngestCase.getStatus()), - autoIngestCase.getCaseDirectoryPath().toString()}); - } - } - setSelectedCase(currentlySelectedCase); - } - - /** - * Indicates whether or not a time satisfies a time filter defined by - * this panel's time filter radio buttons. - * - * @param currentTime The current date and time in milliseconds from the - * Unix epoch. - * @param inputTime The date and time to be tested as milliseconds - * from the Unix epoch. - */ - private boolean passesTimeFilter(long currentTime, long inputTime) { - long numberOfUnits = 10; - long multiplier = 1; - if (rbAllCases.isSelected()) { - return true; - } else if (rbMonths.isSelected()) { - multiplier = 31; - } else if (rbWeeks.isSelected()) { - multiplier = 7; - } else if (rbDays.isSelected()) { - multiplier = 1; - } - return ((currentTime - inputTime) / (1000 * 60 * 60 * 24)) < (numberOfUnits * multiplier); - } - + return ((currentTime - inputTime) / (1000 * 60 * 60 * 24)) < (numberOfUnits * multiplier); } /** @@ -443,7 +352,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP setName("Completed Cases"); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(bnOpen, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.bnOpen.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(bnOpen, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnOpen.text")); // NOI18N bnOpen.setEnabled(false); bnOpen.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -463,7 +372,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP }); scrollPaneTable.setViewportView(casesTable); - org.openide.awt.Mnemonics.setLocalizedText(bnRefresh, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.bnRefresh.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(bnRefresh, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnRefresh.text")); // NOI18N bnRefresh.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnRefreshActionPerformed(evt); @@ -472,7 +381,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP rbGroupHistoryLength.add(rbAllCases); rbAllCases.setSelected(true); - org.openide.awt.Mnemonics.setLocalizedText(rbAllCases, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbAllCases.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbAllCases, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbAllCases.text")); // NOI18N rbAllCases.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { rbAllCasesItemStateChanged(evt); @@ -494,8 +403,8 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP .addComponent(rbAllCases)) ); - org.openide.awt.Mnemonics.setLocalizedText(bnShowLog, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.bnShowLog.text")); // NOI18N - bnShowLog.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.bnShowLog.toolTipText")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(bnShowLog, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnShowLog.text")); // NOI18N + bnShowLog.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnShowLog.toolTipText")); // NOI18N bnShowLog.setEnabled(false); bnShowLog.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -504,7 +413,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP }); rbGroupHistoryLength.add(rbDays); - org.openide.awt.Mnemonics.setLocalizedText(rbDays, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbDays.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbDays, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbDays.text")); // NOI18N rbDays.setName(""); // NOI18N rbDays.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { @@ -513,7 +422,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP }); rbGroupHistoryLength.add(rbWeeks); - org.openide.awt.Mnemonics.setLocalizedText(rbWeeks, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbWeeks.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbWeeks, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbWeeks.text")); // NOI18N rbWeeks.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { rbWeeksItemStateChanged(evt); @@ -521,7 +430,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP }); rbGroupHistoryLength.add(rbMonths); - org.openide.awt.Mnemonics.setLocalizedText(rbMonths, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbMonths.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbMonths, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbMonths.text")); // NOI18N rbMonths.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { rbMonthsItemStateChanged(evt); @@ -529,7 +438,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP }); rbGroupLabel.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(rbGroupLabel, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbGroupLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbGroupLabel, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbGroupLabel.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -556,7 +465,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(bnRefresh) .addGap(4, 4, 4)) - .addComponent(scrollPaneTable, javax.swing.GroupLayout.DEFAULT_SIZE, 1007, Short.MAX_VALUE)) + .addComponent(scrollPaneTable)) .addContainerGap()) ); layout.setVerticalGroup( @@ -588,10 +497,12 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP */ private void bnOpenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOpenActionPerformed int modelRow = casesTable.convertRowIndexToModel(casesTable.getSelectedRow()); - Path caseMetadataFilePath = Paths.get((String) caseTableModel.getValueAt(modelRow, - COLUMN_HEADERS.OUTPUTFOLDER.ordinal()), - caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.CASE.ordinal()) + CaseMetadata.getFileExtension()); - openCase(caseMetadataFilePath); + String caseDirectory = (String) caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.OUTPUTFOLDER.ordinal()); + Path caseMetadataFilePath = Paths.get(caseDirectory, (String) caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.METADATA_FILE.ordinal())); + + new Thread(() -> { + openCase(caseMetadataFilePath); + }).start(); }//GEN-LAST:event_bnOpenActionPerformed /** @@ -599,53 +510,50 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP * * @param evt -- The event that caused this to be called */ - private void bnRefreshActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bnRefreshActionPerformed - {//GEN-HEADEREND:event_bnRefreshActionPerformed - updateView(); - }//GEN-LAST:event_bnRefreshActionPerformed + private void bnRefreshActionPerformed(java.awt.event.ActionEvent evt) { + refreshCasesTable(); + } - private void rbDaysItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbDaysItemStateChanged + private void rbDaysItemStateChanged(java.awt.event.ItemEvent evt) { if (rbDays.isSelected()) { - updateView(); + refreshCasesTable(); } - }//GEN-LAST:event_rbDaysItemStateChanged + } private void rbAllCasesItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbAllCasesItemStateChanged if (rbAllCases.isSelected()) { - updateView(); + refreshCasesTable(); } }//GEN-LAST:event_rbAllCasesItemStateChanged private void rbMonthsItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbMonthsItemStateChanged if (rbMonths.isSelected()) { - updateView(); + refreshCasesTable(); } }//GEN-LAST:event_rbMonthsItemStateChanged private void rbWeeksItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbWeeksItemStateChanged if (rbWeeks.isSelected()) { - updateView(); + refreshCasesTable(); } }//GEN-LAST:event_rbWeeksItemStateChanged private void bnShowLogActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnShowLogActionPerformed - int selectedRow = casesTable.convertRowIndexToModel(casesTable.getSelectedRow()); - int rowCount = casesTable.getRowCount(); - if (selectedRow >= 0 && selectedRow < rowCount) { - String thePath = (String) caseTableModel.getValueAt(selectedRow, COLUMN_HEADERS.OUTPUTFOLDER.ordinal()); - Path pathToLog = AutoIngestJobLogger.getLogPath(Paths.get(thePath)); + Path pathToLog = getSelectedCaseLogFilePath(); + if (pathToLog != null) { try { if (pathToLog.toFile().exists()) { Desktop.getDesktop().edit(pathToLog.toFile()); + } else { - JOptionPane.showMessageDialog(this, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "DisplayLogDialog.cannotFindLog"), - org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "DisplayLogDialog.unableToShowLogFile"), JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(this, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.cannotFindLog"), + org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.unableToShowLogFile"), JOptionPane.ERROR_MESSAGE); } } catch (IOException ex) { - logger.log(Level.SEVERE, String.format("Error attempting to open case auto ingest log file %s", pathToLog), ex); + LOGGER.log(Level.SEVERE, String.format("Error attempting to open case auto ingest log file %s", pathToLog), ex); JOptionPane.showMessageDialog(this, - org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "DisplayLogDialog.cannotOpenLog"), - org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "DisplayLogDialog.unableToShowLogFile"), + org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.cannotOpenLog"), + org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.unableToShowLogFile"), JOptionPane.PLAIN_MESSAGE); } } @@ -654,9 +562,8 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP private void casesTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_casesTableMouseClicked if (evt.getClickCount() == 2) { int modelRow = casesTable.convertRowIndexToModel(casesTable.getSelectedRow()); - Path caseMetadataFilePath = Paths.get((String) caseTableModel.getValueAt(modelRow, - COLUMN_HEADERS.OUTPUTFOLDER.ordinal()), - caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.CASE.ordinal()) + CaseMetadata.getFileExtension()); + String caseDirectory = (String) caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.OUTPUTFOLDER.ordinal()); + Path caseMetadataFilePath = Paths.get(caseDirectory, (String) caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.METADATA_FILE.ordinal())); openCase(caseMetadataFilePath); } }//GEN-LAST:event_casesTableMouseClicked diff --git a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java index df63b0fa1f..86f68e1df5 100755 --- a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java +++ b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2014-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,6 @@ import java.util.prefs.BackingStoreException; import org.sleuthkit.autopsy.events.MessageServiceConnectionInfo; import java.util.prefs.PreferenceChangeListener; import java.util.prefs.Preferences; -import org.openide.util.Exceptions; import org.openide.util.NbPreferences; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; @@ -76,8 +75,7 @@ public final class UserPreferences { public enum SelectedMode { STANDALONE, - AUTOINGEST, - REVIEW + AUTOINGEST }; /** diff --git a/Core/src/org/sleuthkit/autopsy/core/layer.xml b/Core/src/org/sleuthkit/autopsy/core/layer.xml index 95cfcd481e..fb5618c6e6 100755 --- a/Core/src/org/sleuthkit/autopsy/core/layer.xml +++ b/Core/src/org/sleuthkit/autopsy/core/layer.xml @@ -51,7 +51,7 @@ - + @@ -157,7 +157,7 @@ - + @@ -165,11 +165,11 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java b/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java index c908f3b35d..060061e205 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java @@ -30,7 +30,10 @@ import org.netbeans.swing.tabcontrol.plaf.DefaultTabbedContainerUI; import org.openide.modules.ModuleInstall; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.StartupWindowProvider; +import org.sleuthkit.autopsy.core.UserPreferences; +import static org.sleuthkit.autopsy.core.UserPreferences.SETTINGS_PROPERTIES; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; /** * Manages this module's life cycle. Opens the startup dialog during startup. @@ -59,6 +62,7 @@ public class Installer extends ModuleInstall { UIManager.put("ViewTabDisplayerUI", "org.sleuthkit.autopsy.corecomponents.NoTabsTabDisplayerUI"); UIManager.put(DefaultTabbedContainerUI.KEY_VIEW_CONTENT_BORDER, BorderFactory.createEmptyBorder()); UIManager.put("TabbedPane.contentBorderInsets", new Insets(0, 0, 0, 0)); + updateConfig(); WindowManager.getDefault().invokeWhenUIReady(() -> { StartupWindowProvider.getInstance().open(); }); @@ -68,6 +72,21 @@ public class Installer extends ModuleInstall { public void uninstalled() { super.uninstalled(); } + + /** + * If the mode in the configuration file is 'REVIEW' (2, now invalid), this + * method will set it to 'STANDALONE' (0) and disable auto ingest. + */ + private void updateConfig() { + String mode = ModuleSettings.getConfigSetting(SETTINGS_PROPERTIES, "AutopsyMode"); + if(mode != null) { + int ordinal = Integer.parseInt(mode); + if(ordinal > 1) { + UserPreferences.setMode(UserPreferences.SelectedMode.STANDALONE); + ModuleSettings.setConfigSetting(UserPreferences.SETTINGS_PROPERTIES, "JoinAutoModeCluster", Boolean.toString(false)); + } + } + } private void setLookAndFeel() { if (System.getProperty("os.name").toLowerCase().contains("mac")) { //NON-NLS diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseStatusIconCellRenderer.java b/Core/src/org/sleuthkit/autopsy/coreutils/CaseStatusIconCellRenderer.java similarity index 82% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseStatusIconCellRenderer.java rename to Core/src/org/sleuthkit/autopsy/coreutils/CaseStatusIconCellRenderer.java index 0010cc90ee..4d782a6f57 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseStatusIconCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/CaseStatusIconCellRenderer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,24 +16,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.coreutils; import java.awt.Component; import javax.swing.ImageIcon; import javax.swing.JTable; import static javax.swing.SwingConstants.CENTER; import org.openide.util.ImageUtilities; +import org.openide.util.NbBundle.Messages; /** * A JTable cell renderer that represents an auto ingest alert file exists flag * as a center-aligned icon, and grays out the cell if the table is disabled. */ -class CaseStatusIconCellRenderer extends GrayableCellRenderer { +public class CaseStatusIconCellRenderer extends GrayableCellRenderer { private static final long serialVersionUID = 1L; static final ImageIcon checkedIcon = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/experimental/images/tick.png", false)); static final ImageIcon warningIcon = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/experimental/images/warning16.png", false)); + @Messages({ + "CaseStatusIconCellRenderer.tooltiptext.ok=Images processed successfully", + "CaseStatusIconCellRenderer.tooltiptext.warning=An error occurred or processing was canceled for at least one image - please check the log" + }) @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { setHorizontalAlignment(CENTER); diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/GrayableCellRenderer.java b/Core/src/org/sleuthkit/autopsy/coreutils/GrayableCellRenderer.java similarity index 91% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/GrayableCellRenderer.java rename to Core/src/org/sleuthkit/autopsy/coreutils/GrayableCellRenderer.java index 60d3b77ccd..479f30bee2 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/GrayableCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/GrayableCellRenderer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.coreutils; import java.awt.Color; import java.awt.Component; @@ -28,11 +28,11 @@ import javax.swing.table.DefaultTableCellRenderer; * A JTable cell renderer that left-aligns cell content and grays out the cell * if the table is disabled. */ -class GrayableCellRenderer extends DefaultTableCellRenderer { +public class GrayableCellRenderer extends DefaultTableCellRenderer { private static final long serialVersionUID = 1L; - GrayableCellRenderer() { + public GrayableCellRenderer() { setHorizontalAlignment(LEFT); } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/LongDateCellRenderer.java b/Core/src/org/sleuthkit/autopsy/coreutils/LongDateCellRenderer.java similarity index 91% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/LongDateCellRenderer.java rename to Core/src/org/sleuthkit/autopsy/coreutils/LongDateCellRenderer.java index cfa2cedb14..e347b2d28a 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/LongDateCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/LongDateCellRenderer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.coreutils; import java.awt.Component; import java.text.SimpleDateFormat; @@ -28,7 +28,7 @@ import static javax.swing.SwingConstants.CENTER; * center-aligned, long-format date string. It also grays out the cell if the * table is disabled. */ -class LongDateCellRenderer extends GrayableCellRenderer { +public class LongDateCellRenderer extends GrayableCellRenderer { private static final long serialVersionUID = 1L; private static final String FORMAT_STRING = "yyyy/MM/dd HH:mm:ss"; //NON-NLS diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/TimeStampUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/TimeStampUtils.java similarity index 97% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/TimeStampUtils.java rename to Core/src/org/sleuthkit/autopsy/coreutils/TimeStampUtils.java index fe53871dd5..4b22a6010d 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/TimeStampUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/TimeStampUtils.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.coreutils; import java.text.SimpleDateFormat; import java.util.Calendar; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index 3bc76e61fd..b2204f1b2c 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -28,6 +28,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.TimeStampUtils; import org.sleuthkit.datamodel.Content; /* diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCase.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCase.java deleted file mode 100755 index ff47423030..0000000000 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCase.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015-2017 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.experimental.autoingest; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Comparator; -import java.util.Date; -import java.util.Objects; -import java.util.logging.Level; -import org.sleuthkit.autopsy.casemodule.CaseMetadata; -import org.sleuthkit.autopsy.coreutils.Logger; - -/** - * A representation of a case created by automated ingest. - */ -class AutoIngestCase implements Comparable { - - private static final Logger logger = Logger.getLogger(AutoIngestCase.class.getName()); - private final Path caseDirectoryPath; - private final String caseName; - private final Path metadataFilePath; - private final Date createDate; - private final Date lastAccessedDate; - - /** - * Constructs a representation of case created by automated ingest. - * - * @param caseDirectoryPath The case directory path. - */ - AutoIngestCase(Path caseDirectoryPath) { - this.caseDirectoryPath = caseDirectoryPath; - caseName = PathUtils.caseNameFromCaseDirectoryPath(caseDirectoryPath); - metadataFilePath = caseDirectoryPath.resolve(caseName + CaseMetadata.getFileExtension()); - BasicFileAttributes fileAttrs = null; - try { - fileAttrs = Files.readAttributes(metadataFilePath, BasicFileAttributes.class); - } catch (IOException ex) { - logger.log(Level.SEVERE, String.format("Error reading file attributes of case metadata file in %s, will use current time for case createDate/lastModfiedDate", caseDirectoryPath), ex); - } - if (null != fileAttrs) { - createDate = new Date(fileAttrs.creationTime().toMillis()); - lastAccessedDate = new Date(fileAttrs.lastAccessTime().toMillis()); - } else { - createDate = new Date(); - lastAccessedDate = new Date(); - } - } - - /** - * Gets the case directory path. - * - * @return The case directory path. - */ - Path getCaseDirectoryPath() { - return this.caseDirectoryPath; - } - - /** - * Gets the case name. - * - * @return The case name. - */ - String getCaseName() { - return this.caseName; - } - - /** - * Gets the creation date for the case, defined as the create time of the - * case metadata file. - * - * @return The case creation date. - */ - Date getCreationDate() { - return this.createDate; - } - - /** - * Gets the last accessed date for the case, defined as the last accessed - * time of the case metadata file. - * - * @return The last accessed date. - */ - Date getLastAccessedDate() { - return this.lastAccessedDate; - } - - /** - * Gets the status of this case based on the auto ingest result file in the - * case directory. - * - * @return See CaseStatus enum definition. - */ - CaseStatus getStatus() { - if (AutoIngestAlertFile.exists(caseDirectoryPath)) { - return CaseStatus.ALERT; - } else { - return CaseStatus.OK; - } - } - - /** - * Indicates whether or not some other object is "equal to" this - * AutoIngestCase object. - * - * @param other The other object. - * - * @return True or false. - */ - @Override - public boolean equals(Object other) { - if (!(other instanceof AutoIngestCase)) { - return false; - } - if (other == this) { - return true; - } - return this.caseDirectoryPath.toString().equals(((AutoIngestCase) other).caseDirectoryPath.toString()); - } - - /** - * Returns a hash code value for this AutoIngestCase object. - * - * @return The has code. - */ - @Override - public int hashCode() { - int hash = 7; - hash = 71 * hash + Objects.hashCode(this.caseDirectoryPath); - hash = 71 * hash + Objects.hashCode(this.createDate); - hash = 71 * hash + Objects.hashCode(this.caseName); - return hash; - } - - /** - * Compares this AutopIngestCase object with abnother AutoIngestCase object - * for order. - */ - @Override - public int compareTo(AutoIngestCase other) { - return -this.lastAccessedDate.compareTo(other.getLastAccessedDate()); - } - - /** - * Comparator for a descending order sort on date created. - */ - static class LastAccessedDateDescendingComparator implements Comparator { - - /** - * Compares two AutoIngestCase objects for order based on last accessed - * date (descending). - * - * @param object The first AutoIngestCase object - * @param otherObject The second AuotIngestCase object. - * - * @return A negative integer, zero, or a positive integer as the first - * argument is less than, equal to, or greater than the second. - */ - @Override - public int compare(AutoIngestCase object, AutoIngestCase otherObject) { - return -object.getLastAccessedDate().compareTo(otherObject.getLastAccessedDate()); - } - } - - enum CaseStatus { - - OK, - ALERT - } - -} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseManager.java deleted file mode 100755 index 8469ff2315..0000000000 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseManager.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2017 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.experimental.autoingest; - -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.CaseActionException; -import org.sleuthkit.autopsy.coordinationservice.CoordinationService; -import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; - -/** - * Handles locating and opening cases created by auto ingest. - */ -final class AutoIngestCaseManager { - - private static AutoIngestCaseManager instance; - - private CoordinationService coordinationService; - - /** - * Gets the auto ingest case manager. - * - * @return The auto ingest case manager singleton. - * - * @throws AutoIngestCaseManagerException - */ - synchronized static AutoIngestCaseManager getInstance() throws AutoIngestCaseManager.AutoIngestCaseManagerException { - if (null == instance) { - instance = new AutoIngestCaseManager(); - } - return instance; - } - - /** - * Constructs an object that handles locating and opening cases created by - * auto ingest. - * - * @throws AutoIngestCaseManagerException - */ - private AutoIngestCaseManager() throws AutoIngestCaseManagerException { - try { - coordinationService = CoordinationService.getInstance(); - } catch (CoordinationServiceException ex) { - throw new AutoIngestCaseManager.AutoIngestCaseManagerException("Failed to get the coordination service.", ex); - } - } - - /** - * Gets a list of the cases in the top level case folder used by auto - * ingest. - * - * @return List of cases. - * - * @throws AutoIngestCaseManagerException - */ - List getCases() throws AutoIngestCaseManagerException { - List cases = new ArrayList<>(); - List casePathList = getCasePaths(); - for (Path casePath : casePathList) { - cases.add(new AutoIngestCase(casePath)); - } - return cases; - } - - /** - * Retrieve all of the case nodes and filter for only those that represent - * case paths. - * - * @return List of case paths. - * - * @throws AutoIngestCaseManagerException - */ - private List getCasePaths() throws AutoIngestCaseManagerException { - try { - List nodeList = coordinationService.getNodeList(CoordinationService.CategoryNode.CASES); - List casePathList = new ArrayList(0); - for (String node : nodeList) { - if(node.indexOf('\\') >= 0 || node.indexOf('/') >= 0) { - /* - * This is not a case name lock (name specifies a path). - */ - String nodeUpperCase = node.toUpperCase(); - if(!nodeUpperCase.endsWith("_RESOURCES") && !nodeUpperCase.endsWith("AUTO_INGEST_LOG.TXT")) { - /* - * This is not a case resource lock, nor a case auto - * ingest log lock. Collect the path. - */ - casePathList.add(Paths.get(node)); - } - } - } - return casePathList; - - } catch (CoordinationServiceException ex) { - throw new AutoIngestCaseManager.AutoIngestCaseManagerException("Failed to get node list from coordination service.", ex); - } - } - - /** - * Opens an auto ingest case case. - * - * @param caseMetadataFilePath Path to the case metadata file. - * - * @throws CaseActionException - */ - synchronized void openCase(Path caseMetadataFilePath) throws CaseActionException { - /* - * Open the case. - */ - Case.openAsCurrentCase(caseMetadataFilePath.toString()); - } - - /** - * Exception type thrown when there is an error completing an auto ingest - * case manager operation. - */ - static final class AutoIngestCaseManagerException extends Exception { - - private static final long serialVersionUID = 1L; - - /** - * Constructs an instance of the exception type thrown when there is an - * error completing an auto ingest case manager operation. - * - * @param message The exception message. - */ - private AutoIngestCaseManagerException(String message) { - super(message); - } - - /** - * Constructs an instance of the exception type thrown when there is an - * error completing an auto ingest case manager operation. - * - * @param message The exception message. - * @param cause A Throwable cause for the error. - */ - private AutoIngestCaseManagerException(String message, Throwable cause) { - super(message, cause); - } - - } -} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseOpenAction.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseOpenAction.java deleted file mode 100755 index e86a7bcf8a..0000000000 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseOpenAction.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015 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.experimental.autoingest; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.logging.Level; -import org.openide.util.HelpCtx; -import org.openide.util.Lookup; -import org.openide.util.NbBundle; -import org.openide.util.actions.CallableSystemAction; -import org.openide.util.actions.SystemAction; -import org.sleuthkit.autopsy.casemodule.CaseCloseAction; -import org.sleuthkit.autopsy.casemodule.CaseOpenAction; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.StartupWindowProvider; -import org.sleuthkit.autopsy.core.UserPreferences; - -final class AutoIngestCaseOpenAction extends CallableSystemAction implements ActionListener { - - private static final Logger logger = Logger.getLogger(AutoIngestCaseOpenAction.class.getName()); - private static final long serialVersionUID = 1L; - - public AutoIngestCaseOpenAction() { - } - - @Override - public void actionPerformed(ActionEvent e) { - - UserPreferences.SelectedMode mode = UserPreferences.getMode(); - switch (mode) { - case REVIEW: - - if (Case.isCaseOpen()) { - /* - * In review mode, close the currently open case, if any, and - * then display the review mode cases panel. This can be - * accomplished by invoking CaseCloseAction because it calls - * StartupWindowProvider.getInstance().open() after it closes - * the current case. - */ - SystemAction.get(CaseCloseAction.class).actionPerformed(e); - } else { - // no case is open, so show the startup window - StartupWindowProvider.getInstance().open(); - } - break; - - case AUTOINGEST: - /* - * New case action is disabled in auto ingest mode. - */ - break; - - case STANDALONE: - /** - * In standalone mode, invoke default Autopsy version of CaseOpenAction. - */ - Lookup.getDefault().lookup(CaseOpenAction.class).actionPerformed(e); - break; - - - default: - logger.log(Level.SEVERE, "Attempting to open case in unsupported mode {0}", mode.toString()); - } - } - - @Override - public void performAction() { - } - - @Override - public String getName() { - return NbBundle.getMessage(AutoIngestCaseOpenAction.class, "CTL_OpenAction"); - } - - @Override - public HelpCtx getHelpCtx() { - return HelpCtx.DEFAULT_HELP; - } - -} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java index 891975223a..de737978cb 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java @@ -57,6 +57,8 @@ import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.core.ServicesMonitor; +import org.sleuthkit.autopsy.coreutils.CaseStatusIconCellRenderer; +import org.sleuthkit.autopsy.coreutils.LongDateCellRenderer; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.NetworkUtils; import org.sleuthkit.autopsy.coreutils.PlatformUtil; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java index 2d10dff258..5537d07236 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java @@ -41,7 +41,9 @@ import javax.swing.table.TableColumn; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.core.ServicesMonitor; +import org.sleuthkit.autopsy.coreutils.CaseStatusIconCellRenderer; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.LongDateCellRenderer; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestMonitor.JobsSnapshot; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java index 7e1b1907af..45563a4f4b 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java @@ -25,7 +25,6 @@ import org.openide.util.HelpCtx; import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; import org.sleuthkit.autopsy.core.UserPreferences; -import static org.sleuthkit.autopsy.core.UserPreferences.SelectedMode.REVIEW; import org.sleuthkit.autopsy.coreutils.Logger; @ActionID(category = "Tools", id = "org.sleuthkit.autopsy.experimental.autoingest.AutoIngestDashboardOpenAction") @@ -39,8 +38,7 @@ public final class AutoIngestDashboardOpenAction extends CallableSystemAction { @Override public boolean isEnabled() { - UserPreferences.SelectedMode mode = UserPreferences.getMode(); - return (mode == REVIEW); + return (UserPreferences.getIsMultiUserModeEnabled()); } @Override diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index 2f2f22fb0d..0c6c39e0b1 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -62,6 +62,7 @@ import org.openide.util.Lookup; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.casemodule.CaseActionException; +import org.sleuthkit.autopsy.casemodule.CaseDetails; import org.sleuthkit.autopsy.casemodule.CaseMetadata; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; @@ -2115,7 +2116,8 @@ public final class AutoIngestManager extends Observable implements PropertyChang Case.openAsCurrentCase(metadataFilePath.toString()); } else { caseDirectoryPath = PathUtils.createCaseFolderPath(rootOutputDirectory, caseName); - Case.createAsCurrentCase(caseDirectoryPath.toString(), caseName, "", "", CaseType.MULTI_USER_CASE); + CaseDetails caseDetails = new CaseDetails(caseName, "", "", "", "", ""); + Case.createAsCurrentCase(CaseType.MULTI_USER_CASE, caseDirectoryPath.toString(), caseDetails); /* * Sleep a bit before releasing the lock to ensure * that the new case folder is visible on the diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties index edac418672..7b6a28a9f3 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties @@ -1,4 +1,4 @@ -CTL_OpenAction=Open Case... +CTL_OpenAction=Open Case AutoIngestDashboard.lbCompleted.text=Completed Jobs AutoIngestDashboard.lbRunning.text=Running Jobs AutoIngestDashboard.lbPending.text=Pending Jobs @@ -231,15 +231,6 @@ FileExporterSettingsPanel.BrowseReportTooltip_1=Browse for the Reports Folder FileExporterSettingsPanel.NewRuleTooltip_1=Clear the rule editor to begin a new rule FileExporterSettingsPanel.DeleteTooltip_1=Delete the selected rule FileExporterSettingsPanel.SaveTooltip_1=Save the current rule -AutoIngestCasePanel.rbDays.text=Days -AutoIngestCasePanel.rbWeeks.text=Weeks -AutoIngestCasePanel.rbMonths.text=Months -AutoIngestCasePanel.rbAllCases.text=Everything -AutoIngestCasePanel.bnRefresh.text=&Refresh -AutoIngestCasePanel.bnOpen.text=&Open -AutoIngestCasePanel.bnShowLog.toolTipText=Display case log file for selected case -AutoIngestCasePanel.bnShowLog.text=&Show Log -AutoIngestCasePanel.rbGroupLabel.text=Show cases accessed in the last 10: AutoIngestDashboard.refreshButton.toolTipText=Refresh displayed tables AutoIngestDashboard.refreshButton.text=&Refresh AutoIngestDashboard.jButton1.text=jButton1 diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseImportPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseImportPanel.java index a7cd13af72..2e4866b010 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseImportPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseImportPanel.java @@ -672,7 +672,6 @@ public class CaseImportPanel extends javax.swing.JPanel implements ImportDoneCal */ private void enableStartButton() { if (UserPreferences.getIsMultiUserModeEnabled() - && AutoIngestUserPreferences.getJoinAutoModeCluster() && (! RuntimeProperties.runningWithGUI()) && !tbCaseSource.getText().isEmpty() && !tbCaseDestination.getText().isEmpty() diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CenteredGrayableCellRenderer.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CenteredGrayableCellRenderer.java index b9040b674b..04422cd63a 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CenteredGrayableCellRenderer.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CenteredGrayableCellRenderer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.experimental.autoingest; import static javax.swing.SwingConstants.CENTER; +import org.sleuthkit.autopsy.coreutils.GrayableCellRenderer; /** * A JTable cell renderer that center-aligns cell content and grays out the cell diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DurationCellRenderer.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DurationCellRenderer.java index 6bac0a996b..c61e363222 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DurationCellRenderer.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DurationCellRenderer.java @@ -18,10 +18,12 @@ */ package org.sleuthkit.autopsy.experimental.autoingest; +import java.awt.Color; import java.awt.Component; import java.time.Duration; import javax.swing.JTable; import static javax.swing.SwingConstants.CENTER; +import org.sleuthkit.autopsy.coreutils.GrayableCellRenderer; /** * A JTable cell renderer that renders a duration represented as a long as a @@ -71,4 +73,26 @@ class DurationCellRenderer extends GrayableCellRenderer { grayCellIfTableNotEnabled(table, isSelected); return this; } + + void grayCellIfTableNotEnabled(JTable table, boolean isSelected) { + if (table.isEnabled()) { + /* + * The table is enabled, make the foreground and background the + * normal selected or unselected color. + */ + if (isSelected) { + setBackground(table.getSelectionBackground()); + setForeground(table.getSelectionForeground()); + } else { + setBackground(table.getBackground()); + setForeground(table.getForeground()); + } + } else { + /* + * The table is disabled, make the foreground and background gray. + */ + setBackground(Color.lightGray); + setForeground(Color.darkGray); + } + } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java index 18ce9709d5..a7d5675883 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.sleuthkit.autopsy.casemodule.CaseMetadata; +import org.sleuthkit.autopsy.coreutils.TimeStampUtils; final class PathUtils { diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ShortDateCellRenderer.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ShortDateCellRenderer.java index 713d177c0a..f2670fa1b7 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ShortDateCellRenderer.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ShortDateCellRenderer.java @@ -18,10 +18,12 @@ */ package org.sleuthkit.autopsy.experimental.autoingest; +import java.awt.Color; import java.awt.Component; import java.text.SimpleDateFormat; import javax.swing.JTable; import static javax.swing.SwingConstants.CENTER; +import org.sleuthkit.autopsy.coreutils.GrayableCellRenderer; /** * A JTable cell renderer that renders a date represented as a long as a @@ -46,4 +48,26 @@ class ShortDateCellRenderer extends GrayableCellRenderer { grayCellIfTableNotEnabled(table, isSelected); return this; } + + void grayCellIfTableNotEnabled(JTable table, boolean isSelected) { + if (table.isEnabled()) { + /* + * The table is enabled, make the foreground and background the + * normal selected or unselected color. + */ + if (isSelected) { + setBackground(table.getSelectionBackground()); + setForeground(table.getSelectionForeground()); + } else { + setBackground(table.getBackground()); + setForeground(table.getForeground()); + } + } else { + /* + * The table is disabled, make the foreground and background gray. + */ + setBackground(Color.lightGray); + setForeground(Color.darkGray); + } + } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/SingleUserCaseImporter.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/SingleUserCaseImporter.java index e04399d321..3a5c45632f 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/SingleUserCaseImporter.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/SingleUserCaseImporter.java @@ -47,6 +47,7 @@ import org.sleuthkit.autopsy.casemodule.SingleUserCaseConverter; import org.sleuthkit.autopsy.casemodule.SingleUserCaseConverter.ImportCaseData; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.NetworkUtils; +import org.sleuthkit.autopsy.coreutils.TimeStampUtils; public class SingleUserCaseImporter implements Runnable { diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.form b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.form index 20c8c7a981..9965d1ad8f 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.form @@ -56,18 +56,71 @@ - - - - + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -79,542 +132,65 @@ - - + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -649,6 +225,238 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java index 4877ce9d60..892a27aab6 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java @@ -56,7 +56,7 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { enum OptionsUiMode { - STANDALONE, AIM, REVIEW, DOWNLOADING_CONFIGURATION + STANDALONE, AIM, DOWNLOADING_CONFIGURATION }; /** @@ -127,21 +127,10 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { if (inStartup) { UserPreferences.SelectedMode storedMode = UserPreferences.getMode(); inputPathTextField.requestFocusInWindow(); - if (null != storedMode) { - switch (storedMode) { - case REVIEW: - jRadioButtonReview.setSelected(true); - enableOptionsBasedOnMode(OptionsUiMode.REVIEW); - break; - case AUTOINGEST: - jRadioButtonAutomated.setSelected(true); - enableOptionsBasedOnMode(OptionsUiMode.AIM); - break; - default: - cbJoinAutoIngestCluster.setSelected(false); - enableOptionsBasedOnMode(OptionsUiMode.STANDALONE); - break; - } + if (storedMode == UserPreferences.SelectedMode.AUTOINGEST) { + enableOptionsBasedOnMode(OptionsUiMode.AIM); + } else if (storedMode != null) { + enableOptionsBasedOnMode(OptionsUiMode.STANDALONE); } } @@ -207,22 +196,12 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { * Save mode to persistent storage. */ void store() { - boolean needsRestart = false; - UserPreferences.SelectedMode storedMode = UserPreferences.getMode(); - + boolean needsRestart = (cbJoinAutoIngestCluster.isSelected() != AutoIngestUserPreferences.getJoinAutoModeCluster()); + AutoIngestUserPreferences.setJoinAutoModeCluster(cbJoinAutoIngestCluster.isSelected()); if (!cbJoinAutoIngestCluster.isSelected()) { - if(storedMode == UserPreferences.SelectedMode.AUTOINGEST) { - needsRestart = true; - } - UserPreferences.setMode(UserPreferences.SelectedMode.STANDALONE); - } - else if (jRadioButtonAutomated.isSelected()) { - if (storedMode == UserPreferences.SelectedMode.REVIEW) { - needsRestart = true; - } - + } else { UserPreferences.setMode(UserPreferences.SelectedMode.AUTOINGEST); String imageFolderPath = getNormalizedFolderPath(inputPathTextField.getText().trim()); AutoIngestUserPreferences.setAutoModeImageFolder(imageFolderPath); @@ -234,15 +213,8 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { AutoIngestUserPreferences.setSharedConfigFolder(globalSettingsPath); AutoIngestUserPreferences.setSharedConfigMaster(masterNodeCheckBox.isSelected()); } - } else if (jRadioButtonReview.isSelected()) { - if (storedMode == UserPreferences.SelectedMode.AUTOINGEST) { - needsRestart = true; - } - - UserPreferences.setMode(UserPreferences.SelectedMode.REVIEW); - String resultsFolderPath = getNormalizedFolderPath(outputPathTextField.getText().trim()); - AutoIngestUserPreferences.setAutoModeResultsFolder(resultsFolderPath); } + if (needsRestart) { SwingUtilities.invokeLater(() -> { JOptionPane.showMessageDialog(null, @@ -306,23 +278,14 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { configButtonErrorTextField.setText("Shared configuration folder is invalid"); } break; - case REVIEW: - jLabelInvalidImageFolder.setVisible(false); - if (!validateResultsPath()) { - isValidNodePanel = false; - } - break; - case STANDALONE: break; default: break; } - if (jRadioButtonAutomated.isSelected()) { - if (sharedConfigCheckbox.isEnabled() && sharedConfigCheckbox.isSelected() && !validSharedConfigSettings()) { - isValidNodePanel = false; - } + if (sharedConfigCheckbox.isEnabled() && sharedConfigCheckbox.isSelected() && !validSharedConfigSettings()) { + isValidNodePanel = false; } return isValidNodePanel; } @@ -579,24 +542,17 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { private void enableOptionsBasedOnMode(OptionsUiMode mode) { if (mode != OptionsUiMode.DOWNLOADING_CONFIGURATION) { boolean nonMasterSharedConfig = !masterNodeCheckBox.isSelected() && sharedConfigCheckbox.isSelected(); - jRadioButtonAutomated.setEnabled(cbJoinAutoIngestCluster.isSelected()); - jRadioButtonReview.setEnabled(cbJoinAutoIngestCluster.isSelected()); - jLabelSelectInputFolder.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); inputPathTextField.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); browseInputFolderButton.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); - jLabelSelectOutputFolder.setEnabled((mode == OptionsUiMode.AIM && !nonMasterSharedConfig) || mode == OptionsUiMode.REVIEW); - outputPathTextField.setEnabled((mode == OptionsUiMode.AIM && !nonMasterSharedConfig) || mode == OptionsUiMode.REVIEW); - browseOutputFolderButton.setEnabled((mode == OptionsUiMode.AIM && !nonMasterSharedConfig) || mode == OptionsUiMode.REVIEW); + jLabelSelectOutputFolder.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); + outputPathTextField.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); + browseOutputFolderButton.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); - jPanelSharedConfig.setEnabled(mode == OptionsUiMode.AIM); - - jPanelIngestSettings.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); bnEditIngestSettings.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); bnAdvancedSettings.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); bnLogging.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); - jPanelSharedConfig.setEnabled(mode == OptionsUiMode.AIM); sharedConfigCheckbox.setEnabled(mode == OptionsUiMode.AIM); masterNodeCheckBox.setEnabled(mode == OptionsUiMode.AIM && sharedConfigCheckbox.isSelected()); bnFileExport.setEnabled(mode == OptionsUiMode.AIM); @@ -613,14 +569,8 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { private OptionsUiMode getModeFromRadioButtons() { if (!cbJoinAutoIngestCluster.isSelected()) { return OptionsUiMode.STANDALONE; - } - - if (jRadioButtonAutomated.isSelected()) { - return OptionsUiMode.AIM; - } else if (jRadioButtonReview.isSelected()) { - return OptionsUiMode.REVIEW; } else { - return OptionsUiMode.STANDALONE; + return OptionsUiMode.AIM; } } @@ -636,289 +586,49 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { modeRadioButtons = new javax.swing.ButtonGroup(); nodeScrollPane = new javax.swing.JScrollPane(); nodePanel = new javax.swing.JPanel(); - jPanelNodeType = new javax.swing.JPanel(); - jLabelSelectMode = new javax.swing.JLabel(); - jRadioButtonAutomated = new javax.swing.JRadioButton(); - jRadioButtonReview = new javax.swing.JRadioButton(); - jLabelSelectInputFolder = new javax.swing.JLabel(); - inputPathTextField = new javax.swing.JTextField(); - browseInputFolderButton = new javax.swing.JButton(); - jLabelSelectOutputFolder = new javax.swing.JLabel(); - outputPathTextField = new javax.swing.JTextField(); - browseOutputFolderButton = new javax.swing.JButton(); - jLabelInvalidImageFolder = new javax.swing.JLabel(); - jLabelInvalidResultsFolder = new javax.swing.JLabel(); - jLabel1 = new javax.swing.JLabel(); - jPanelSharedConfig = new javax.swing.JPanel(); - sharedConfigCheckbox = new javax.swing.JCheckBox(); - sharedSettingsTextField = new javax.swing.JTextField(); - browseSharedSettingsButton = new javax.swing.JButton(); - sharedSettingsErrorTextField = new javax.swing.JTextField(); - masterNodeCheckBox = new javax.swing.JCheckBox(); - uploadButton = new javax.swing.JButton(); - downloadButton = new javax.swing.JButton(); - jLabelCurrentTask = new javax.swing.JLabel(); - pbTaskInProgress = new javax.swing.JProgressBar(); - jLabelTaskDescription = new javax.swing.JLabel(); - configButtonErrorTextField = new javax.swing.JTextField(); - jSeparator1 = new javax.swing.JSeparator(); - jPanelIngestSettings = new javax.swing.JPanel(); + cbJoinAutoIngestCluster = new javax.swing.JCheckBox(); + tbOops = new javax.swing.JTextField(); bnEditIngestSettings = new javax.swing.JButton(); bnAdvancedSettings = new javax.swing.JButton(); bnFileExport = new javax.swing.JButton(); bnLogging = new javax.swing.JButton(); - cbJoinAutoIngestCluster = new javax.swing.JCheckBox(); - tbOops = new javax.swing.JTextField(); + browseOutputFolderButton = new javax.swing.JButton(); + browseInputFolderButton = new javax.swing.JButton(); + inputPathTextField = new javax.swing.JTextField(); + outputPathTextField = new javax.swing.JTextField(); + jLabelInvalidResultsFolder = new javax.swing.JLabel(); + jLabelInvalidImageFolder = new javax.swing.JLabel(); + jLabelSelectInputFolder = new javax.swing.JLabel(); + jLabelSelectOutputFolder = new javax.swing.JLabel(); + sharedConfigCheckbox = new javax.swing.JCheckBox(); + sharedSettingsErrorTextField = new javax.swing.JTextField(); + sharedSettingsTextField = new javax.swing.JTextField(); + browseSharedSettingsButton = new javax.swing.JButton(); + downloadButton = new javax.swing.JButton(); + configButtonErrorTextField = new javax.swing.JTextField(); + pbTaskInProgress = new javax.swing.JProgressBar(); + jLabelTaskDescription = new javax.swing.JLabel(); + jLabelCurrentTask = new javax.swing.JLabel(); + uploadButton = new javax.swing.JButton(); + masterNodeCheckBox = new javax.swing.JCheckBox(); nodeScrollPane.setMinimumSize(new java.awt.Dimension(0, 0)); nodePanel.setMinimumSize(new java.awt.Dimension(100, 100)); - jPanelNodeType.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jPanelNodeType.border.title"))); // NOI18N - jPanelNodeType.setMinimumSize(new java.awt.Dimension(50, 50)); - - org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectMode, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelSelectMode.text")); // NOI18N - - modeRadioButtons.add(jRadioButtonAutomated); - jRadioButtonAutomated.setSelected(true); - org.openide.awt.Mnemonics.setLocalizedText(jRadioButtonAutomated, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jRadioButtonAutomated.text")); // NOI18N - jRadioButtonAutomated.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jRadioButtonAutomated.toolTipText")); // NOI18N - jRadioButtonAutomated.addActionListener(new java.awt.event.ActionListener() { + cbJoinAutoIngestCluster.setFont(cbJoinAutoIngestCluster.getFont().deriveFont(cbJoinAutoIngestCluster.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + org.openide.awt.Mnemonics.setLocalizedText(cbJoinAutoIngestCluster, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.cbJoinAutoIngestCluster.text")); // NOI18N + cbJoinAutoIngestCluster.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - jRadioButtonAutomatedActionPerformed(evt); + cbJoinAutoIngestClusterActionPerformed(evt); } }); - modeRadioButtons.add(jRadioButtonReview); - org.openide.awt.Mnemonics.setLocalizedText(jRadioButtonReview, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jRadioButtonReview.text")); // NOI18N - jRadioButtonReview.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jRadioButtonReview.toolTipText")); // NOI18N - jRadioButtonReview.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - jRadioButtonReviewActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectInputFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelSelectInputFolder.text")); // NOI18N - jLabelSelectInputFolder.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM); - - inputPathTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.inputPathTextField.text")); // NOI18N - inputPathTextField.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.inputPathTextField.toolTipText")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(browseInputFolderButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseInputFolderButton.text")); // NOI18N - browseInputFolderButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - browseInputFolderButtonActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectOutputFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelSelectOutputFolder.text")); // NOI18N - jLabelSelectOutputFolder.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM); - - outputPathTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.outputPathTextField.text")); // NOI18N - outputPathTextField.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.outputPathTextField.toolTipText")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(browseOutputFolderButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseOutputFolderButton.text")); // NOI18N - browseOutputFolderButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - browseOutputFolderButtonActionPerformed(evt); - } - }); - - jLabelInvalidImageFolder.setForeground(new java.awt.Color(255, 0, 0)); - org.openide.awt.Mnemonics.setLocalizedText(jLabelInvalidImageFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelInvalidImageFolder.text")); // NOI18N - - jLabelInvalidResultsFolder.setForeground(new java.awt.Color(255, 0, 0)); - org.openide.awt.Mnemonics.setLocalizedText(jLabelInvalidResultsFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelInvalidResultsFolder.text")); // NOI18N - - jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/experimental/images/AIM.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabel1.text")); // NOI18N - - javax.swing.GroupLayout jPanelNodeTypeLayout = new javax.swing.GroupLayout(jPanelNodeType); - jPanelNodeType.setLayout(jPanelNodeTypeLayout); - jPanelNodeTypeLayout.setHorizontalGroup( - jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(outputPathTextField, javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(inputPathTextField, javax.swing.GroupLayout.Alignment.LEADING)) - .addGap(10, 10, 10) - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(browseInputFolderButton, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(browseOutputFolderButton, javax.swing.GroupLayout.Alignment.TRAILING))) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabelSelectMode) - .addComponent(jRadioButtonReview) - .addComponent(jRadioButtonAutomated)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jLabel1)) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addComponent(jLabelSelectInputFolder) - .addGap(18, 18, 18) - .addComponent(jLabelInvalidImageFolder, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addComponent(jLabelSelectOutputFolder) - .addGap(18, 18, 18) - .addComponent(jLabelInvalidResultsFolder, javax.swing.GroupLayout.PREFERRED_SIZE, 544, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE))) - .addContainerGap()) - ); - jPanelNodeTypeLayout.setVerticalGroup( - jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addContainerGap() - .addComponent(jLabelSelectMode) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jRadioButtonAutomated) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jRadioButtonReview)) - .addComponent(jLabel1)) - .addGap(1, 1, 1) - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabelSelectInputFolder) - .addComponent(jLabelInvalidImageFolder)) - .addGap(1, 1, 1) - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(inputPathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(browseInputFolderButton)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabelSelectOutputFolder, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jLabelInvalidResultsFolder)) - .addGap(1, 1, 1) - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(browseOutputFolderButton) - .addComponent(outputPathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(0, 0, Short.MAX_VALUE)) - ); - - jPanelSharedConfig.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jPanelSharedConfig.border.title"))); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(sharedConfigCheckbox, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedConfigCheckbox.text")); // NOI18N - sharedConfigCheckbox.setMaximumSize(new java.awt.Dimension(191, 14)); - sharedConfigCheckbox.setMinimumSize(new java.awt.Dimension(191, 14)); - sharedConfigCheckbox.setPreferredSize(new java.awt.Dimension(191, 14)); - sharedConfigCheckbox.addItemListener(new java.awt.event.ItemListener() { - public void itemStateChanged(java.awt.event.ItemEvent evt) { - sharedConfigCheckboxItemStateChanged(evt); - } - }); - - sharedSettingsTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedSettingsTextField.text")); // NOI18N - sharedSettingsTextField.setEnabled(false); - - org.openide.awt.Mnemonics.setLocalizedText(browseSharedSettingsButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseSharedSettingsButton.text")); // NOI18N - browseSharedSettingsButton.setEnabled(false); - browseSharedSettingsButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - browseSharedSettingsButtonActionPerformed(evt); - } - }); - - sharedSettingsErrorTextField.setEditable(false); - sharedSettingsErrorTextField.setForeground(new java.awt.Color(255, 0, 0)); - sharedSettingsErrorTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedSettingsErrorTextField.text")); // NOI18N - sharedSettingsErrorTextField.setBorder(null); - - org.openide.awt.Mnemonics.setLocalizedText(masterNodeCheckBox, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.masterNodeCheckBox.text")); // NOI18N - masterNodeCheckBox.setEnabled(false); - masterNodeCheckBox.addItemListener(new java.awt.event.ItemListener() { - public void itemStateChanged(java.awt.event.ItemEvent evt) { - masterNodeCheckBoxItemStateChanged(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(uploadButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.uploadButton.text")); // NOI18N - uploadButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - uploadButtonActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(downloadButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.downloadButton.text")); // NOI18N - downloadButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - downloadButtonActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(jLabelCurrentTask, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelCurrentTask.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(jLabelTaskDescription, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelTaskDescription.text")); // NOI18N - - configButtonErrorTextField.setEditable(false); - configButtonErrorTextField.setForeground(new java.awt.Color(255, 0, 0)); - configButtonErrorTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.configButtonErrorTextField.text")); // NOI18N - configButtonErrorTextField.setBorder(null); - - javax.swing.GroupLayout jPanelSharedConfigLayout = new javax.swing.GroupLayout(jPanelSharedConfig); - jPanelSharedConfig.setLayout(jPanelSharedConfigLayout); - jPanelSharedConfigLayout.setHorizontalGroup( - jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelSharedConfigLayout.createSequentialGroup() - .addGap(10, 10, 10) - .addComponent(jLabelCurrentTask) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jLabelTaskDescription, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addContainerGap()) - .addGroup(jPanelSharedConfigLayout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelSharedConfigLayout.createSequentialGroup() - .addComponent(sharedSettingsTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 400, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(browseSharedSettingsButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(uploadButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanelSharedConfigLayout.createSequentialGroup() - .addComponent(downloadButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(configButtonErrorTextField)) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanelSharedConfigLayout.createSequentialGroup() - .addComponent(sharedConfigCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(sharedSettingsErrorTextField)) - .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 692, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(pbTaskInProgress, javax.swing.GroupLayout.PREFERRED_SIZE, 695, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(masterNodeCheckBox)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - jPanelSharedConfigLayout.setVerticalGroup( - jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelSharedConfigLayout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(sharedConfigCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(sharedSettingsErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(sharedSettingsTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(browseSharedSettingsButton)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(downloadButton) - .addComponent(configButtonErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(1, 1, 1) - .addComponent(masterNodeCheckBox, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(uploadButton) - .addGap(8, 8, 8) - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabelCurrentTask) - .addComponent(jLabelTaskDescription)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(pbTaskInProgress, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - - jPanelIngestSettings.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jPanelIngestSettings.border.title"))); // NOI18N + tbOops.setEditable(false); + tbOops.setFont(tbOops.getFont().deriveFont(tbOops.getFont().getStyle() | java.awt.Font.BOLD, 12)); + tbOops.setForeground(new java.awt.Color(255, 0, 0)); + tbOops.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.tbOops.text")); // NOI18N + tbOops.setBorder(null); org.openide.awt.Mnemonics.setLocalizedText(bnEditIngestSettings, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.bnEditIngestSettings.text")); // NOI18N bnEditIngestSettings.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.bnEditIngestSettings.toolTipText")); // NOI18N @@ -949,46 +659,94 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } }); - javax.swing.GroupLayout jPanelIngestSettingsLayout = new javax.swing.GroupLayout(jPanelIngestSettings); - jPanelIngestSettings.setLayout(jPanelIngestSettingsLayout); - jPanelIngestSettingsLayout.setHorizontalGroup( - jPanelIngestSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelIngestSettingsLayout.createSequentialGroup() - .addContainerGap() - .addComponent(bnEditIngestSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnAdvancedSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnFileExport, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnLogging, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - jPanelIngestSettingsLayout.setVerticalGroup( - jPanelIngestSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelIngestSettingsLayout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanelIngestSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(bnEditIngestSettings) - .addComponent(bnFileExport) - .addComponent(bnAdvancedSettings) - .addComponent(bnLogging)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - - cbJoinAutoIngestCluster.setFont(cbJoinAutoIngestCluster.getFont().deriveFont(cbJoinAutoIngestCluster.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - org.openide.awt.Mnemonics.setLocalizedText(cbJoinAutoIngestCluster, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.cbJoinAutoIngestCluster.text")); // NOI18N - cbJoinAutoIngestCluster.addActionListener(new java.awt.event.ActionListener() { + org.openide.awt.Mnemonics.setLocalizedText(browseOutputFolderButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseOutputFolderButton.text")); // NOI18N + browseOutputFolderButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - cbJoinAutoIngestClusterActionPerformed(evt); + browseOutputFolderButtonActionPerformed(evt); } }); - tbOops.setEditable(false); - tbOops.setFont(tbOops.getFont().deriveFont(tbOops.getFont().getStyle() | java.awt.Font.BOLD, 12)); - tbOops.setForeground(new java.awt.Color(255, 0, 0)); - tbOops.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.tbOops.text")); // NOI18N - tbOops.setBorder(null); + org.openide.awt.Mnemonics.setLocalizedText(browseInputFolderButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseInputFolderButton.text")); // NOI18N + browseInputFolderButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + browseInputFolderButtonActionPerformed(evt); + } + }); + + inputPathTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.inputPathTextField.text")); // NOI18N + inputPathTextField.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.inputPathTextField.toolTipText")); // NOI18N + + outputPathTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.outputPathTextField.text")); // NOI18N + outputPathTextField.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.outputPathTextField.toolTipText")); // NOI18N + + jLabelInvalidResultsFolder.setForeground(new java.awt.Color(255, 0, 0)); + org.openide.awt.Mnemonics.setLocalizedText(jLabelInvalidResultsFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelInvalidResultsFolder.text")); // NOI18N + + jLabelInvalidImageFolder.setForeground(new java.awt.Color(255, 0, 0)); + org.openide.awt.Mnemonics.setLocalizedText(jLabelInvalidImageFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelInvalidImageFolder.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectInputFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelSelectInputFolder.text")); // NOI18N + jLabelSelectInputFolder.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM); + + org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectOutputFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelSelectOutputFolder.text")); // NOI18N + jLabelSelectOutputFolder.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM); + + org.openide.awt.Mnemonics.setLocalizedText(sharedConfigCheckbox, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedConfigCheckbox.text")); // NOI18N + sharedConfigCheckbox.setMaximumSize(new java.awt.Dimension(191, 14)); + sharedConfigCheckbox.setMinimumSize(new java.awt.Dimension(191, 14)); + sharedConfigCheckbox.setPreferredSize(new java.awt.Dimension(191, 14)); + sharedConfigCheckbox.addItemListener(new java.awt.event.ItemListener() { + public void itemStateChanged(java.awt.event.ItemEvent evt) { + sharedConfigCheckboxItemStateChanged(evt); + } + }); + + sharedSettingsErrorTextField.setEditable(false); + sharedSettingsErrorTextField.setForeground(new java.awt.Color(255, 0, 0)); + sharedSettingsErrorTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedSettingsErrorTextField.text")); // NOI18N + sharedSettingsErrorTextField.setBorder(null); + + sharedSettingsTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedSettingsTextField.text")); // NOI18N + sharedSettingsTextField.setEnabled(false); + + org.openide.awt.Mnemonics.setLocalizedText(browseSharedSettingsButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseSharedSettingsButton.text")); // NOI18N + browseSharedSettingsButton.setEnabled(false); + browseSharedSettingsButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + browseSharedSettingsButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(downloadButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.downloadButton.text")); // NOI18N + downloadButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + downloadButtonActionPerformed(evt); + } + }); + + configButtonErrorTextField.setEditable(false); + configButtonErrorTextField.setForeground(new java.awt.Color(255, 0, 0)); + configButtonErrorTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.configButtonErrorTextField.text")); // NOI18N + configButtonErrorTextField.setBorder(null); + + org.openide.awt.Mnemonics.setLocalizedText(jLabelTaskDescription, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelTaskDescription.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jLabelCurrentTask, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelCurrentTask.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(uploadButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.uploadButton.text")); // NOI18N + uploadButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + uploadButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(masterNodeCheckBox, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.masterNodeCheckBox.text")); // NOI18N + masterNodeCheckBox.setEnabled(false); + masterNodeCheckBox.addItemListener(new java.awt.event.ItemListener() { + public void itemStateChanged(java.awt.event.ItemEvent evt) { + masterNodeCheckBoxItemStateChanged(evt); + } + }); javax.swing.GroupLayout nodePanelLayout = new javax.swing.GroupLayout(nodePanel); nodePanel.setLayout(nodePanelLayout); @@ -998,14 +756,56 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { .addContainerGap() .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(nodePanelLayout.createSequentialGroup() - .addComponent(cbJoinAutoIngestCluster, javax.swing.GroupLayout.PREFERRED_SIZE, 171, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabelCurrentTask) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jLabelTaskDescription, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(outputPathTextField, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(inputPathTextField, javax.swing.GroupLayout.Alignment.LEADING)) + .addGap(10, 10, 10) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(browseInputFolderButton, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(browseOutputFolderButton, javax.swing.GroupLayout.Alignment.TRAILING))) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(jLabelSelectInputFolder) .addGap(18, 18, 18) - .addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, 465, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(jPanelNodeType, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jPanelSharedConfig, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jPanelIngestSettings, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(jLabelInvalidImageFolder, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(uploadButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(pbTaskInProgress, javax.swing.GroupLayout.PREFERRED_SIZE, 695, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(masterNodeCheckBox) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(cbJoinAutoIngestCluster, javax.swing.GroupLayout.PREFERRED_SIZE, 171, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, 465, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(bnEditIngestSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bnAdvancedSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bnFileExport, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bnLogging, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(jLabelSelectOutputFolder) + .addGap(18, 18, 18) + .addComponent(jLabelInvalidResultsFolder, javax.swing.GroupLayout.PREFERRED_SIZE, 544, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(sharedConfigCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(sharedSettingsErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(sharedSettingsTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 400, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(browseSharedSettingsButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(downloadButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(configButtonErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 396, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGap(0, 32, Short.MAX_VALUE))) + .addContainerGap()) ); nodePanelLayout.setVerticalGroup( nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -1014,12 +814,51 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(cbJoinAutoIngestCluster) .addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(3, 3, 3) - .addComponent(jPanelNodeType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabelSelectInputFolder) + .addComponent(jLabelInvalidImageFolder)) + .addGap(1, 1, 1) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(inputPathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(browseInputFolderButton)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jPanelIngestSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 62, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabelSelectOutputFolder, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabelInvalidResultsFolder)) + .addGap(1, 1, 1) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(browseOutputFolderButton) + .addComponent(outputPathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(25, 25, 25) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(bnEditIngestSettings) + .addComponent(bnFileExport) + .addComponent(bnAdvancedSettings) + .addComponent(bnLogging)) + .addGap(18, 18, 18) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(sharedConfigCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(sharedSettingsErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jPanelSharedConfig, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(sharedSettingsTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(browseSharedSettingsButton)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(downloadButton) + .addComponent(configButtonErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(18, 18, 18) + .addComponent(masterNodeCheckBox, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(uploadButton) + .addGap(8, 8, 8) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabelCurrentTask) + .addComponent(jLabelTaskDescription)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(pbTaskInProgress, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(161, Short.MAX_VALUE)) ); nodeScrollPane.setViewportView(nodePanel); @@ -1039,31 +878,35 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { ); }// //GEN-END:initComponents - private void browseSharedSettingsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseSharedSettingsButtonActionPerformed - - String oldText = sharedSettingsTextField.getText().trim(); - // set the current directory of the FileChooser if the oldText is valid - File currentDir = new File(oldText); - if (currentDir.exists()) { - fc.setCurrentDirectory(currentDir); - } - - fc.setDialogTitle("Select shared configuration folder:"); - fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - - int retval = fc.showOpenDialog(this); - if (retval == JFileChooser.APPROVE_OPTION) { - String path = fc.getSelectedFile().getPath(); - sharedSettingsTextField.setText(path); - validateSettings(); - controller.changed(); - } - }//GEN-LAST:event_browseSharedSettingsButtonActionPerformed - boolean permissionsAppropriate(String path) { return FileUtil.hasReadWriteAccess(Paths.get(path)); } + private void setSharedConfigEnable() { + setEnabledStateForSharedConfiguration(); + if (sharedConfigCheckbox.isEnabled() && sharedConfigCheckbox.isSelected()) { + sharedSettingsTextField.setEnabled(true); + browseSharedSettingsButton.setEnabled(true); + masterNodeCheckBox.setEnabled(true); + downloadButton.setEnabled(true); + validateSettings(); + controller.changed(); + } else { + sharedSettingsTextField.setEnabled(false); + browseSharedSettingsButton.setEnabled(false); + masterNodeCheckBox.setEnabled(false); + downloadButton.setEnabled(false); + sharedSettingsErrorTextField.setText(""); + validateSettings(); + controller.changed(); + } + } + + private void cbJoinAutoIngestClusterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbJoinAutoIngestClusterActionPerformed + enableOptionsBasedOnMode(getModeFromRadioButtons()); + controller.changed(); + }//GEN-LAST:event_cbJoinAutoIngestClusterActionPerformed + private void downloadButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_downloadButtonActionPerformed // First save the shared config folder and solr settings to the properties String globalSettingsPath = getNormalizedFolderPath(sharedSettingsTextField.getText().trim()); @@ -1100,31 +943,6 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } }//GEN-LAST:event_uploadButtonActionPerformed - private void sharedConfigCheckboxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_sharedConfigCheckboxItemStateChanged - // Enable the global settings text box and browse button iff the checkbox is checked and enabled - setSharedConfigEnable(); - }//GEN-LAST:event_sharedConfigCheckboxItemStateChanged - - private void setSharedConfigEnable() { - setEnabledStateForSharedConfiguration(); - if (sharedConfigCheckbox.isEnabled() && sharedConfigCheckbox.isSelected() && jRadioButtonAutomated.isSelected()) { - sharedSettingsTextField.setEnabled(true); - browseSharedSettingsButton.setEnabled(true); - masterNodeCheckBox.setEnabled(true); - downloadButton.setEnabled(true); - validateSettings(); - controller.changed(); - } else { - sharedSettingsTextField.setEnabled(false); - browseSharedSettingsButton.setEnabled(false); - masterNodeCheckBox.setEnabled(false); - downloadButton.setEnabled(false); - sharedSettingsErrorTextField.setText(""); - validateSettings(); - controller.changed(); - } - } - private void masterNodeCheckBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_masterNodeCheckBoxItemStateChanged // Enable the global settings text box and browse button iff the checkbox is checked and enabled setEnabledStateForSharedConfiguration(); @@ -1137,10 +955,31 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } }//GEN-LAST:event_masterNodeCheckBoxItemStateChanged - private void cbJoinAutoIngestClusterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbJoinAutoIngestClusterActionPerformed - enableOptionsBasedOnMode(getModeFromRadioButtons()); - controller.changed(); - }//GEN-LAST:event_cbJoinAutoIngestClusterActionPerformed + private void browseSharedSettingsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseSharedSettingsButtonActionPerformed + + String oldText = sharedSettingsTextField.getText().trim(); + // set the current directory of the FileChooser if the oldText is valid + File currentDir = new File(oldText); + if (currentDir.exists()) { + fc.setCurrentDirectory(currentDir); + } + + fc.setDialogTitle("Select shared configuration folder:"); + fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + + int retval = fc.showOpenDialog(this); + if (retval == JFileChooser.APPROVE_OPTION) { + String path = fc.getSelectedFile().getPath(); + sharedSettingsTextField.setText(path); + validateSettings(); + controller.changed(); + } + }//GEN-LAST:event_browseSharedSettingsButtonActionPerformed + + private void sharedConfigCheckboxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_sharedConfigCheckboxItemStateChanged + // Enable the global settings text box and browse button iff the checkbox is checked and enabled + setSharedConfigEnable(); + }//GEN-LAST:event_sharedConfigCheckboxItemStateChanged private void browseOutputFolderButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseOutputFolderButtonActionPerformed String oldText = outputPathTextField.getText().trim(); @@ -1182,24 +1021,6 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } }//GEN-LAST:event_browseInputFolderButtonActionPerformed - private void jRadioButtonReviewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButtonReviewActionPerformed - if (cbJoinAutoIngestCluster.isSelected()) { - enableOptionsBasedOnMode(OptionsUiMode.REVIEW); - setSharedConfigEnable(); - validateSettings(); - controller.changed(); - } - }//GEN-LAST:event_jRadioButtonReviewActionPerformed - - private void jRadioButtonAutomatedActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButtonAutomatedActionPerformed - if (cbJoinAutoIngestCluster.isSelected()) { - enableOptionsBasedOnMode(OptionsUiMode.AIM); - setSharedConfigEnable(); - validateSettings(); - controller.changed(); - } - }//GEN-LAST:event_jRadioButtonAutomatedActionPerformed - private void bnLoggingActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnLoggingActionPerformed JDialog jDialog = new JDialog(); NodeStatusLogPanel loggingPanel = new NodeStatusLogPanel(jDialog); @@ -1242,9 +1063,9 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { private void bnAdvancedSettingsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnAdvancedSettingsActionPerformed AdvancedAutoIngestSettingsPanel advancedAutoIngestSettingsPanel = new AdvancedAutoIngestSettingsPanel(getModeFromRadioButtons()); if (JOptionPane.showConfirmDialog(null, advancedAutoIngestSettingsPanel, - NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.AdvancedAutoIngestSettingsPanel.Title"), - JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE) == JOptionPane.OK_OPTION) { - advancedAutoIngestSettingsPanel.store(); + NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.AdvancedAutoIngestSettingsPanel.Title"), + JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE) == JOptionPane.OK_OPTION) { + advancedAutoIngestSettingsPanel.store(); } }//GEN-LAST:event_bnAdvancedSettingsActionPerformed @@ -1349,7 +1170,7 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } void setEnabledStateForSharedConfiguration() { - if (jRadioButtonAutomated.isSelected() && cbJoinAutoIngestCluster.isSelected()) { + if (cbJoinAutoIngestCluster.isSelected()) { enableOptionsBasedOnMode(OptionsUiMode.AIM); } } @@ -1361,19 +1182,13 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { bnLogging.setEnabled(enabled); browseInputFolderButton.setEnabled(enabled); browseOutputFolderButton.setEnabled(enabled); - browseSharedSettingsButton.setEnabled(sharedConfigCheckbox.isSelected() && jRadioButtonAutomated.isSelected()); + browseSharedSettingsButton.setEnabled(sharedConfigCheckbox.isSelected() && cbJoinAutoIngestCluster.isSelected()); configButtonErrorTextField.setEnabled(enabled); inputPathTextField.setEnabled(enabled); jLabelInvalidImageFolder.setEnabled(enabled); jLabelInvalidResultsFolder.setEnabled(enabled); jLabelSelectInputFolder.setEnabled(enabled); - jLabelSelectMode.setEnabled(enabled); jLabelSelectOutputFolder.setEnabled(enabled); - jPanelIngestSettings.setEnabled(enabled); - jPanelNodeType.setEnabled(enabled); - jPanelSharedConfig.setEnabled(enabled); - jRadioButtonAutomated.setEnabled(enabled); - jRadioButtonReview.setEnabled(enabled); outputPathTextField.setEnabled(enabled); } @@ -1389,20 +1204,12 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { private javax.swing.JTextField configButtonErrorTextField; private javax.swing.JButton downloadButton; private javax.swing.JTextField inputPathTextField; - private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabelCurrentTask; private javax.swing.JLabel jLabelInvalidImageFolder; private javax.swing.JLabel jLabelInvalidResultsFolder; private javax.swing.JLabel jLabelSelectInputFolder; - private javax.swing.JLabel jLabelSelectMode; private javax.swing.JLabel jLabelSelectOutputFolder; private javax.swing.JLabel jLabelTaskDescription; - private javax.swing.JPanel jPanelIngestSettings; - private javax.swing.JPanel jPanelNodeType; - private javax.swing.JPanel jPanelSharedConfig; - private javax.swing.JRadioButton jRadioButtonAutomated; - private javax.swing.JRadioButton jRadioButtonReview; - private javax.swing.JSeparator jSeparator1; private javax.swing.JCheckBox masterNodeCheckBox; private javax.swing.ButtonGroup modeRadioButtons; private javax.swing.JPanel nodePanel; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties index 66ed50dd20..a12453e3c1 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties @@ -23,12 +23,9 @@ AIMIngestSettingsPanel.lbSecondsBetweenJobs.toolTipText=Increase this value if d AIMIngestSettingsPanel.spSecondsBetweenJobs.toolTipText=Increase this value if database locks cause problems. It gives a little more time for finalizing. AutoIngestSettingsPanel.AdvancedAutoIngestSettingsPanel.Title=Advanced Settings AutoIngestSettingsPanel.browseGlobalSettingsButton.text=Browse -AutoIngestSettingsPanel.browseSharedSettingsButton.text=Browse AutoIngestSettingsPanel.CannotAccess=Cannot access AutoIngestSettingsPanel.cbJoinAutoIngestCluster.text=Join auto ingest cluster AutoIngestSettingsPanel.CheckPermissions=Check permissions. -AutoIngestSettingsPanel.configButtonErrorTextField.text=configButtonErrorTextField -AutoIngestSettingsPanel.downloadButton.text=Download Config AutoIngestSettingsPanel.EmptySettingsDirectory=Enter path to settings directory AutoIngestSettingsPanel.ErrorSettingDefaultFolder=Error creating default folder AutoIngestSettingsPanel.FileExportRules.text=File Export Rules @@ -36,12 +33,8 @@ AutoIngestSettingsPanel.globalSettingsErrorTextField.text= AutoIngestSettingsPanel.globalSettingsTextField.text= AutoIngestSettingsPanel.ImageDirectoryUnspecified=Shared images folder must be set AutoIngestSettingsPanel.InvalidPortNumber=Invalid port number. -AutoIngestSettingsPanel.jLabelCurrentTask.text=Current task: -AutoIngestSettingsPanel.jLabelTaskDescription.text=jLabel1 -AutoIngestSettingsPanel.jPanelSharedConfig.border.title=Shared Configuration AutoIngestSettingsPanel.jRadioButtonCopyFiles.text=File Copy mode AutoIngestSettingsPanel.KeywordSearchNull=Cannot find Keyword Search service -AutoIngestSettingsPanel.masterNodeCheckBox.text=Use this node as a master node that can upload settings AutoIngestSettingsPanel.MustRestart=Autopsy must be restarted for new configuration to take effect AutoIngestSettingsPanel.nodePanel.TabConstraints.tabTitle=Node Configuration AutoIngestSettingsPanel.NodeStatusLogging.text=Node Status Logging Settings @@ -49,11 +42,7 @@ AutoIngestSettingsPanel.PathInvalid=Path is not valid AutoIngestSettingsPanel.restartRequiredLabel.text=Application restart required to take effect. AutoIngestSettingsPanel.restartRequiredLabel.text=Application restart required AutoIngestSettingsPanel.ResultsDirectoryUnspecified=Shared cases folder must be set -AutoIngestSettingsPanel.sharedConfigCheckbox.text=Use shared configuration in folder: -AutoIngestSettingsPanel.sharedSettingsErrorTextField.text=globalSettingsErrorTextField -AutoIngestSettingsPanel.sharedSettingsTextField.text= AutoIngestSettingsPanel.tbOops.text= -AutoIngestSettingsPanel.uploadButton.text=Save & Upload Config AutoIngestSettingsPanel.validationErrMsg.incomplete=Fill in all values AutoIngestSettingsPanel.validationErrMsg.invalidDatabasePort=Invalid database port number AutoIngestSettingsPanel.validationErrMsg.invalidIndexingServerPort=Invalid Solr server port number @@ -119,8 +108,16 @@ AdvancedAutoIngestSettingsPanel.lbConcurrentJobsPerCase.toolTipText_1=A soft lim AdvancedAutoIngestSettingsPanel.lbNumberOfThreads.toolTipText_1=The number of threads running file level ingest modules. AdvancedAutoIngestSettingsPanel.numberOfFileIngestThreadsComboBox.toolTipText=The number of threads running file level ingest modules. NodeStatusLogPanel.tbDbName.toolTipText_1=Database name -AutoIngestSettingsPanel.jPanelNodeType.border.title=Node Type Setup -AutoIngestSettingsPanel.jLabel1.text= +AutoIngestSettingsPanel.sharedSettingsTextField.text= +AutoIngestSettingsPanel.sharedConfigCheckbox.text=Use shared configuration in folder: +AutoIngestSettingsPanel.configButtonErrorTextField.text=configButtonErrorTextField +AutoIngestSettingsPanel.jLabelTaskDescription.text=jLabel1 +AutoIngestSettingsPanel.jLabelCurrentTask.text=Current task: +AutoIngestSettingsPanel.downloadButton.text=Download Config +AutoIngestSettingsPanel.uploadButton.text=Save & Upload Config +AutoIngestSettingsPanel.masterNodeCheckBox.text=Use this node as a master node that can upload settings +AutoIngestSettingsPanel.sharedSettingsErrorTextField.text=globalSettingsErrorTextField +AutoIngestSettingsPanel.browseSharedSettingsButton.text=Browse AutoIngestSettingsPanel.jLabelInvalidResultsFolder.text=jLabelInvalidResultsFolder AutoIngestSettingsPanel.jLabelInvalidImageFolder.text=jLabelInvalidImageFolder AutoIngestSettingsPanel.browseOutputFolderButton.text=Browse @@ -131,12 +128,6 @@ AutoIngestSettingsPanel.browseInputFolderButton.text=Browse AutoIngestSettingsPanel.inputPathTextField.toolTipText=Input folder for automated processing, i.e., the location where input case folders will be created for ingest by automated processing mode AutoIngestSettingsPanel.inputPathTextField.text= AutoIngestSettingsPanel.jLabelSelectInputFolder.text=Select shared images folder: -AutoIngestSettingsPanel.jRadioButtonReview.toolTipText=Review cases created in automated processing mode -AutoIngestSettingsPanel.jRadioButtonReview.text=Examiner node -AutoIngestSettingsPanel.jRadioButtonAutomated.toolTipText=Automatically detect new data sources and create cases. -AutoIngestSettingsPanel.jRadioButtonAutomated.text=Auto ingest node (application restart required) -AutoIngestSettingsPanel.jLabelSelectMode.text=Select mode: -AutoIngestSettingsPanel.jPanelIngestSettings.border.title=Automated Ingest Settings AutoIngestSettingsPanel.bnLogging.text=Node Status Logging AutoIngestSettingsPanel.bnFileExport.text=File Export Settings AutoIngestSettingsPanel.bnAdvancedSettings.text=Advanced Settings From dd7c6d9c033477384a0dacee228c66482b545666 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 31 Oct 2017 16:38:11 -0400 Subject: [PATCH 035/115] Removed unnecessary method. --- .../org/sleuthkit/autopsy/casemodule/CueBannerPanel.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java index c4c15fdd91..9a45304c0f 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java @@ -60,7 +60,7 @@ public class CueBannerPanel extends javax.swing.JPanel { public CueBannerPanel() { initComponents(); - customizeComponents(); + initRecentCasesWindow(); enableComponents(); } @@ -86,10 +86,6 @@ public class CueBannerPanel extends javax.swing.JPanel { public void refresh() { enableComponents(); } - - private void customizeComponents() { - initRecentCasesWindow(); - } private void initRecentCasesWindow() { recentCasesWindow = new JDialog( From ae4f07c16461b51038fee78f942fced194197d45 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 31 Oct 2017 17:14:33 -0400 Subject: [PATCH 036/115] Updated documentation; moved updateConfig() to 'core' Installer. --- .../autopsy/casemodule/CueBannerPanel.java | 2 +- .../autopsy/casemodule/MultiUserCase.java | 9 ++++---- .../org/sleuthkit/autopsy/core/Installer.java | 22 +++++++++++++++++-- .../autopsy/corecomponents/Installer.java | 19 ---------------- 4 files changed, 25 insertions(+), 27 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java index 9a45304c0f..24c714eb5b 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java @@ -71,7 +71,7 @@ public class CueBannerPanel extends javax.swing.JPanel { ImageIcon icon = new ImageIcon(cl.getResource(welcomeLogo)); autopsyLogo.setIcon(icon); } - customizeComponents(); + initRecentCasesWindow(); enableComponents(); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java index 502ff260b1..e0bba29c43 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java @@ -29,10 +29,9 @@ import java.util.Date; import java.util.Objects; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.TimeStampUtils; /** - * A representation of a case created by automated ingest. + * A representation of a multi-user case. */ class MultiUserCase implements Comparable { @@ -44,7 +43,7 @@ class MultiUserCase implements Comparable { private final Date lastAccessedDate; /** - * Constructs a representation of case created by automated ingest. + * Constructs a representation of a multi-user case * * @param caseDirectoryPath The case directory path. * @@ -219,7 +218,7 @@ class MultiUserCase implements Comparable { } /** - * Compares this AutopIngestCase object with abnother MultiUserCase object + * Compares this MultiUserCase object with another MultiUserCase object * for order. */ @Override @@ -237,7 +236,7 @@ class MultiUserCase implements Comparable { * date (descending). * * @param object The first MultiUserCase object - * @param otherObject The second AuotIngestCase object. + * @param otherObject The second MultiUserCase object. * * @return A negative integer, zero, or a positive integer as the first * argument is less than, equal to, or greater than the second. diff --git a/Core/src/org/sleuthkit/autopsy/core/Installer.java b/Core/src/org/sleuthkit/autopsy/core/Installer.java index 0b660acd2a..83250f719d 100755 --- a/Core/src/org/sleuthkit/autopsy/core/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/core/Installer.java @@ -29,15 +29,15 @@ import java.util.logging.Handler; import java.util.logging.Level; import javafx.application.Platform; import javafx.embed.swing.JFXPanel; -import javax.swing.SwingWorker; -import org.openide.LifecycleManager; import org.openide.modules.ModuleInstall; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.actions.IngestRunningCheck; import org.sleuthkit.autopsy.casemodule.Case; +import static org.sleuthkit.autopsy.core.UserPreferences.SETTINGS_PROPERTIES; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; /** @@ -206,6 +206,9 @@ public class Installer extends ModuleInstall { // Prevent the Autopsy UI from shrinking on high DPI displays System.setProperty("sun.java2d.dpiaware", "false"); System.setProperty("prism.allowhidpi", "false"); + + // Update existing configuration in case of unsupported settings + updateConfig(); packageInstallers = new ArrayList<>(); packageInstallers.add(org.sleuthkit.autopsy.coreutils.Installer.getDefault()); @@ -214,6 +217,21 @@ public class Installer extends ModuleInstall { packageInstallers.add(org.sleuthkit.autopsy.ingest.Installer.getDefault()); packageInstallers.add(org.sleuthkit.autopsy.centralrepository.eventlisteners.Installer.getDefault()); } + + /** + * If the mode in the configuration file is 'REVIEW' (2, now invalid), this + * method will set it to 'STANDALONE' (0) and disable auto ingest. + */ + private void updateConfig() { + String mode = ModuleSettings.getConfigSetting(SETTINGS_PROPERTIES, "AutopsyMode"); + if(mode != null) { + int ordinal = Integer.parseInt(mode); + if(ordinal > 1) { + UserPreferences.setMode(UserPreferences.SelectedMode.STANDALONE); + ModuleSettings.setConfigSetting(UserPreferences.SETTINGS_PROPERTIES, "JoinAutoModeCluster", Boolean.toString(false)); + } + } + } /** * Check if JavaFx initialized diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java b/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java index 060061e205..c908f3b35d 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java @@ -30,10 +30,7 @@ import org.netbeans.swing.tabcontrol.plaf.DefaultTabbedContainerUI; import org.openide.modules.ModuleInstall; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.StartupWindowProvider; -import org.sleuthkit.autopsy.core.UserPreferences; -import static org.sleuthkit.autopsy.core.UserPreferences.SETTINGS_PROPERTIES; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.ModuleSettings; /** * Manages this module's life cycle. Opens the startup dialog during startup. @@ -62,7 +59,6 @@ public class Installer extends ModuleInstall { UIManager.put("ViewTabDisplayerUI", "org.sleuthkit.autopsy.corecomponents.NoTabsTabDisplayerUI"); UIManager.put(DefaultTabbedContainerUI.KEY_VIEW_CONTENT_BORDER, BorderFactory.createEmptyBorder()); UIManager.put("TabbedPane.contentBorderInsets", new Insets(0, 0, 0, 0)); - updateConfig(); WindowManager.getDefault().invokeWhenUIReady(() -> { StartupWindowProvider.getInstance().open(); }); @@ -72,21 +68,6 @@ public class Installer extends ModuleInstall { public void uninstalled() { super.uninstalled(); } - - /** - * If the mode in the configuration file is 'REVIEW' (2, now invalid), this - * method will set it to 'STANDALONE' (0) and disable auto ingest. - */ - private void updateConfig() { - String mode = ModuleSettings.getConfigSetting(SETTINGS_PROPERTIES, "AutopsyMode"); - if(mode != null) { - int ordinal = Integer.parseInt(mode); - if(ordinal > 1) { - UserPreferences.setMode(UserPreferences.SelectedMode.STANDALONE); - ModuleSettings.setConfigSetting(UserPreferences.SETTINGS_PROPERTIES, "JoinAutoModeCluster", Boolean.toString(false)); - } - } - } private void setLookAndFeel() { if (System.getProperty("os.name").toLowerCase().contains("mac")) { //NON-NLS From 59df3725072497ed149410895333eb4f31e73816 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 31 Oct 2017 17:23:21 -0400 Subject: [PATCH 037/115] Add unit test utilities to Autopsy-Core NBM --- .../testutils/UnitTestDspCallback.java | 109 ++++++++++++++++++ .../testutils/UnitTestDspProgressMonitor.java | 62 ++++++++++ 2 files changed, 171 insertions(+) create mode 100755 Core/test/unit/src/org/sleuthkit/autopsy/testutils/UnitTestDspCallback.java create mode 100755 Core/test/unit/src/org/sleuthkit/autopsy/testutils/UnitTestDspProgressMonitor.java diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/testutils/UnitTestDspCallback.java b/Core/test/unit/src/org/sleuthkit/autopsy/testutils/UnitTestDspCallback.java new file mode 100755 index 0000000000..c6adb1f24c --- /dev/null +++ b/Core/test/unit/src/org/sleuthkit/autopsy/testutils/UnitTestDspCallback.java @@ -0,0 +1,109 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.testutils; + +import java.util.ArrayList; +import java.util.List; +import javax.annotation.concurrent.Immutable; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; +import org.sleuthkit.datamodel.Content; + +/** + * A data source processor "callback" for unit testing that collects the results + * of running a data source processor on a data source and unblocks the job + * processing thread when the data source processor finishes running in its own + * thread. + */ +@Immutable +public class UnitTestDspCallback extends DataSourceProcessorCallback { + + private final Object monitor; + private final List errorMessages = new ArrayList<>(); + private final List dataSourceContent = new ArrayList<>(); + + /** + * Constructs a data source processor "callback" for unit testing that + * collects the results of running a data source processor on a data source + * and unblocks the job processing thread when the data source processor + * finishes running in its own thread. + * + * @param monitor A monitor for the callback to signal when the data source + * processor completes its processing. + */ + UnitTestDspCallback(Object monitor) { + this.monitor = monitor; + } + + /** + * Called by the data source processor when it finishes running in its own + * thread. + * + * @param result The result code for the processing of the data + * source. + * @param errorMessages Any error messages generated during the + * processing of the data source. + * @param dataSourceContent The content produced by processing the data + * source. + */ + @Override + public void done(DataSourceProcessorCallback.DataSourceProcessorResult result, List errorMessages, List dataSourceContent) { + this.errorMessages.addAll(errorMessages); + this.dataSourceContent.addAll(dataSourceContent); + synchronized (monitor) { + monitor.notify(); + } + } + + /** + * Called by the data source processor when it finishes running in its own + * thread, if that thread is the AWT (Abstract Window Toolkit) event + * dispatch thread (EDT). + * + * @param result The result code for the processing of the data + * source. + * @param errorMessages Any error messages generated during the + * processing of the data source. + * @param dataSourceContent The content produced by processing the data + * source. + */ + @Override + public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List errorMessages, List dataSourceContent) { + done(result, errorMessages, dataSourceContent); + } + + /** + * Gets any error messages emitted by the data source processor. + * + * @return A list of error messages, possibly empty. + */ + public List getDspErrorMessages() { + return new ArrayList<>(this.errorMessages); + } + + /** + * Gets any data source content objects produced by the data source + * processor. + * + * @return A list of content objects, possibly empty. + */ + public List getDataSourceContent() { + return new ArrayList<>(this.dataSourceContent); + } + +} diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/testutils/UnitTestDspProgressMonitor.java b/Core/test/unit/src/org/sleuthkit/autopsy/testutils/UnitTestDspProgressMonitor.java new file mode 100755 index 0000000000..1f856e6500 --- /dev/null +++ b/Core/test/unit/src/org/sleuthkit/autopsy/testutils/UnitTestDspProgressMonitor.java @@ -0,0 +1,62 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.testutils; + +import javax.annotation.concurrent.Immutable; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; + +/** + * A data source processor progress monitor for unit testing. + */ +@Immutable +public class UnitTestDspProgressMonitor implements DataSourceProcessorProgressMonitor { + + /** + * Switches the progress indicator to indeterminate mode (the total number + * of work units to be completed is unknown) or determinate mode (the total + * number of work units to be completed is unknown). + * + * @param indeterminate True for indeterminate mode, false for determinate + * mode. + */ + @Override + public void setIndeterminate(final boolean indeterminate) { + } + + /** + * Updates the progress indicator with the number of work units completed so + * far when in determinate mode (the total number of work units to be + * completed is known). + * + * @param workUnitsCompleted Number of work units completed so far. + */ + @Override + public void setProgress(final int workUnitsCompleted) { + } + + /** + * Updates the progress indicator with a progress message. + * + * @param message The progress message. + */ + @Override + public void setProgressText(final String message) { + } + +} From 2d4852f22d40d8ccbb633b4a76a4d926133a9c54 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 1 Nov 2017 09:53:45 -0400 Subject: [PATCH 038/115] Table refresh NPE fixed using 'invokeLater()'. --- .../casemodule/MultiUserCasesPanel.java | 68 ++++++++----------- 1 file changed, 30 insertions(+), 38 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java index bce0a33602..42201e5850 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.concurrent.ExecutionException; import java.util.logging.Level; import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.event.ListSelectionEvent; import javax.swing.table.DefaultTableModel; @@ -167,47 +168,38 @@ public class MultiUserCasesPanel extends javax.swing.JPanel { setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); }); - new SwingWorker() { - - @Override - protected Void doInBackground() throws Exception { - try { - currentlySelectedCase = getSelectedCase(); - MultiUserCaseManager manager = MultiUserCaseManager.getInstance(); - List cases = manager.getCases(); - cases.sort(REVERSE_DATE_MODIFIED_COMPARATOR); - caseTableModel.setRowCount(0); - long now = new Date().getTime(); - for (MultiUserCase autoIngestCase : cases) { - if (passesTimeFilter(now, autoIngestCase.getLastAccessedDate().getTime())) { - caseTableModel.addRow(new Object[]{ - autoIngestCase.getCaseDisplayName(), - autoIngestCase.getCreationDate(), - autoIngestCase.getLastAccessedDate(), - (MultiUserCase.CaseStatus.OK != autoIngestCase.getStatus()), - autoIngestCase.getCaseDirectoryPath().toString(), - autoIngestCase.getMetadataFileName()}); + synchronized(this) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + try { + currentlySelectedCase = getSelectedCase(); + MultiUserCaseManager manager = MultiUserCaseManager.getInstance(); + List cases = manager.getCases(); + cases.sort(REVERSE_DATE_MODIFIED_COMPARATOR); + caseTableModel.setRowCount(0); + long now = new Date().getTime(); + for (MultiUserCase autoIngestCase : cases) { + if (passesTimeFilter(now, autoIngestCase.getLastAccessedDate().getTime())) { + caseTableModel.addRow(new Object[]{ + autoIngestCase.getCaseDisplayName(), + autoIngestCase.getCreationDate(), + autoIngestCase.getLastAccessedDate(), + (MultiUserCase.CaseStatus.OK != autoIngestCase.getStatus()), + autoIngestCase.getCaseDirectoryPath().toString(), + autoIngestCase.getMetadataFileName()}); + } } + setSelectedCase(currentlySelectedCase); + setButtons(); + } catch (Exception ex) { + LOGGER.log(Level.SEVERE, "Unexpected exception while refreshing the table.", ex); //NON-NLS + } finally { + setCursor(null); } - setSelectedCase(currentlySelectedCase); - setButtons(); - } catch (Exception ex) { - LOGGER.log(Level.SEVERE, "Unexpected exception while refreshing the table.", ex); //NON-NLS } - return null; - } - - @Override - protected void done() { - super.done(); - setCursor(null); - try { - get(); - } catch (InterruptedException | ExecutionException ex) { - LOGGER.log(Level.SEVERE, "Unexpected exception while refreshing the table.", ex); //NON-NLS - } - } - }.execute(); + }); + } } /** From a19b32e3893278034f22b9cd1b925abc45a27e2e Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 1 Nov 2017 16:25:15 -0400 Subject: [PATCH 039/115] Rewrote portions of 'doRecoveryIfCrashed()' to fix bugs. --- .../autoingest/AutoIngestManager.java | 248 +++++------------- 1 file changed, 63 insertions(+), 185 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index 9f43879b55..a779085813 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -37,7 +37,6 @@ import java.time.Duration; import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.EnumSet; @@ -59,13 +58,11 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.stream.Collectors; import javax.annotation.concurrent.GuardedBy; -import javax.annotation.concurrent.Immutable; -import javax.annotation.concurrent.ThreadSafe; -import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.casemodule.CaseActionException; +import org.sleuthkit.autopsy.casemodule.CaseDetails; import org.sleuthkit.autopsy.casemodule.CaseMetadata; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; @@ -101,7 +98,6 @@ import org.sleuthkit.autopsy.ingest.IngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestJobStartResult; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestModuleError; -import org.sleuthkit.datamodel.Content; /** * An auto ingest manager is responsible for processing auto ingest jobs defined @@ -503,7 +499,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang } SYS_LOGGER.log(Level.INFO, "Starting input scan of {0}", rootInputDirectory); InputDirScanner scanner = new InputDirScanner(); - scanner.scan(); SYS_LOGGER.log(Level.INFO, "Completed input scan of {0}", rootInputDirectory); } @@ -559,12 +554,10 @@ public final class AutoIngestManager extends Observable implements PropertyChang if (!prioritizedJobs.isEmpty()) { ++maxPriority; for (AutoIngestJob job : prioritizedJobs) { - int oldPriority = job.getPriority(); - job.setPriority(maxPriority); try { this.updateCoordinationServiceNode(job); + job.setPriority(maxPriority); } catch (CoordinationServiceException | InterruptedException ex) { - job.setPriority(oldPriority); throw new AutoIngestManagerException("Error updating case priority", ex); } } @@ -615,14 +608,12 @@ public final class AutoIngestManager extends Observable implements PropertyChang */ if (null != prioritizedJob) { ++maxPriority; - int oldPriority = prioritizedJob.getPriority(); - prioritizedJob.setPriority(maxPriority); try { this.updateCoordinationServiceNode(prioritizedJob); } catch (CoordinationServiceException | InterruptedException ex) { - prioritizedJob.setPriority(oldPriority); throw new AutoIngestManagerException("Error updating job priority", ex); } + prioritizedJob.setPriority(maxPriority); } Collections.sort(pendingJobs, new AutoIngestJob.PriorityComparator()); @@ -1051,8 +1042,8 @@ public final class AutoIngestManager extends Observable implements PropertyChang if (null != manifest) { /* - * Update the mapping of case names to manifest paths that - * is used for case deletion. + * Update the mapping of case names to manifest paths that is + * used for case deletion. */ String caseName = manifest.getCaseName(); Path manifestPath = manifest.getFilePath(); @@ -1066,8 +1057,8 @@ public final class AutoIngestManager extends Observable implements PropertyChang } /* - * Add a job to the pending jobs queue, the completed jobs - * list, or do crashed job recovery, as required. + * Add a job to the pending jobs queue, the completed jobs list, + * or do crashed job recovery, as required. */ try { byte[] rawData = coordinationService.getNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestPath.toString()); @@ -1087,7 +1078,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang break; case DELETED: /* - * Ignore jobs marked as "deleted." + * Ignore jobs marked as "deleted." */ break; default: @@ -1247,48 +1238,38 @@ public final class AutoIngestManager extends Observable implements PropertyChang if (null != manifestLock) { SYS_LOGGER.log(Level.SEVERE, "Attempting crash recovery for {0}", manifestPath); try { + Path caseDirectoryPath = PathUtils.findCaseDirectory(rootOutputDirectory, manifest.getCaseName()); + /* * Create the recovery job. */ AutoIngestJob job = new AutoIngestJob(nodeData); int numberOfCrashes = job.getNumberOfCrashes(); - ++numberOfCrashes; - job.setNumberOfCrashes(numberOfCrashes); - job.setCompletedDate(new Date(0)); - Path caseDirectoryPath = PathUtils.findCaseDirectory(rootOutputDirectory, manifest.getCaseName()); + if (numberOfCrashes <= AutoIngestUserPreferences.getMaxNumTimesToProcessImage()) { + ++numberOfCrashes; + job.setNumberOfCrashes(numberOfCrashes); + if (numberOfCrashes <= AutoIngestUserPreferences.getMaxNumTimesToProcessImage()) { + job.setCompletedDate(new Date(0)); + } else { + job.setCompletedDate(Date.from(Instant.now())); + } + } + if (null != caseDirectoryPath) { job.setCaseDirectoryPath(caseDirectoryPath); job.setErrorsOccurred(true); - } else { - job.setErrorsOccurred(false); - } - - /* - * Update the coordination service node for the job. If - * this fails, leave the recovery to another host. - */ - try { - updateCoordinationServiceNode(job); - if (numberOfCrashes <= AutoIngestUserPreferences.getMaxNumTimesToProcessImage()) { - newPendingJobsList.add(job); - } else { - newCompletedJobsList.add(new AutoIngestJob(nodeData)); - } - } catch (CoordinationServiceException ex) { - SYS_LOGGER.log(Level.SEVERE, String.format("Error attempting to set node data for %s", manifestPath), ex); - return; - } - - /* - * Write the alert file and do the logging. - */ - if (null != caseDirectoryPath) { try { - AutoIngestAlertFile.create(nodeData.getCaseDirectoryPath()); + /* + * Write the alert file and do the logging. + */ + AutoIngestAlertFile.create(caseDirectoryPath); } catch (AutoIngestAlertFileException ex) { SYS_LOGGER.log(Level.SEVERE, String.format("Error creating alert file for crashed job for %s", manifestPath), ex); } + } else { + job.setErrorsOccurred(false); } + if (numberOfCrashes <= AutoIngestUserPreferences.getMaxNumTimesToProcessImage()) { job.setProcessingStatus(AutoIngestJob.ProcessingStatus.PENDING); if (null != caseDirectoryPath) { @@ -1302,13 +1283,32 @@ public final class AutoIngestManager extends Observable implements PropertyChang job.setProcessingStatus(AutoIngestJob.ProcessingStatus.COMPLETED); if (null != caseDirectoryPath) { try { - new AutoIngestJobLogger(manifest.getFilePath(), manifest.getDataSourceFileName(), nodeData.getCaseDirectoryPath()).logCrashRecoveryNoRetry(); + new AutoIngestJobLogger(manifest.getFilePath(), manifest.getDataSourceFileName(), caseDirectoryPath).logCrashRecoveryNoRetry(); } catch (AutoIngestJobLoggerException ex) { SYS_LOGGER.log(Level.SEVERE, String.format("Error creating case auto ingest log entry for crashed job for %s", manifestPath), ex); } } } + /* + * Update the coordination service node for the job. If + * this fails, leave the recovery to another host. + */ + try { + updateCoordinationServiceNode(job); + } catch (CoordinationServiceException ex) { + SYS_LOGGER.log(Level.SEVERE, String.format("Error attempting to set node data for %s", manifestPath), ex); + return; + } + + nodeData = new AutoIngestJobNodeData(job); + + if (numberOfCrashes <= AutoIngestUserPreferences.getMaxNumTimesToProcessImage()) { + newPendingJobsList.add(job); + } else { + newCompletedJobsList.add(new AutoIngestJob(nodeData)); + } + } finally { try { manifestLock.release(); @@ -1459,7 +1459,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang */ private final class JobProcessingTask implements Runnable { - private static final String AUTO_INGEST_MODULE_OUTPUT_DIR = "AutoIngest"; private final Object ingestLock; private final Object pauseLock; @GuardedBy("pauseLock") @@ -2126,7 +2125,8 @@ public final class AutoIngestManager extends Observable implements PropertyChang Case.openAsCurrentCase(metadataFilePath.toString()); } else { caseDirectoryPath = PathUtils.createCaseFolderPath(rootOutputDirectory, caseName); - Case.createAsCurrentCase(caseDirectoryPath.toString(), caseName, "", "", CaseType.MULTI_USER_CASE); + CaseDetails caseDetails = new CaseDetails(caseName, "", "", "", "", ""); + Case.createAsCurrentCase(CaseType.MULTI_USER_CASE, caseDirectoryPath.toString(), caseDetails); /* * Sleep a bit before releasing the lock to ensure * that the new case folder is visible on the @@ -2222,7 +2222,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang return; } - DataSource dataSource = identifyDataSource(caseForJob); + DataSource dataSource = identifyDataSource(); if (null == dataSource) { currentJob.setProcessingStage(AutoIngestJob.Stage.COMPLETED, Date.from(Instant.now())); return; @@ -2275,7 +2275,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang * interrupted while blocked, i.e., * if auto ingest is shutting down. */ - private DataSource identifyDataSource(Case caseForJob) throws AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException { + private DataSource identifyDataSource() throws AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException { Manifest manifest = currentJob.getManifest(); Path manifestPath = manifest.getFilePath(); SYS_LOGGER.log(Level.INFO, "Identifying data source for {0} ", manifestPath); @@ -2294,7 +2294,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang String deviceId = manifest.getDeviceId(); return new DataSource(deviceId, dataSourcePath); } - + /** * Passes the data source for the current job through a data source * processor that adds it to the case database. @@ -2317,28 +2317,21 @@ public final class AutoIngestManager extends Observable implements PropertyChang SYS_LOGGER.log(Level.INFO, "Adding data source for {0} ", manifestPath); currentJob.setProcessingStage(AutoIngestJob.Stage.ADDING_DATA_SOURCE, Date.from(Instant.now())); UUID taskId = UUID.randomUUID(); - DataSourceProcessorCallback callBack = new AddDataSourceCallback(caseForJob, dataSource, taskId); + DataSourceProcessorCallback callBack = new AddDataSourceCallback(caseForJob, dataSource, taskId, ingestLock); DataSourceProcessorProgressMonitor progressMonitor = new DoNothingDSPProgressMonitor(); Path caseDirectoryPath = currentJob.getCaseDirectoryPath(); AutoIngestJobLogger jobLogger = new AutoIngestJobLogger(manifestPath, manifest.getDataSourceFileName(), caseDirectoryPath); try { caseForJob.notifyAddingDataSource(taskId); - // lookup all AutomatedIngestDataSourceProcessors - Collection processorCandidates = Lookup.getDefault().lookupAll(AutoIngestDataSourceProcessor.class); - - Map validDataSourceProcessorsMap = new HashMap<>(); - for (AutoIngestDataSourceProcessor processor : processorCandidates) { - try { - int confidence = processor.canProcess(dataSource.getPath()); - if (confidence > 0) { - validDataSourceProcessorsMap.put(processor, confidence); - } - } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) { - SYS_LOGGER.log(Level.SEVERE, "Exception while determining whether data source processor {0} can process {1}", new Object[]{processor.getDataSourceType(), dataSource.getPath()}); - // rethrow the exception. It will get caught & handled upstream and will result in AIM auto-pause. - throw ex; - } + Map validDataSourceProcessorsMap; + try { + // lookup all AutomatedIngestDataSourceProcessors and poll which ones are able to process the current data source + validDataSourceProcessorsMap = DataSourceProcessorUtility.getDataSourceProcessor(dataSource.getPath()); + } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) { + SYS_LOGGER.log(Level.SEVERE, "Exception while determining best data source processor for {0}", dataSource.getPath()); + // rethrow the exception. It will get caught & handled upstream and will result in AIM auto-pause. + throw ex; } // did we find a data source processor that can process the data source @@ -2595,80 +2588,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang jobLogger.logFileExportError(); } } - - /** - * A "callback" that collects the results of running a data source - * processor on a data source and unblocks the job processing thread - * when the data source processor finishes running in its own thread. - */ - @Immutable - class AddDataSourceCallback extends DataSourceProcessorCallback { - - private final Case caseForJob; - private final DataSource dataSourceInfo; - private final UUID taskId; - - /** - * Constructs a "callback" that collects the results of running a - * data source processor on a data source and unblocks the job - * processing thread when the data source processor finishes running - * in its own thread. - * - * @param caseForJob The case for the current job. - * @param dataSourceInfo The data source - * @param taskId The task id to associate with ingest job - * events. - */ - AddDataSourceCallback(Case caseForJob, DataSource dataSourceInfo, UUID taskId) { - this.caseForJob = caseForJob; - this.dataSourceInfo = dataSourceInfo; - this.taskId = taskId; - } - - /** - * Called by the data source processor when it finishes running in - * its own thread. - * - * @param result The result code for the processing of - * the data source. - * @param errorMessages Any error messages generated during the - * processing of the data source. - * @param dataSourceContent The content produced by processing the - * data source. - */ - @Override - public void done(DataSourceProcessorCallback.DataSourceProcessorResult result, List errorMessages, List dataSourceContent) { - if (!dataSourceContent.isEmpty()) { - caseForJob.notifyDataSourceAdded(dataSourceContent.get(0), taskId); - } else { - caseForJob.notifyFailedAddingDataSource(taskId); - } - dataSourceInfo.setDataSourceProcessorOutput(result, errorMessages, dataSourceContent); - dataSourceContent.addAll(dataSourceContent); - synchronized (ingestLock) { - ingestLock.notify(); - } - } - - /** - * Called by the data source processor when it finishes running in - * its own thread, if that thread is the AWT (Abstract Window - * Toolkit) event dispatch thread (EDT). - * - * @param result The result code for the processing of - * the data source. - * @param errorMessages Any error messages generated during the - * processing of the data source. - * @param dataSourceContent The content produced by processing the - * data source. - */ - @Override - public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List errorMessages, List dataSources) { - done(result, errorMessages, dataSources); - } - - } - + /** * A data source processor progress monitor does nothing. There is * currently no mechanism for showing or recording data source processor @@ -3008,49 +2928,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang PARTIALLY_DELETED, FULLY_DELETED } - - @ThreadSafe - private static final class DataSource { - - private final String deviceId; - private final Path path; - private DataSourceProcessorResult resultCode; - private List errorMessages; - private List content; - - DataSource(String deviceId, Path path) { - this.deviceId = deviceId; - this.path = path; - } - - String getDeviceId() { - return deviceId; - } - - Path getPath() { - return this.path; - } - - synchronized void setDataSourceProcessorOutput(DataSourceProcessorResult result, List errorMessages, List content) { - this.resultCode = result; - this.errorMessages = new ArrayList<>(errorMessages); - this.content = new ArrayList<>(content); - } - - synchronized DataSourceProcessorResult getResultDataSourceProcessorResultCode() { - return resultCode; - } - - synchronized List getDataSourceProcessorErrorMessages() { - return new ArrayList<>(errorMessages); - } - - synchronized List getContent() { - return new ArrayList<>(content); - } - - } - + static final class AutoIngestManagerException extends Exception { private static final long serialVersionUID = 1L; From 29c25d71e6cbd59a64831a6ee0997091b81261cd Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 1 Nov 2017 16:35:44 -0400 Subject: [PATCH 040/115] Minor revision --- .../autopsy/experimental/autoingest/AutoIngestManager.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index a779085813..cf41d00df2 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -62,7 +62,6 @@ import org.openide.util.Lookup; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.casemodule.CaseActionException; -import org.sleuthkit.autopsy.casemodule.CaseDetails; import org.sleuthkit.autopsy.casemodule.CaseMetadata; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; @@ -2125,8 +2124,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang Case.openAsCurrentCase(metadataFilePath.toString()); } else { caseDirectoryPath = PathUtils.createCaseFolderPath(rootOutputDirectory, caseName); - CaseDetails caseDetails = new CaseDetails(caseName, "", "", "", "", ""); - Case.createAsCurrentCase(CaseType.MULTI_USER_CASE, caseDirectoryPath.toString(), caseDetails); + Case.createAsCurrentCase(caseDirectoryPath.toString(), caseName, "", "", CaseType.MULTI_USER_CASE); /* * Sleep a bit before releasing the lock to ensure * that the new case folder is visible on the From d0e5f9d50b7c7f5c961e0611b93d38fdcce2deee Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 1 Nov 2017 16:40:55 -0400 Subject: [PATCH 041/115] Minor revision --- .../autoingest/AutoIngestManager.java | 177 +++++++++++++++--- 1 file changed, 155 insertions(+), 22 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index cf41d00df2..3f28487394 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -37,6 +37,7 @@ import java.time.Duration; import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.EnumSet; @@ -58,6 +59,9 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.stream.Collectors; import javax.annotation.concurrent.GuardedBy; +import javax.annotation.concurrent.Immutable; +import javax.annotation.concurrent.ThreadSafe; +import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case.CaseType; @@ -97,6 +101,7 @@ import org.sleuthkit.autopsy.ingest.IngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestJobStartResult; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestModuleError; +import org.sleuthkit.datamodel.Content; /** * An auto ingest manager is responsible for processing auto ingest jobs defined @@ -498,6 +503,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang } SYS_LOGGER.log(Level.INFO, "Starting input scan of {0}", rootInputDirectory); InputDirScanner scanner = new InputDirScanner(); + scanner.scan(); SYS_LOGGER.log(Level.INFO, "Completed input scan of {0}", rootInputDirectory); } @@ -553,10 +559,12 @@ public final class AutoIngestManager extends Observable implements PropertyChang if (!prioritizedJobs.isEmpty()) { ++maxPriority; for (AutoIngestJob job : prioritizedJobs) { + int oldPriority = job.getPriority(); + job.setPriority(maxPriority); try { this.updateCoordinationServiceNode(job); - job.setPriority(maxPriority); } catch (CoordinationServiceException | InterruptedException ex) { + job.setPriority(oldPriority); throw new AutoIngestManagerException("Error updating case priority", ex); } } @@ -607,12 +615,14 @@ public final class AutoIngestManager extends Observable implements PropertyChang */ if (null != prioritizedJob) { ++maxPriority; + int oldPriority = prioritizedJob.getPriority(); + prioritizedJob.setPriority(maxPriority); try { this.updateCoordinationServiceNode(prioritizedJob); } catch (CoordinationServiceException | InterruptedException ex) { + prioritizedJob.setPriority(oldPriority); throw new AutoIngestManagerException("Error updating job priority", ex); } - prioritizedJob.setPriority(maxPriority); } Collections.sort(pendingJobs, new AutoIngestJob.PriorityComparator()); @@ -1041,8 +1051,8 @@ public final class AutoIngestManager extends Observable implements PropertyChang if (null != manifest) { /* - * Update the mapping of case names to manifest paths that is - * used for case deletion. + * Update the mapping of case names to manifest paths that + * is used for case deletion. */ String caseName = manifest.getCaseName(); Path manifestPath = manifest.getFilePath(); @@ -1056,8 +1066,8 @@ public final class AutoIngestManager extends Observable implements PropertyChang } /* - * Add a job to the pending jobs queue, the completed jobs list, - * or do crashed job recovery, as required. + * Add a job to the pending jobs queue, the completed jobs + * list, or do crashed job recovery, as required. */ try { byte[] rawData = coordinationService.getNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestPath.toString()); @@ -1077,7 +1087,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang break; case DELETED: /* - * Ignore jobs marked as "deleted." + * Ignore jobs marked as "deleted." */ break; default: @@ -1458,6 +1468,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang */ private final class JobProcessingTask implements Runnable { + private static final String AUTO_INGEST_MODULE_OUTPUT_DIR = "AutoIngest"; private final Object ingestLock; private final Object pauseLock; @GuardedBy("pauseLock") @@ -2220,7 +2231,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang return; } - DataSource dataSource = identifyDataSource(); + DataSource dataSource = identifyDataSource(caseForJob); if (null == dataSource) { currentJob.setProcessingStage(AutoIngestJob.Stage.COMPLETED, Date.from(Instant.now())); return; @@ -2273,7 +2284,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang * interrupted while blocked, i.e., * if auto ingest is shutting down. */ - private DataSource identifyDataSource() throws AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException { + private DataSource identifyDataSource(Case caseForJob) throws AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException { Manifest manifest = currentJob.getManifest(); Path manifestPath = manifest.getFilePath(); SYS_LOGGER.log(Level.INFO, "Identifying data source for {0} ", manifestPath); @@ -2292,7 +2303,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang String deviceId = manifest.getDeviceId(); return new DataSource(deviceId, dataSourcePath); } - + /** * Passes the data source for the current job through a data source * processor that adds it to the case database. @@ -2315,21 +2326,28 @@ public final class AutoIngestManager extends Observable implements PropertyChang SYS_LOGGER.log(Level.INFO, "Adding data source for {0} ", manifestPath); currentJob.setProcessingStage(AutoIngestJob.Stage.ADDING_DATA_SOURCE, Date.from(Instant.now())); UUID taskId = UUID.randomUUID(); - DataSourceProcessorCallback callBack = new AddDataSourceCallback(caseForJob, dataSource, taskId, ingestLock); + DataSourceProcessorCallback callBack = new AddDataSourceCallback(caseForJob, dataSource, taskId); DataSourceProcessorProgressMonitor progressMonitor = new DoNothingDSPProgressMonitor(); Path caseDirectoryPath = currentJob.getCaseDirectoryPath(); AutoIngestJobLogger jobLogger = new AutoIngestJobLogger(manifestPath, manifest.getDataSourceFileName(), caseDirectoryPath); try { caseForJob.notifyAddingDataSource(taskId); - Map validDataSourceProcessorsMap; - try { - // lookup all AutomatedIngestDataSourceProcessors and poll which ones are able to process the current data source - validDataSourceProcessorsMap = DataSourceProcessorUtility.getDataSourceProcessor(dataSource.getPath()); - } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) { - SYS_LOGGER.log(Level.SEVERE, "Exception while determining best data source processor for {0}", dataSource.getPath()); - // rethrow the exception. It will get caught & handled upstream and will result in AIM auto-pause. - throw ex; + // lookup all AutomatedIngestDataSourceProcessors + Collection processorCandidates = Lookup.getDefault().lookupAll(AutoIngestDataSourceProcessor.class); + + Map validDataSourceProcessorsMap = new HashMap<>(); + for (AutoIngestDataSourceProcessor processor : processorCandidates) { + try { + int confidence = processor.canProcess(dataSource.getPath()); + if (confidence > 0) { + validDataSourceProcessorsMap.put(processor, confidence); + } + } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) { + SYS_LOGGER.log(Level.SEVERE, "Exception while determining whether data source processor {0} can process {1}", new Object[]{processor.getDataSourceType(), dataSource.getPath()}); + // rethrow the exception. It will get caught & handled upstream and will result in AIM auto-pause. + throw ex; + } } // did we find a data source processor that can process the data source @@ -2586,7 +2604,80 @@ public final class AutoIngestManager extends Observable implements PropertyChang jobLogger.logFileExportError(); } } - + + /** + * A "callback" that collects the results of running a data source + * processor on a data source and unblocks the job processing thread + * when the data source processor finishes running in its own thread. + */ + @Immutable + class AddDataSourceCallback extends DataSourceProcessorCallback { + + private final Case caseForJob; + private final DataSource dataSourceInfo; + private final UUID taskId; + + /** + * Constructs a "callback" that collects the results of running a + * data source processor on a data source and unblocks the job + * processing thread when the data source processor finishes running + * in its own thread. + * + * @param caseForJob The case for the current job. + * @param dataSourceInfo The data source + * @param taskId The task id to associate with ingest job + * events. + */ + AddDataSourceCallback(Case caseForJob, DataSource dataSourceInfo, UUID taskId) { + this.caseForJob = caseForJob; + this.dataSourceInfo = dataSourceInfo; + this.taskId = taskId; + } + + /** + * Called by the data source processor when it finishes running in + * its own thread. + * + * @param result The result code for the processing of + * the data source. + * @param errorMessages Any error messages generated during the + * processing of the data source. + * @param dataSourceContent The content produced by processing the + * data source. + */ + @Override + public void done(DataSourceProcessorCallback.DataSourceProcessorResult result, List errorMessages, List dataSourceContent) { + if (!dataSourceContent.isEmpty()) { + caseForJob.notifyDataSourceAdded(dataSourceContent.get(0), taskId); + } else { + caseForJob.notifyFailedAddingDataSource(taskId); + } + dataSourceInfo.setDataSourceProcessorOutput(result, errorMessages, dataSourceContent); + dataSourceContent.addAll(dataSourceContent); + synchronized (ingestLock) { + ingestLock.notify(); + } + } + + /** + * Called by the data source processor when it finishes running in + * its own thread, if that thread is the AWT (Abstract Window + * Toolkit) event dispatch thread (EDT). + * + * @param result The result code for the processing of + * the data source. + * @param errorMessages Any error messages generated during the + * processing of the data source. + * @param dataSourceContent The content produced by processing the + * data source. + */ + @Override + public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List errorMessages, List dataSources) { + done(result, errorMessages, dataSources); + } + + } + /** * A data source processor progress monitor does nothing. There is * currently no mechanism for showing or recording data source processor @@ -2926,7 +3017,49 @@ public final class AutoIngestManager extends Observable implements PropertyChang PARTIALLY_DELETED, FULLY_DELETED } - + + @ThreadSafe + private static final class DataSource { + + private final String deviceId; + private final Path path; + private DataSourceProcessorResult resultCode; + private List errorMessages; + private List content; + + DataSource(String deviceId, Path path) { + this.deviceId = deviceId; + this.path = path; + } + + String getDeviceId() { + return deviceId; + } + + Path getPath() { + return this.path; + } + + synchronized void setDataSourceProcessorOutput(DataSourceProcessorResult result, List errorMessages, List content) { + this.resultCode = result; + this.errorMessages = new ArrayList<>(errorMessages); + this.content = new ArrayList<>(content); + } + + synchronized DataSourceProcessorResult getResultDataSourceProcessorResultCode() { + return resultCode; + } + + synchronized List getDataSourceProcessorErrorMessages() { + return new ArrayList<>(errorMessages); + } + + synchronized List getContent() { + return new ArrayList<>(content); + } + + } + static final class AutoIngestManagerException extends Exception { private static final long serialVersionUID = 1L; @@ -2941,4 +3074,4 @@ public final class AutoIngestManager extends Observable implements PropertyChang } -} +} \ No newline at end of file From 377075401ba73928d3ae7986681a440a270463db Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Wed, 1 Nov 2017 16:46:04 -0400 Subject: [PATCH 042/115] 3180: correct the typo --- ...{IntestFileFiltersTest.java => IngestFileFiltersTest.java} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename Core/test/unit/src/org/sleuthkit/autopsy/ingest/{IntestFileFiltersTest.java => IngestFileFiltersTest.java} (94%) diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/ingest/IntestFileFiltersTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java similarity index 94% rename from Core/test/unit/src/org/sleuthkit/autopsy/ingest/IntestFileFiltersTest.java rename to Core/test/unit/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java index b952462de8..29618e30ec 100755 --- a/Core/test/unit/src/org/sleuthkit/autopsy/ingest/IntestFileFiltersTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java @@ -23,9 +23,9 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -public class IntestFileFiltersTest { +public class IngestFileFiltersTest { - public IntestFileFiltersTest() { + public IngestFileFiltersTest() { } @BeforeClass From 536056f415b018924a35114b03f1adc1989ccd2a Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 1 Nov 2017 16:49:49 -0400 Subject: [PATCH 043/115] Removed unused import and variable. --- .../autopsy/experimental/autoingest/AutoIngestManager.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index 3f28487394..c169223396 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -61,7 +61,6 @@ import java.util.stream.Collectors; import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.ThreadSafe; -import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case.CaseType; @@ -122,7 +121,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang private static final int NUM_INPUT_SCAN_SCHEDULING_THREADS = 1; private static final String INPUT_SCAN_SCHEDULER_THREAD_NAME = "AIM-input-scan-scheduler-%d"; private static final String INPUT_SCAN_THREAD_NAME = "AIM-input-scan-%d"; - private static int DEFAULT_JOB_PRIORITY = 0; private static final String AUTO_INGEST_THREAD_NAME = "AIM-job-processing-%d"; private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName(); private static final String EVENT_CHANNEL_NAME = "Auto-Ingest-Manager-Events"; From bd32abf036b6a36d8efc19d2054ec211458a1ff0 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 2 Nov 2017 15:37:49 -0400 Subject: [PATCH 044/115] Added cancelation via Future --- .../autoingest/AddArchiveTask.java | 12 +++++------- .../ArchiveExtractorDSProcessor.java | 19 ++++++++++++++++--- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index 0b121c902c..add8617ae9 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -89,6 +89,8 @@ class AddArchiveTask implements Runnable { result = DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS; callback.done(result, errorMessages, newDataSources); } + + logger.log(Level.INFO, "Using Archive Extractor DSP to process archive {0} ", archivePath); // extract the archive and pass the extracted folder as input UUID taskId = UUID.randomUUID(); @@ -151,6 +153,7 @@ class AddArchiveTask implements Runnable { // identified a "valid" data source within the archive progressMonitor.setProgressText(String.format("Adding: %s", file)); + logger.log(Level.INFO, "Using {0} to process extracted file {1} ", new Object[]{selectedProcessor.getDataSourceType(), file}); /* * NOTE: we have to move the valid data sources to a @@ -204,6 +207,7 @@ class AddArchiveTask implements Runnable { // after all archive contents have been examined (and moved to separate folders if necessary), // add remaining extracted contents as one logical file set progressMonitor.setProgressText(String.format("Adding: %s", destinationFolder.toString())); + logger.log(Level.INFO, "Adding directory {0} as logical file set", destinationFolder.toString()); synchronized (archiveDspLock) { DataSource internalDataSource = new DataSource(deviceId, destinationFolder); DataSourceProcessorCallback internalArchiveDspCallBack = new AddDataSourceCallback(currentCase, internalDataSource, taskId, archiveDspLock); @@ -228,6 +232,7 @@ class AddArchiveTask implements Runnable { errorMessages.add(ex.getMessage()); logger.log(Level.SEVERE, String.format("Critical error occurred while extracting archive %s", archivePath), ex); //NON-NLS } finally { + logger.log(Level.INFO, "Finished processing of archive {0}", archivePath); progressMonitor.setProgress(100); if (criticalErrorOccurred) { result = DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS; @@ -252,11 +257,4 @@ class AddArchiveTask implements Runnable { } return newFolder; } - - /* - * Attempts to cancel adding the archive to the case database. - */ - public void cancelTask() { - // do a cancelation via future instead - } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java index 0123592593..0e75e4c200 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java @@ -18,9 +18,15 @@ */ package org.sleuthkit.autopsy.experimental.autoingest; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.nio.file.Path; import java.util.UUID; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; import javax.swing.JPanel; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProviders; @@ -50,6 +56,9 @@ public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIng private String archivePath; private boolean setDataSourceOptionsCalled; + private final ExecutorService jobProcessingExecutor; + private Future jobProcessingTaskFuture; + private static final String ARCHIVE_DSP_THREAD_NAME = "Archive-DSP-%d"; private AddArchiveTask addArchiveTask; /** @@ -60,6 +69,7 @@ public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIng */ public ArchiveExtractorDSProcessor() { configPanel = ArchiveFilePanel.createInstance(ArchiveExtractorDSProcessor.class.getName(), ArchiveUtil.getArchiveFilters()); + jobProcessingExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(ARCHIVE_DSP_THREAD_NAME).build()); } @Override @@ -151,7 +161,7 @@ public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIng */ public void run(String deviceId, String archivePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { addArchiveTask = new AddArchiveTask(deviceId, archivePath, progressMonitor, callback); - new Thread(addArchiveTask).start(); + jobProcessingTaskFuture = jobProcessingExecutor.submit(addArchiveTask); } /** @@ -163,8 +173,11 @@ public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIng */ @Override public void cancel() { - if (null != addArchiveTask) { - addArchiveTask.cancelTask(); + if (null != jobProcessingTaskFuture) { + jobProcessingTaskFuture.cancel(true); + jobProcessingExecutor.shutdownNow(); + // ELTBD - do we want to wait for the cancellation to complete? I think not, + // given that the cancelation is of "best effort" variety } } From cb3ebedf9cd2840a4ea52724eafe522bd897bf20 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 2 Nov 2017 15:38:12 -0400 Subject: [PATCH 045/115] Progress monitor and logging updates --- .../autopsy/experimental/autoingest/AddArchiveTask.java | 3 ++- .../experimental/autoingest/ArchiveExtractorDSProcessor.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index add8617ae9..98f36d6273 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -111,7 +111,8 @@ class AddArchiveTask implements Runnable { return; } - // extract contents of ZIP archive into destination folder + // extract contents of ZIP archive into destination folder + progressMonitor.setProgressText(String.format("Extracting archive contents to: %s", destinationFolder.toString())); List extractedFiles = ArchiveUtil.unpackArchiveFile(archivePath, destinationFolder.toString()); // do processing diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java index 0e75e4c200..dee9879dec 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java @@ -175,7 +175,7 @@ public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIng public void cancel() { if (null != jobProcessingTaskFuture) { jobProcessingTaskFuture.cancel(true); - jobProcessingExecutor.shutdownNow(); + jobProcessingExecutor.shutdown(); // ELTBD - do we want to wait for the cancellation to complete? I think not, // given that the cancelation is of "best effort" variety } From 17f8112f6642d87c8893dd8e41cb08ce70ff9c95 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 2 Nov 2017 17:35:01 -0400 Subject: [PATCH 046/115] Lots of optimizations and bug fixes --- .../autoingest/AddArchiveTask.java | 151 +++++++++++------- 1 file changed, 95 insertions(+), 56 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index 98f36d6273..b14255caff 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -22,16 +22,19 @@ import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.logging.Level; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; +import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.LocalDiskDSProcessor; import org.sleuthkit.autopsy.casemodule.LocalFilesDSProcessor; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; +import static org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; @@ -116,70 +119,45 @@ class AddArchiveTask implements Runnable { List extractedFiles = ArchiveUtil.unpackArchiveFile(archivePath, destinationFolder.toString()); // do processing - Map validDataSourceProcessorsMap; - for (String file : extractedFiles) { - - // identify DSP for this file - try { - // lookup all AutomatedIngestDataSourceProcessors and poll which ones are able to process the current data source - validDataSourceProcessorsMap = DataSourceProcessorUtility.getDataSourceProcessor(Paths.get(file)); - if (validDataSourceProcessorsMap.isEmpty()) { - continue; - } - } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) { - criticalErrorOccurred = true; - errorMessages.add(ex.getMessage()); - logger.log(Level.SEVERE, String.format("Critical error occurred while extracting archive %s", archivePath), ex); //NON-NLS - // continue to next extracted file + for (String file : extractedFiles) { + // identify all "valid" DSPs that can process this file + List validDataSourceProcessors = getValidDataSourceProcessors(Paths.get(file), errorMessages); + if (validDataSourceProcessors.isEmpty()) { continue; } - // Get an ordered list of data source processors to try - List validDataSourceProcessors = DataSourceProcessorUtility.orderDataSourceProcessorsByConfidence(validDataSourceProcessorsMap); + // identified a "valid" data source within the archive + progressMonitor.setProgressText(String.format("Adding: %s", file)); + + /* + * NOTE: we have to move the valid data sources to a separate + * folder and then add the data source from that folder. This is + * necessary because after all valid data sources have been + * identified, we are going to add the remaining extracted + * contents of the archive as a single logacl file set. Hence, + * if we do not move the data sources out of the extracted + * contents folder, those data source files will get added twice + * and can potentially result in duplicate keyword hits. + */ + Path newFolder = createDirectoryForFile(file, currentCase.getModuleDirectory()); + if (newFolder.toString().isEmpty()) { + // unable to create directory + criticalErrorOccurred = true; + errorMessages.add(String.format("Unable to create directory {0} to extract content of archive {1} ", new Object[]{newFolder.toString(), archivePath})); + logger.log(Level.SEVERE, String.format("Unable to create directory {0} to extract content of archive {1} ", new Object[]{newFolder.toString(), archivePath})); + return; + } + + // Copy it to a different folder + FileUtils.copyFileToDirectory(new File(file), newFolder.toFile()); + Path newFilePath = Paths.get(newFolder.toString(), FilenameUtils.getName(file)); // Try each DSP in decreasing order of confidence + boolean success = false; for (AutoIngestDataSourceProcessor selectedProcessor : validDataSourceProcessors) { - // skip local files and local disk DSPs, only looking for "valid" data sources - if (selectedProcessor instanceof LocalDiskDSProcessor) { - continue; - } - if (selectedProcessor instanceof LocalFilesDSProcessor) { - continue; - } - // also skip nested archive files, those will be ingested as logical files and extracted during ingest - if (selectedProcessor instanceof ArchiveExtractorDSProcessor) { - continue; - } - - // identified a "valid" data source within the archive - progressMonitor.setProgressText(String.format("Adding: %s", file)); logger.log(Level.INFO, "Using {0} to process extracted file {1} ", new Object[]{selectedProcessor.getDataSourceType(), file}); - /* - * NOTE: we have to move the valid data sources to a - * separate folder and then add the data source from that - * folder. This is necessary because after all valid data - * sources have been identified, we are going to add the - * remaining extracted contents of the archive as a single - * logacl file set. Hence, if we do not move the data - * sources out of the extracted contents folder, those data - * source files will get added twice and can potentially - * result in duplicate keyword hits. - */ - Path newFolder = createDirectoryForFile(file, currentCase.getModuleDirectory()); - if (newFolder.toString().isEmpty()) { - // unable to create directory - criticalErrorOccurred = true; - errorMessages.add(String.format("Unable to create directory {0} to extract content of archive {1} ", new Object[]{newFolder.toString(), archivePath})); - logger.log(Level.SEVERE, String.format("Unable to create directory {0} to extract content of archive {1} ", new Object[]{newFolder.toString(), archivePath})); - return; - } - - // Move it to a different folder - FileUtils.moveFileToDirectory(new File(file), newFolder.toFile(), false); - Path newFilePath = Paths.get(newFolder.toString(), FilenameUtils.getName(file)); - // ELTBD - do we want to log this in case log and/or system admin log? synchronized (archiveDspLock) { try { @@ -188,7 +166,16 @@ class AddArchiveTask implements Runnable { selectedProcessor.process(deviceId, newFilePath, progressMonitor, internalArchiveDspCallBack); archiveDspLock.wait(); - // at this point we got the content object(s) from the current DSP + // at this point we got the content object(s) from the current DSP. + // check whether the data source was processed successfully + if ((internalDataSource.getResultDataSourceProcessorResultCode() == CRITICAL_ERRORS) || + internalDataSource.getContent().isEmpty()) { + // move onto the the next DSP that can process this data source + continue; + } + + // if we are here it means the data source was addedd successfully + success = true; newDataSources.addAll(internalDataSource.getContent()); // skip all other DSPs for this data source @@ -203,6 +190,18 @@ class AddArchiveTask implements Runnable { } } } + + if (success) { + // one of the DSPs successfully processed the data source. delete the + // copy of the data source in the original extracted archive folder. + // otherwise the data source is going to be added again as a logical file. + FileUtils.deleteQuietly(Paths.get(file).toFile()); + } else { + // none of the DSPs were able to process the data source. delete the + // copy of the data source in the temporary folder. the data source is + // going to be added as a logical file with the rest of the extracted contents. + FileUtils.deleteQuietly(newFolder.toFile()); + } } // after all archive contents have been examined (and moved to separate folders if necessary), @@ -245,6 +244,46 @@ class AddArchiveTask implements Runnable { callback.done(result, errorMessages, newDataSources); } } + + + private List getValidDataSourceProcessors(Path dataSourcePath, List errorMessages) { + Map validDataSourceProcessorsMap; + try { + validDataSourceProcessorsMap = DataSourceProcessorUtility.getDataSourceProcessor(dataSourcePath); + } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) { + criticalErrorOccurred = true; + errorMessages.add(ex.getMessage()); + logger.log(Level.SEVERE, String.format("Critical error occurred while extracting archive %s", archivePath), ex); //NON-NLS + return Collections.emptyList(); + } + if (validDataSourceProcessorsMap.isEmpty()) { + return Collections.emptyList(); + } + + // Get an ordered list of data source processors to try + List validDataSourceProcessors = DataSourceProcessorUtility.orderDataSourceProcessorsByConfidence(validDataSourceProcessorsMap); + + for (AutoIngestDataSourceProcessor selectedProcessor : validDataSourceProcessors) { + + // skip local files and local disk DSPs, only looking for "valid" data sources + if (selectedProcessor instanceof LocalDiskDSProcessor) { + validDataSourceProcessors.remove(selectedProcessor); + continue; + } + if (selectedProcessor instanceof LocalFilesDSProcessor) { + validDataSourceProcessors.remove(selectedProcessor); + continue; + } + // also skip nested archive files, those will be ingested as logical files and extracted during ingest + if (selectedProcessor instanceof ArchiveExtractorDSProcessor) { + validDataSourceProcessors.remove(selectedProcessor); + continue; + } + } + + return validDataSourceProcessors; + } + private Path createDirectoryForFile(String fileName, String baseDirectory) { // get file name without full path or extension From 2ba9b1fa266f4ce64b919d4c928c28968bf13f98 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 3 Nov 2017 13:15:16 -0400 Subject: [PATCH 047/115] New generic status icon cell renderer. --- .../autopsy/casemodule/MultiUserCase.java | 285 ------------------ .../coreutils/CaseStatusIconCellRenderer.java | 58 ---- .../CenteredGrayableCellRenderer.java | 0 .../LongDateCellRenderer.java | 0 .../guiutils}/ShortDateCellRenderer.java | 0 .../autoingest/DurationCellRenderer.java | 98 ------ 6 files changed, 441 deletions(-) delete mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java delete mode 100755 Core/src/org/sleuthkit/autopsy/coreutils/CaseStatusIconCellRenderer.java rename {Experimental/src/org/sleuthkit/autopsy/experimental/autoingest => Core/src/org/sleuthkit/autopsy/guiutils}/CenteredGrayableCellRenderer.java (100%) rename Core/src/org/sleuthkit/autopsy/{coreutils => guiutils}/LongDateCellRenderer.java (100%) rename {Experimental/src/org/sleuthkit/autopsy/experimental/autoingest => Core/src/org/sleuthkit/autopsy/guiutils}/ShortDateCellRenderer.java (100%) delete mode 100755 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DurationCellRenderer.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java deleted file mode 100755 index e0bba29c43..0000000000 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015-2017 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.casemodule; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Comparator; -import java.util.Date; -import java.util.Objects; -import java.util.logging.Level; -import org.sleuthkit.autopsy.coreutils.Logger; - -/** - * A representation of a multi-user case. - */ -class MultiUserCase implements Comparable { - - private static final Logger logger = Logger.getLogger(MultiUserCase.class.getName()); - private final Path caseDirectoryPath; - private final String caseDisplayName; - private final String metadataFileName; - private final Date createDate; - private final Date lastAccessedDate; - - /** - * Constructs a representation of a multi-user case - * - * @param caseDirectoryPath The case directory path. - * - * @throws CaseMetadata.CaseMetadataException If the CaseMetadata object - * cannot be constructed for the - * case display name. - * @throws MultiUserCaseException If no case metadata (.aut) - * file is found in the case - * directory. - */ - MultiUserCase(Path caseDirectoryPath) throws CaseMetadata.CaseMetadataException, MultiUserCaseException { - CaseMetadata caseMetadata = null; - - try { - caseMetadata = getCaseMetadataFromCaseDirectoryPath(caseDirectoryPath); - } catch (CaseMetadata.CaseMetadataException ex) { - logger.log(Level.SEVERE, String.format("Error reading the case metadata for %s.", caseDirectoryPath), ex); - throw ex; - } - - this.caseDirectoryPath = caseDirectoryPath; - caseDisplayName = caseMetadata.getCaseDisplayName(); - metadataFileName = caseMetadata.getFilePath().getFileName().toString(); - BasicFileAttributes fileAttrs = null; - try { - fileAttrs = Files.readAttributes(Paths.get(caseDirectoryPath.toString(), metadataFileName), BasicFileAttributes.class); - } catch (IOException ex) { - logger.log(Level.SEVERE, String.format("Error reading file attributes of case metadata file in %s, will use current time for case createDate/lastModfiedDate", caseDirectoryPath), ex); - } - if (null != fileAttrs) { - createDate = new Date(fileAttrs.creationTime().toMillis()); - lastAccessedDate = new Date(fileAttrs.lastAccessTime().toMillis()); - } else { - createDate = new Date(); - lastAccessedDate = new Date(); - } - } - - /** - * Gets the case directory path. - * - * @return The case directory path. - */ - Path getCaseDirectoryPath() { - return this.caseDirectoryPath; - } - - /** - * Gets the case display name. This may differ from the name supplied to the - * directory or metadata file names if a case has been renamed. - * - * @return The case display name. - */ - String getCaseDisplayName() { - return this.caseDisplayName; - } - - /** - * Gets the creation date for the case, defined as the create time of the - * case metadata file. - * - * @return The case creation date. - */ - Date getCreationDate() { - return this.createDate; - } - - /** - * Gets the last accessed date for the case, defined as the last accessed - * time of the case metadata file. - * - * @return The last accessed date. - */ - Date getLastAccessedDate() { - return this.lastAccessedDate; - } - - /** - * Gets metadata (.aut) file name. - * - * @return The metadata file name. - */ - String getMetadataFileName() { - return this.metadataFileName; - } - - /** - * Gets the status of this case based on the auto ingest result file in the - * case directory. - * - * @return See CaseStatus enum definition. - */ - CaseStatus getStatus() { - if(caseDirectoryPath.resolve("autoingest.alert").toFile().exists()) { - return CaseStatus.ALERT; - } else { - return CaseStatus.OK; - } - } - - /** - * Gets the case metadata from a case directory path. - * - * @param caseDirectoryPath The case directory path. - * - * @return Case metadata. - * - * @throws CaseMetadata.CaseMetadataException If the CaseMetadata object - * cannot be constructed. - * @throws MultiUserCaseException If no case metadata (.aut) - * file is found in the case - * directory. - */ - private static CaseMetadata getCaseMetadataFromCaseDirectoryPath(Path caseDirectoryPath) throws CaseMetadata.CaseMetadataException, MultiUserCaseException { - CaseMetadata caseMetadata = null; - - File directory = new File(caseDirectoryPath.toString()); - if (directory.isDirectory()) { - File autFile = null; - - /* - * Attempt to find an AUT file via a directory scan. - */ - for (File file : directory.listFiles()) { - if (file.getName().toLowerCase().endsWith(CaseMetadata.getFileExtension()) && file.isFile()) { - autFile = file; - break; - } - } - - if(autFile == null || !autFile.isFile()) { - throw new MultiUserCaseException(String.format("No case metadata (.aut) file found in the case directory '%s'.", caseDirectoryPath.toString())); - } - - caseMetadata = new CaseMetadata(Paths.get(autFile.getAbsolutePath())); - } - - return caseMetadata; - } - - /** - * Indicates whether or not some other object is "equal to" this - * MultiUserCase object. - * - * @param other The other object. - * - * @return True or false. - */ - @Override - public boolean equals(Object other) { - if (!(other instanceof MultiUserCase)) { - return false; - } - if (other == this) { - return true; - } - return this.caseDirectoryPath.toString().equals(((MultiUserCase) other).caseDirectoryPath.toString()); - } - - /** - * Returns a hash code value for this MultiUserCase object. - * - * @return The has code. - */ - @Override - public int hashCode() { - int hash = 7; - hash = 71 * hash + Objects.hashCode(this.caseDirectoryPath); - hash = 71 * hash + Objects.hashCode(this.createDate); - hash = 71 * hash + Objects.hashCode(this.caseDisplayName); - return hash; - } - - /** - * Compares this MultiUserCase object with another MultiUserCase object - * for order. - */ - @Override - public int compareTo(MultiUserCase other) { - return -this.lastAccessedDate.compareTo(other.getLastAccessedDate()); - } - - /** - * Comparator for a descending order sort on date created. - */ - static class LastAccessedDateDescendingComparator implements Comparator { - - /** - * Compares two MultiUserCase objects for order based on last accessed - * date (descending). - * - * @param object The first MultiUserCase object - * @param otherObject The second MultiUserCase object. - * - * @return A negative integer, zero, or a positive integer as the first - * argument is less than, equal to, or greater than the second. - */ - @Override - public int compare(MultiUserCase object, MultiUserCase otherObject) { - return -object.getLastAccessedDate().compareTo(otherObject.getLastAccessedDate()); - } - } - - /** - * Exception thrown when there is a problem creating a multi-user case. - */ - final static class MultiUserCaseException extends Exception { - - private static final long serialVersionUID = 1L; - - /** - * Constructs an exception to throw when there is a problem creating a - * multi-user case. - * - * @param message The exception message. - */ - private MultiUserCaseException(String message) { - super(message); - } - - /** - * Constructs an exception to throw when there is a problem creating a - * multi-user case. - * - * @param message The exception message. - * @param cause The cause of the exception, if it was an exception. - */ - private MultiUserCaseException(String message, Throwable cause) { - super(message, cause); - } - } - - enum CaseStatus { - - OK, - ALERT - } - -} diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/CaseStatusIconCellRenderer.java b/Core/src/org/sleuthkit/autopsy/coreutils/CaseStatusIconCellRenderer.java deleted file mode 100755 index 4d782a6f57..0000000000 --- a/Core/src/org/sleuthkit/autopsy/coreutils/CaseStatusIconCellRenderer.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015-2017 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.coreutils; - -import java.awt.Component; -import javax.swing.ImageIcon; -import javax.swing.JTable; -import static javax.swing.SwingConstants.CENTER; -import org.openide.util.ImageUtilities; -import org.openide.util.NbBundle.Messages; - -/** - * A JTable cell renderer that represents an auto ingest alert file exists flag - * as a center-aligned icon, and grays out the cell if the table is disabled. - */ -public class CaseStatusIconCellRenderer extends GrayableCellRenderer { - - private static final long serialVersionUID = 1L; - static final ImageIcon checkedIcon = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/experimental/images/tick.png", false)); - static final ImageIcon warningIcon = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/experimental/images/warning16.png", false)); - - @Messages({ - "CaseStatusIconCellRenderer.tooltiptext.ok=Images processed successfully", - "CaseStatusIconCellRenderer.tooltiptext.warning=An error occurred or processing was canceled for at least one image - please check the log" - }) - @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - setHorizontalAlignment(CENTER); - if ((value instanceof Boolean)) { - if (true == (Boolean) value) { - setIcon(warningIcon); - setToolTipText(org.openide.util.NbBundle.getMessage(CaseStatusIconCellRenderer.class, "CaseStatusIconCellRenderer.tooltiptext.warning")); - } else { - setIcon(checkedIcon); - setToolTipText(org.openide.util.NbBundle.getMessage(CaseStatusIconCellRenderer.class, "CaseStatusIconCellRenderer.tooltiptext.ok")); - } - } - grayCellIfTableNotEnabled(table, isSelected); - - return this; - } -} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CenteredGrayableCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/CenteredGrayableCellRenderer.java similarity index 100% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CenteredGrayableCellRenderer.java rename to Core/src/org/sleuthkit/autopsy/guiutils/CenteredGrayableCellRenderer.java diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/LongDateCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/LongDateCellRenderer.java similarity index 100% rename from Core/src/org/sleuthkit/autopsy/coreutils/LongDateCellRenderer.java rename to Core/src/org/sleuthkit/autopsy/guiutils/LongDateCellRenderer.java diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ShortDateCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/ShortDateCellRenderer.java similarity index 100% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ShortDateCellRenderer.java rename to Core/src/org/sleuthkit/autopsy/guiutils/ShortDateCellRenderer.java diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DurationCellRenderer.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DurationCellRenderer.java deleted file mode 100755 index c61e363222..0000000000 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DurationCellRenderer.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015 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.experimental.autoingest; - -import java.awt.Color; -import java.awt.Component; -import java.time.Duration; -import javax.swing.JTable; -import static javax.swing.SwingConstants.CENTER; -import org.sleuthkit.autopsy.coreutils.GrayableCellRenderer; - -/** - * A JTable cell renderer that renders a duration represented as a long as a - * string with days, hours, minutes, and seconds components. It center-aligns - * cell content and grays out the cell if the table is disabled. - */ -class DurationCellRenderer extends GrayableCellRenderer { - - private static final long serialVersionUID = 1L; - - DurationCellRenderer() { - setHorizontalAlignment(CENTER); - } - - @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - if (value instanceof Long) { - { - Duration d = Duration.ofMillis((long) value); - if (d.isNegative()) { - d = Duration.ofMillis(-(long) value); - } - - String result; - long days = d.toDays(); - long hours = d.minusDays(days).toHours(); - long minutes = d.minusDays(days).minusHours(hours).toMinutes(); - long seconds = d.minusDays(days).minusHours(hours).minusMinutes(minutes).getSeconds(); - - if (minutes > 0) { - if (hours > 0) { - if (days > 0) { - result = days + " d " + hours + " h " + minutes + " m " + seconds + " s"; - } else { - result = hours + " h " + minutes + " m " + seconds + " s"; - } - } else { - result = minutes + " m " + seconds + " s"; - } - } else { - result = seconds + " s"; - } - - setText(result); - } - } - grayCellIfTableNotEnabled(table, isSelected); - return this; - } - - void grayCellIfTableNotEnabled(JTable table, boolean isSelected) { - if (table.isEnabled()) { - /* - * The table is enabled, make the foreground and background the - * normal selected or unselected color. - */ - if (isSelected) { - setBackground(table.getSelectionBackground()); - setForeground(table.getSelectionForeground()); - } else { - setBackground(table.getBackground()); - setForeground(table.getForeground()); - } - } else { - /* - * The table is disabled, make the foreground and background gray. - */ - setBackground(Color.lightGray); - setForeground(Color.darkGray); - } - } -} From b5526ecf838da0aff20c142b54b1a371287863a7 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 3 Nov 2017 14:54:20 -0400 Subject: [PATCH 048/115] Revisions to multi-user cases panel code. --- Core/nbproject/project.xml | 1 + .../autopsy/casemodule/Bundle.properties | 2 +- .../autopsy/casemodule/CaseDeleteAction.java | 9 +- .../casemodule/CaseOpenMultiUserAction.java | 17 +- .../autopsy/casemodule/CueBannerPanel.java | 12 +- .../casemodule/MultiUserCaseManager.java | 258 +++++++++++++++++- .../casemodule/MultiUserCasesDialog.java | 20 +- .../casemodule/MultiUserCasesPanel.java | 101 ++++--- .../autopsy/coreutils/TimeStampUtils.java | 22 +- .../CenteredGrayableCellRenderer.java | 3 +- .../guiutils/DurationCellRenderer.java | 97 +++++++ .../GrayableCellRenderer.java | 2 +- .../guiutils/LongDateCellRenderer.java | 2 +- .../guiutils/ShortDateCellRenderer.java | 3 +- .../guiutils/StatusIconCellRenderer.java | 74 +++++ .../src/org/sleuthkit/autopsy/images/tick.png | Bin 0 -> 582 bytes .../sleuthkit/autopsy/images/warning16.png | Bin 0 -> 552 bytes .../autoingest/AutoIngestControlPanel.java | 13 +- .../autoingest/AutoIngestDashboard.java | 9 +- .../autoingest/AutoIngestManager.java | 5 +- .../experimental/autoingest/Bundle.properties | 3 - .../autopsy/experimental/autoingest/layer.xml | 25 +- .../AutoIngestSettingsPanel.form | 4 - .../AutoIngestSettingsPanel.java | 2 - 24 files changed, 529 insertions(+), 155 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/guiutils/DurationCellRenderer.java rename Core/src/org/sleuthkit/autopsy/{coreutils => guiutils}/GrayableCellRenderer.java (98%) create mode 100755 Core/src/org/sleuthkit/autopsy/guiutils/StatusIconCellRenderer.java create mode 100755 Core/src/org/sleuthkit/autopsy/images/tick.png create mode 100755 Core/src/org/sleuthkit/autopsy/images/warning16.png diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 25e17dd3eb..993af4bf6e 100755 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -269,6 +269,7 @@ org.sleuthkit.autopsy.events org.sleuthkit.autopsy.externalresults org.sleuthkit.autopsy.filesearch + org.sleuthkit.autopsy.guiutils org.sleuthkit.autopsy.ingest org.sleuthkit.autopsy.keywordsearchservice org.sleuthkit.autopsy.menuactions diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 5b80fd80ba..60db8edaf8 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -4,7 +4,7 @@ CTL_CaseCloseAct=Close Case CTL_CaseNewAction=New Case CTL_CasePropertiesAction=Case Properties CTL_CaseDeleteAction=Delete Case -CTL_OpenAction=Open Case +CTL_CaseOpenAction=Open Case Menu/Case/OpenRecentCase=Open Recent Case CTL_CaseDeleteAction=Delete Case OpenIDE-Module-Name=Case diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java index b95ad78edf..66e983b1ce 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java @@ -44,12 +44,15 @@ import org.sleuthkit.autopsy.coreutils.Logger; final class CaseDeleteAction extends CallableSystemAction { private static final long serialVersionUID = 1L; - private static final Logger logger = Logger.getLogger(CaseDeleteAction.class.getName()); + private static final Logger LOGGER = Logger.getLogger(CaseDeleteAction.class.getName()); CaseDeleteAction() { putValue(Action.NAME, NbBundle.getMessage(CaseDeleteAction.class, "CTL_CaseDeleteAction")); this.setEnabled(false); Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> { + /* + * A value of 'null' signifies that there is no case open. + */ setEnabled(null != evt.getNewValue()); }); } @@ -92,7 +95,7 @@ final class CaseDeleteAction extends CallableSystemAction { try { get(); } catch (InterruptedException | ExecutionException ex) { - logger.log(Level.SEVERE, String.format("Failed to delete case %s at %s", caseName, caseDirectory), ex); + LOGGER.log(Level.SEVERE, String.format("Failed to delete case %s at %s", caseName, caseDirectory), ex); JOptionPane.showMessageDialog( null, Bundle.Case_deleteCaseFailureMessageBox_message(ex.getLocalizedMessage()), @@ -107,7 +110,7 @@ final class CaseDeleteAction extends CallableSystemAction { }.execute(); } } catch (IllegalStateException ex) { - logger.log(Level.SEVERE, "Case delete action called with no current case", ex); + LOGGER.log(Level.SEVERE, "Case delete action called with no current case", ex); } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java index 76607210c5..7a12b69cf7 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java @@ -18,13 +18,9 @@ */ package org.sleuthkit.autopsy.casemodule; -import java.awt.Dialog; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.event.KeyEvent; -import javax.swing.JComponent; import javax.swing.JDialog; -import javax.swing.KeyStroke; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; import org.openide.awt.ActionRegistration; @@ -33,7 +29,6 @@ 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.NetworkUtils; /** * The action associated with the Open Multi-User Case menu item via the @@ -51,16 +46,8 @@ public final class CaseOpenMultiUserAction extends CallableSystemAction implemen private static JDialog multiUserCaseWindow; private static final String DISPLAY_NAME = Bundle.CTL_CaseOpenMultiUserAction(); - private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName(); - private static final String REVIEW_MODE_TITLE = "Open Multi-User Case (" + LOCAL_HOST_NAME + ")"; public CaseOpenMultiUserAction() {} - - public static void closeMultiUserCasesWindow() { - if (null != multiUserCaseWindow) { - multiUserCaseWindow.setVisible(false); - } - } @Override public boolean isEnabled() { @@ -68,10 +55,10 @@ public final class CaseOpenMultiUserAction extends CallableSystemAction implemen } /** - * Pops up a case selection panel to allow the user to selecte a multi-user + * Pops up a case selection panel to allow the user to select a multi-user * case to open. * - * @param e The action event. + * @param event The action event. */ @Override public void actionPerformed(ActionEvent event) { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java index 24c714eb5b..2c81d100e4 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java @@ -38,13 +38,11 @@ import org.sleuthkit.autopsy.core.UserPreferences; public class CueBannerPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; - private static final String REVIEW_MODE_TITLE = "Open Multi-User Case"; /* * This is field is static for the sake of the closeOpenRecentCasesWindow * method. */ private static JDialog recentCasesWindow; - private static JDialog multiUserCaseWindow; public static void closeOpenRecentCasesWindow() { if (null != recentCasesWindow) { @@ -52,12 +50,6 @@ public class CueBannerPanel extends javax.swing.JPanel { } } - public static void closeMultiUserCasesWindow() { - if (null != multiUserCaseWindow) { - multiUserCaseWindow.setVisible(false); - } - } - public CueBannerPanel() { initComponents(); initRecentCasesWindow(); @@ -284,9 +276,7 @@ public class CueBannerPanel extends javax.swing.JPanel { }//GEN-LAST:event_openRecentCaseButtonActionPerformed private void openMultiUserCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openMultiUserCaseButtonActionPerformed - if(multiUserCaseWindow == null) { - multiUserCaseWindow = MultiUserCasesDialog.getInstance(); - } + MultiUserCasesDialog multiUserCaseWindow = MultiUserCasesDialog.getInstance(); multiUserCaseWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); multiUserCaseWindow.setVisible(true); }//GEN-LAST:event_openMultiUserCaseButtonActionPerformed diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java index 3101461443..d0baf94bc9 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java @@ -19,20 +19,29 @@ package org.sleuthkit.autopsy.casemodule; import java.io.File; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; +import java.util.Comparator; +import java.util.Date; import java.util.List; +import java.util.Objects; +import java.util.logging.Level; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; +import org.sleuthkit.autopsy.coreutils.Logger; /** * Handles locating and opening multi-user cases. */ final class MultiUserCaseManager { + private static final Logger LOGGER = Logger.getLogger(MultiUserCaseManager.class.getName()); + private static final String LOG_FILE_NAME = "auto_ingest_log.txt"; private static MultiUserCaseManager instance; - private CoordinationService coordinationService; /** @@ -79,9 +88,10 @@ final class MultiUserCaseManager { File[] autFiles = caseFolder.listFiles((dir, name) -> name.toLowerCase().endsWith(".aut")); if(autFiles != null && autFiles.length > 0) { try { - cases.add(new MultiUserCase(casePath)); + CaseMetadata caseMetadata = new CaseMetadata(Paths.get(autFiles[0].getAbsolutePath())); + cases.add(new MultiUserCase(casePath, caseMetadata)); } catch (CaseMetadata.CaseMetadataException | MultiUserCase.MultiUserCaseException ex) { - // Ignore and continue. + LOGGER.log(Level.SEVERE, String.format("Error reading case metadata file '%s'.", autFiles[0].getAbsolutePath()), ex); } } } @@ -133,4 +143,246 @@ final class MultiUserCaseManager { } } + + /** + * A representation of a multi-user case. + */ + static class MultiUserCase implements Comparable { + + private final Path caseDirectoryPath; + private final String caseDisplayName; + private final String metadataFileName; + private final Date createDate; + private final Date lastAccessedDate; + + /** + * Constructs a representation of a multi-user case + * + * @param caseDirectoryPath The case directory path. + * @param caseMetadata The case metadata. + * + * @throws MultiUserCaseException If no case metadata (.aut) + * file is found in the case + * directory. + */ + MultiUserCase(Path caseDirectoryPath, CaseMetadata caseMetadata) throws MultiUserCaseException { + this.caseDirectoryPath = caseDirectoryPath; + caseDisplayName = caseMetadata.getCaseDisplayName(); + metadataFileName = caseMetadata.getFilePath().getFileName().toString(); + BasicFileAttributes fileAttrs = null; + try { + fileAttrs = Files.readAttributes(Paths.get(caseDirectoryPath.toString(), metadataFileName), BasicFileAttributes.class); + } catch (IOException ex) { + LOGGER.log(Level.SEVERE, String.format("Error reading file attributes of case metadata file in %s, will use current time for case createDate/lastModfiedDate", caseDirectoryPath), ex); + } + if (null != fileAttrs) { + createDate = new Date(fileAttrs.creationTime().toMillis()); + lastAccessedDate = new Date(fileAttrs.lastAccessTime().toMillis()); + } else { + createDate = new Date(); + lastAccessedDate = new Date(); + } + } + + /** + * Gets the case directory path. + * + * @return The case directory path. + */ + Path getCaseDirectoryPath() { + return this.caseDirectoryPath; + } + + /** + * Gets the case display name. This may differ from the name supplied to the + * directory or metadata file names if a case has been renamed. + * + * @return The case display name. + */ + String getCaseDisplayName() { + return this.caseDisplayName; + } + + /** + * Gets the creation date for the case, defined as the create time of the + * case metadata file. + * + * @return The case creation date. + */ + Date getCreationDate() { + return this.createDate; + } + + /** + * Gets the last accessed date for the case, defined as the last accessed + * time of the case metadata file. + * + * @return The last accessed date. + */ + Date getLastAccessedDate() { + return this.lastAccessedDate; + } + + /** + * Gets metadata (.aut) file name. + * + * @return The metadata file name. + */ + String getMetadataFileName() { + return this.metadataFileName; + } + + /** + * Gets the status of this case based on the auto ingest result file in the + * case directory. + * + * @return See CaseStatus enum definition. + */ + CaseStatus getStatus() { + if(caseDirectoryPath.resolve("autoingest.alert").toFile().exists()) { + return CaseStatus.ALERT; + } else { + return CaseStatus.OK; + } + } + + /** + * Gets the case metadata from a case directory path. + * + * @param caseDirectoryPath The case directory path. + * + * @return Case metadata. + * + * @throws CaseMetadata.CaseMetadataException If the CaseMetadata object + * cannot be constructed. + * @throws MultiUserCaseException If no case metadata (.aut) + * file is found in the case + * directory. + */ + private CaseMetadata getCaseMetadataFromCaseDirectoryPath(Path caseDirectoryPath) throws CaseMetadata.CaseMetadataException, MultiUserCaseException { + CaseMetadata caseMetadata = null; + + File directory = new File(caseDirectoryPath.toString()); + if (directory.isDirectory()) { + File autFile = null; + + /* + * Attempt to find an AUT file via a directory scan. + */ + for (File file : directory.listFiles()) { + if (file.getName().toLowerCase().endsWith(CaseMetadata.getFileExtension()) && file.isFile()) { + autFile = file; + break; + } + } + + if(autFile == null || !autFile.isFile()) { + throw new MultiUserCaseException(String.format("No case metadata (.aut) file found in the case directory '%s'.", caseDirectoryPath.toString())); + } + + caseMetadata = new CaseMetadata(Paths.get(autFile.getAbsolutePath())); + } + + return caseMetadata; + } + + /** + * Indicates whether or not some other object is "equal to" this + * MultiUserCase object. + * + * @param other The other object. + * + * @return True or false. + */ + @Override + public boolean equals(Object other) { + if (!(other instanceof MultiUserCase)) { + return false; + } + if (other == this) { + return true; + } + return this.caseDirectoryPath.toString().equals(((MultiUserCase) other).caseDirectoryPath.toString()); + } + + /** + * Returns a hash code value for this MultiUserCase object. + * + * @return The has code. + */ + @Override + public int hashCode() { + int hash = 7; + hash = 71 * hash + Objects.hashCode(this.caseDirectoryPath); + hash = 71 * hash + Objects.hashCode(this.createDate); + hash = 71 * hash + Objects.hashCode(this.caseDisplayName); + return hash; + } + + /** + * Compares this MultiUserCase object with another MultiUserCase object + * for order. + */ + @Override + public int compareTo(MultiUserCase other) { + return -this.lastAccessedDate.compareTo(other.getLastAccessedDate()); + } + + /** + * Comparator for a descending order sort on date created. + */ + static class LastAccessedDateDescendingComparator implements Comparator { + + /** + * Compares two MultiUserCase objects for order based on last accessed + * date (descending). + * + * @param object The first MultiUserCase object + * @param otherObject The second MultiUserCase object. + * + * @return A negative integer, zero, or a positive integer as the first + * argument is less than, equal to, or greater than the second. + */ + @Override + public int compare(MultiUserCase object, MultiUserCase otherObject) { + return -object.getLastAccessedDate().compareTo(otherObject.getLastAccessedDate()); + } + } + + /** + * Exception thrown when there is a problem creating a multi-user case. + */ + final class MultiUserCaseException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructs an exception to throw when there is a problem creating a + * multi-user case. + * + * @param message The exception message. + */ + private MultiUserCaseException(String message) { + super(message); + } + + /** + * Constructs an exception to throw when there is a problem creating a + * multi-user case. + * + * @param message The exception message. + * @param cause The cause of the exception, if it was an exception. + */ + private MultiUserCaseException(String message, Throwable cause) { + super(message, cause); + } + } + + } + + static enum CaseStatus { + OK, + ALERT + } + } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesDialog.java index b6d9feeb7e..8c90aeccb4 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesDialog.java @@ -28,9 +28,11 @@ import org.openide.windows.WindowManager; /** * This class extends a JDialog and maintains the MultiUserCasesPanel. */ -public class MultiUserCasesDialog extends JDialog { +final class MultiUserCasesDialog extends JDialog { + + private static final long serialVersionUID = 1L; private static final String REVIEW_MODE_TITLE = "Open Multi-User Case"; - private final MultiUserCasesPanel multiUserCasesPanel; + private static MultiUserCasesPanel multiUserCasesPanel; private static MultiUserCasesDialog instance; /** @@ -41,6 +43,7 @@ public class MultiUserCasesDialog extends JDialog { static public MultiUserCasesDialog getInstance() { if(instance == null) { instance = new MultiUserCasesDialog(); + instance.init(); } return instance; } @@ -48,18 +51,23 @@ public class MultiUserCasesDialog extends JDialog { /** * Constructs a MultiUserCasesDialog object. */ - MultiUserCasesDialog() { + private MultiUserCasesDialog() { super(WindowManager.getDefault().getMainWindow(), REVIEW_MODE_TITLE, Dialog.ModalityType.APPLICATION_MODAL); - + } + + /** + * Initializes the multi-user cases panel. + */ + private void init() { getRootPane().registerKeyboardAction( e -> { setVisible(false); }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); - multiUserCasesPanel = new MultiUserCasesPanel(); + multiUserCasesPanel = new MultiUserCasesPanel(this); add(multiUserCasesPanel); pack(); setResizable(false); @@ -74,7 +82,7 @@ public class MultiUserCasesDialog extends JDialog { @Override public void setVisible(boolean value) { if(value) { - multiUserCasesPanel.refreshCasesTable(); + multiUserCasesPanel.refresh(); } super.setVisible(value); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java index 42201e5850..133d3e2671 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java @@ -20,35 +20,34 @@ package org.sleuthkit.autopsy.casemodule; import java.awt.Cursor; import java.awt.Desktop; -import java.awt.EventQueue; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Date; import java.util.List; -import java.util.concurrent.ExecutionException; import java.util.logging.Level; +import javax.swing.JDialog; import javax.swing.JOptionPane; -import javax.swing.SwingUtilities; -import javax.swing.SwingWorker; import javax.swing.event.ListSelectionEvent; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableColumn; -import org.sleuthkit.autopsy.coreutils.CaseStatusIconCellRenderer; -import org.sleuthkit.autopsy.coreutils.GrayableCellRenderer; +import org.sleuthkit.autopsy.casemodule.MultiUserCaseManager.MultiUserCase; +import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.LongDateCellRenderer; +import org.sleuthkit.autopsy.guiutils.LongDateCellRenderer; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.guiutils.GrayableCellRenderer; +import org.sleuthkit.autopsy.guiutils.StatusIconCellRenderer; /** * A panel that allows a user to open cases created by auto ingest. */ -public class MultiUserCasesPanel extends javax.swing.JPanel { +final class MultiUserCasesPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; private static final Logger LOGGER = Logger.getLogger(MultiUserCasesPanel.class.getName()); private static final String LOG_FILE_NAME = "auto_ingest_log.txt"; - private static final MultiUserCase.LastAccessedDateDescendingComparator REVERSE_DATE_MODIFIED_COMPARATOR = new MultiUserCase.LastAccessedDateDescendingComparator(); + private static final MultiUserCaseManager.MultiUserCase.LastAccessedDateDescendingComparator REVERSE_DATE_MODIFIED_COMPARATOR = new MultiUserCaseManager.MultiUserCase.LastAccessedDateDescendingComparator(); private static final int CASE_COL_MIN_WIDTH = 30; private static final int CASE_COL_MAX_WIDTH = 2000; private static final int CASE_COL_PREFERRED_WIDTH = 300; @@ -85,12 +84,14 @@ public class MultiUserCasesPanel extends javax.swing.JPanel { private final String[] columnNames = {CASE_HEADER, CREATEDTIME_HEADER, COMPLETEDTIME_HEADER, STATUS_ICON_HEADER, OUTPUT_FOLDER_HEADER, METADATA_FILE_HEADER}; private DefaultTableModel caseTableModel; private Path currentlySelectedCase = null; + private JDialog parentDialog; /** * Constructs a panel that allows a user to open cases created by automated * ingest. */ - MultiUserCasesPanel() { + MultiUserCasesPanel(JDialog parentDialog) { + this.parentDialog = parentDialog; caseTableModel = new DefaultTableModel(columnNames, 0) { private static final long serialVersionUID = 1L; @@ -137,7 +138,7 @@ public class MultiUserCasesPanel extends javax.swing.JPanel { theColumn.setWidth(TIME_COL_PREFERRED_WIDTH); theColumn = casesTable.getColumn(STATUS_ICON_HEADER); - theColumn.setCellRenderer(new CaseStatusIconCellRenderer()); + theColumn.setCellRenderer(new StatusIconCellRenderer()); theColumn.setMinWidth(STATUS_COL_MIN_WIDTH); theColumn.setMaxWidth(STATUS_COL_MAX_WIDTH); theColumn.setPreferredWidth(STATUS_COL_PREFERRED_WIDTH); @@ -163,42 +164,33 @@ public class MultiUserCasesPanel extends javax.swing.JPanel { * Gets the list of cases known to the review mode cases manager and * refreshes the cases table. */ - void refreshCasesTable() { - EventQueue.invokeLater(() -> { - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - }); - - synchronized(this) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - try { - currentlySelectedCase = getSelectedCase(); - MultiUserCaseManager manager = MultiUserCaseManager.getInstance(); - List cases = manager.getCases(); - cases.sort(REVERSE_DATE_MODIFIED_COMPARATOR); - caseTableModel.setRowCount(0); - long now = new Date().getTime(); - for (MultiUserCase autoIngestCase : cases) { - if (passesTimeFilter(now, autoIngestCase.getLastAccessedDate().getTime())) { - caseTableModel.addRow(new Object[]{ - autoIngestCase.getCaseDisplayName(), - autoIngestCase.getCreationDate(), - autoIngestCase.getLastAccessedDate(), - (MultiUserCase.CaseStatus.OK != autoIngestCase.getStatus()), - autoIngestCase.getCaseDirectoryPath().toString(), - autoIngestCase.getMetadataFileName()}); - } - } - setSelectedCase(currentlySelectedCase); - setButtons(); - } catch (Exception ex) { - LOGGER.log(Level.SEVERE, "Unexpected exception while refreshing the table.", ex); //NON-NLS - } finally { - setCursor(null); - } + void refresh() { + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + try { + currentlySelectedCase = getSelectedCase(); + MultiUserCaseManager manager = MultiUserCaseManager.getInstance(); + List cases = manager.getCases(); + cases.sort(REVERSE_DATE_MODIFIED_COMPARATOR); + caseTableModel.setRowCount(0); + long now = new Date().getTime(); + for (MultiUserCase autoIngestCase : cases) { + if (passesTimeFilter(now, autoIngestCase.getLastAccessedDate().getTime())) { + caseTableModel.addRow(new Object[]{ + autoIngestCase.getCaseDisplayName(), + autoIngestCase.getCreationDate(), + autoIngestCase.getLastAccessedDate(), + (MultiUserCaseManager.CaseStatus.OK != autoIngestCase.getStatus()) ? StatusIconCellRenderer.Status.WARNING : StatusIconCellRenderer.Status.OK, + autoIngestCase.getCaseDirectoryPath().toString(), + autoIngestCase.getMetadataFileName()}); } - }); + } + setSelectedCase(currentlySelectedCase); + setButtons(); + } catch (MultiUserCaseManager.MultiUserCaseManagerException | CoordinationService.CoordinationServiceException ex) { + LOGGER.log(Level.SEVERE, "Unexpected exception while refreshing the table.", ex); //NON-NLS + } finally { + setCursor(null); } } @@ -282,8 +274,9 @@ public class MultiUserCasesPanel extends javax.swing.JPanel { setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); try { StartupWindowProvider.getInstance().close(); - CueBannerPanel.closeMultiUserCasesWindow(); - CaseOpenMultiUserAction.closeMultiUserCasesWindow(); + if (parentDialog != null) { + parentDialog.setVisible(false); + } MultiUserCaseManager.getInstance().openCase(caseMetadataFilePath); } catch (CaseActionException | MultiUserCaseManager.MultiUserCaseManagerException ex) { if (null != ex.getCause() && !(ex.getCause() instanceof CaseActionCancelledException)) { @@ -491,7 +484,7 @@ public class MultiUserCasesPanel extends javax.swing.JPanel { int modelRow = casesTable.convertRowIndexToModel(casesTable.getSelectedRow()); String caseDirectory = (String) caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.OUTPUTFOLDER.ordinal()); Path caseMetadataFilePath = Paths.get(caseDirectory, (String) caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.METADATA_FILE.ordinal())); - + new Thread(() -> { openCase(caseMetadataFilePath); }).start(); @@ -503,30 +496,30 @@ public class MultiUserCasesPanel extends javax.swing.JPanel { * @param evt -- The event that caused this to be called */ private void bnRefreshActionPerformed(java.awt.event.ActionEvent evt) { - refreshCasesTable(); + refresh(); } private void rbDaysItemStateChanged(java.awt.event.ItemEvent evt) { if (rbDays.isSelected()) { - refreshCasesTable(); + refresh(); } } private void rbAllCasesItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbAllCasesItemStateChanged if (rbAllCases.isSelected()) { - refreshCasesTable(); + refresh(); } }//GEN-LAST:event_rbAllCasesItemStateChanged private void rbMonthsItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbMonthsItemStateChanged if (rbMonths.isSelected()) { - refreshCasesTable(); + refresh(); } }//GEN-LAST:event_rbMonthsItemStateChanged private void rbWeeksItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbWeeksItemStateChanged if (rbWeeks.isSelected()) { - refreshCasesTable(); + refresh(); } }//GEN-LAST:event_rbWeeksItemStateChanged diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/TimeStampUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/TimeStampUtils.java index 4b22a6010d..e14b5c5897 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/TimeStampUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/TimeStampUtils.java @@ -24,32 +24,32 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; /** - * Utility methods for working with strings with the time-stamp suffixes used by - * auto ingest. + * Utility methods for working with time stamps of the form + * 'yyyy_MM_dd_HH_mm_ss'. */ public final class TimeStampUtils { /* * Sample time stamp suffix: 2015_02_02_12_10_31 */ - private static final Pattern timeStampPattern = Pattern.compile("\\d{4}_\\d{2}_\\d{2}_\\d{2}_\\d{2}_\\d{2}$"); + private static final Pattern TIME_STAMP_PATTERN = Pattern.compile("\\d{4}_\\d{2}_\\d{2}_\\d{2}_\\d{2}_\\d{2}$"); private static final int LENGTH_OF_DATE_TIME_STAMP = 20; // length of the above time stamp - private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss"); + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss"); /** - * Checks whether a string ends with an auto ingest time stamp. + * Checks whether a string ends with a time stamp. * * @param inputString The string to check. * * @return True or false. */ public static boolean endsWithTimeStamp(String inputString) { - Matcher m = timeStampPattern.matcher(inputString); + Matcher m = TIME_STAMP_PATTERN.matcher(inputString); return m.find(); } /** - * Gets the fixed length of the auto-ingest time stamp suffix. + * Gets the fixed length of the time stamp suffix. * * @return The length. */ @@ -58,16 +58,16 @@ public final class TimeStampUtils { } /** - * Creates an auto ingest time stamp suffix using the current time. + * Creates a time stamp suffix using the current time. * * @return The suffix. */ public static String createTimeStamp() { - return dateFormat.format(Calendar.getInstance().getTime()); + return DATE_FORMAT.format(Calendar.getInstance().getTime()); } /** - * Removes an auto ingest timestamp suffix, if it present. + * Removes the time stamp suffix from a string, if present. * * @param inputString The string to trim. * @@ -82,7 +82,7 @@ public final class TimeStampUtils { } /** - * Gets the auto ingest time stamp suffix from a string, if it is present. + * Gets the time stamp suffix from a string, if present. * * @param inputString the name to check for a timestamp * diff --git a/Core/src/org/sleuthkit/autopsy/guiutils/CenteredGrayableCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/CenteredGrayableCellRenderer.java index 04422cd63a..af37f3f2e3 100755 --- a/Core/src/org/sleuthkit/autopsy/guiutils/CenteredGrayableCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/guiutils/CenteredGrayableCellRenderer.java @@ -16,10 +16,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.guiutils; import static javax.swing.SwingConstants.CENTER; -import org.sleuthkit.autopsy.coreutils.GrayableCellRenderer; /** * A JTable cell renderer that center-aligns cell content and grays out the cell diff --git a/Core/src/org/sleuthkit/autopsy/guiutils/DurationCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/DurationCellRenderer.java new file mode 100755 index 0000000000..970dafacfc --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/guiutils/DurationCellRenderer.java @@ -0,0 +1,97 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015-2017 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.guiutils; + +import java.awt.Color; +import java.awt.Component; +import java.time.Duration; +import javax.swing.JTable; +import static javax.swing.SwingConstants.CENTER; + +/** + * A JTable cell renderer that renders a duration represented as a long as a + * string with days, hours, minutes, and seconds components. It center-aligns + * cell content and grays out the cell if the table is disabled. + */ +public class DurationCellRenderer extends GrayableCellRenderer { + + private static final long serialVersionUID = 1L; + + public DurationCellRenderer() { + setHorizontalAlignment(CENTER); + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + if (value instanceof Long) { + { + Duration d = Duration.ofMillis((long) value); + if (d.isNegative()) { + d = Duration.ofMillis(-(long) value); + } + + String result; + long days = d.toDays(); + long hours = d.minusDays(days).toHours(); + long minutes = d.minusDays(days).minusHours(hours).toMinutes(); + long seconds = d.minusDays(days).minusHours(hours).minusMinutes(minutes).getSeconds(); + + if (minutes > 0) { + if (hours > 0) { + if (days > 0) { + result = days + " d " + hours + " h " + minutes + " m " + seconds + " s"; + } else { + result = hours + " h " + minutes + " m " + seconds + " s"; + } + } else { + result = minutes + " m " + seconds + " s"; + } + } else { + result = seconds + " s"; + } + + setText(result); + } + } + grayCellIfTableNotEnabled(table, isSelected); + return this; + } + + void grayCellIfTableNotEnabled(JTable table, boolean isSelected) { + if (table.isEnabled()) { + /* + * The table is enabled, make the foreground and background the + * normal selected or unselected color. + */ + if (isSelected) { + setBackground(table.getSelectionBackground()); + setForeground(table.getSelectionForeground()); + } else { + setBackground(table.getBackground()); + setForeground(table.getForeground()); + } + } else { + /* + * The table is disabled, make the foreground and background gray. + */ + setBackground(Color.lightGray); + setForeground(Color.darkGray); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/GrayableCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/GrayableCellRenderer.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/coreutils/GrayableCellRenderer.java rename to Core/src/org/sleuthkit/autopsy/guiutils/GrayableCellRenderer.java index 479f30bee2..53031faae3 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/GrayableCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/guiutils/GrayableCellRenderer.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.coreutils; +package org.sleuthkit.autopsy.guiutils; import java.awt.Color; import java.awt.Component; diff --git a/Core/src/org/sleuthkit/autopsy/guiutils/LongDateCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/LongDateCellRenderer.java index e347b2d28a..373e4e2501 100755 --- a/Core/src/org/sleuthkit/autopsy/guiutils/LongDateCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/guiutils/LongDateCellRenderer.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.coreutils; +package org.sleuthkit.autopsy.guiutils; import java.awt.Component; import java.text.SimpleDateFormat; diff --git a/Core/src/org/sleuthkit/autopsy/guiutils/ShortDateCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/ShortDateCellRenderer.java index f2670fa1b7..299880f1c0 100755 --- a/Core/src/org/sleuthkit/autopsy/guiutils/ShortDateCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/guiutils/ShortDateCellRenderer.java @@ -16,14 +16,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.guiutils; import java.awt.Color; import java.awt.Component; import java.text.SimpleDateFormat; import javax.swing.JTable; import static javax.swing.SwingConstants.CENTER; -import org.sleuthkit.autopsy.coreutils.GrayableCellRenderer; /** * A JTable cell renderer that renders a date represented as a long as a diff --git a/Core/src/org/sleuthkit/autopsy/guiutils/StatusIconCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/StatusIconCellRenderer.java new file mode 100755 index 0000000000..b7ee58e4d4 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/guiutils/StatusIconCellRenderer.java @@ -0,0 +1,74 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015-2017 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.guiutils; + +import java.awt.Component; +import javax.swing.ImageIcon; +import javax.swing.JTable; +import static javax.swing.SwingConstants.CENTER; +import org.openide.util.ImageUtilities; +import org.openide.util.NbBundle.Messages; + +/** + * A JTable cell renderer that represents a status as a center-aligned icon, and + * grays out the cell if the table is disabled. The statuses represented are OK, + * WARNING, and ERROR. + */ +public class StatusIconCellRenderer extends GrayableCellRenderer { + + private static final long serialVersionUID = 1L; + static final ImageIcon OK_ICON = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/images/tick.png", false)); + static final ImageIcon WARNING_ICON = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/images/warning16.png", false)); + static final ImageIcon ERROR_ICON = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/images/cross-script.png", false)); + + @Messages({ + "StatusIconCellRenderer.tooltiptext.ok=OK", + "StatusIconCellRenderer.tooltiptext.warning=A warning occurred", + "StatusIconCellRenderer.tooltiptext.error=An error occurred" + }) + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + setHorizontalAlignment(CENTER); + if ((value instanceof Status)) { + switch((Status) value) { + case OK: + setIcon(OK_ICON); + setToolTipText(org.openide.util.NbBundle.getMessage(StatusIconCellRenderer.class, "StatusIconCellRenderer.tooltiptext.ok")); + break; + case WARNING: + setIcon(WARNING_ICON); + setToolTipText(org.openide.util.NbBundle.getMessage(StatusIconCellRenderer.class, "StatusIconCellRenderer.tooltiptext.warning")); + break; + case ERROR: + setIcon(ERROR_ICON); + setToolTipText(org.openide.util.NbBundle.getMessage(StatusIconCellRenderer.class, "StatusIconCellRenderer.tooltiptext.error")); + break; + } + } + grayCellIfTableNotEnabled(table, isSelected); + + return this; + } + + public enum Status { + OK, + WARNING, + ERROR + } +} diff --git a/Core/src/org/sleuthkit/autopsy/images/tick.png b/Core/src/org/sleuthkit/autopsy/images/tick.png new file mode 100755 index 0000000000000000000000000000000000000000..a7d7a96be3f2282a62e3c0733bac89c7f6de7b4a GIT binary patch literal 582 zcmV-M0=fN(P)tYd4K$mX5uyr2F@fdffp{&DSHtl4|Bn9=ukpCx`#%PTUr-D(@b7;C zhJXJjrnw{;1KBM=6&|E`fsNrGL!Y6%zUh}QUl`(@V)PmQFtotEKmafTHP0uP}7&%m4pcKQ#X)BiAJ2y+PrtBI>9eEIt2-_c7)?*Lsf z5vX5*Af@m-wBJRV%#Fiz=BdPr0!2^az8K(fJ0K@xl?-_o)`1bna-SH57SeZUButL)d$cI_) zkpl5Q!w#U+YtHUCagF&eebP3jhEB literal 0 HcmV?d00001 diff --git a/Core/src/org/sleuthkit/autopsy/images/warning16.png b/Core/src/org/sleuthkit/autopsy/images/warning16.png new file mode 100755 index 0000000000000000000000000000000000000000..f5ba881738ae3072e476f3ddbd7dd34d642f06d6 GIT binary patch literal 552 zcmV+@0@wYCP)A&a_P7S}o zG!s6}jEu~GKp4p&41mvo3NbA|1~KhGFq>2ZZB(et$g5@cY9-1{tFW22MeRe4v~wF$QERIaM<- z{{O*nd`23>@mYBc|Np&XP;x8-%MmglnP1j4N=(g;;pf|paKWFi*D(ky8Zq$8n1Dhw z4W9v-%1)IGf4<*f`2Xh#iNdNA(_lT4EX==BZIP28N-#eIhh~>reEIz qPU=w%q=BsSelect this box if a low-band CopyFilesPanel.bnShowCurrentLog.text=Show &Log CopyFilesPanel.bnShowCurrentLog.text=Show &Log CopyFilesPanel.lbCaseName.text=Case Name -CaseStatusIconCellRenderer.tooltiptext.ok=Images processed successfully -CaseStatusIconCellRenderer.tooltiptext.warning=An error occurred or processing was canceled for at least one image - please check the log OptionsCategory_Name_Case_Import=Case Import OptionsCategory_Keywords_Case_Import=Case Import Settings CaseImportPanel.validationErrMsg.MUdisabled=Multi user settings must be enabled and saved diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/layer.xml b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/layer.xml index 56ad444eb0..ced44d8569 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/layer.xml +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/layer.xml @@ -2,20 +2,6 @@ - - - - - - - - - - - - @@ -23,19 +9,12 @@ - - - - - - - - + - + diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.form b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.form index 9965d1ad8f..68002e8055 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.form @@ -1,10 +1,6 @@
- - - - diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java index 892a27aab6..0d449fdb02 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java @@ -583,7 +583,6 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { // //GEN-BEGIN:initComponents private void initComponents() { - modeRadioButtons = new javax.swing.ButtonGroup(); nodeScrollPane = new javax.swing.JScrollPane(); nodePanel = new javax.swing.JPanel(); cbJoinAutoIngestCluster = new javax.swing.JCheckBox(); @@ -1211,7 +1210,6 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { private javax.swing.JLabel jLabelSelectOutputFolder; private javax.swing.JLabel jLabelTaskDescription; private javax.swing.JCheckBox masterNodeCheckBox; - private javax.swing.ButtonGroup modeRadioButtons; private javax.swing.JPanel nodePanel; private javax.swing.JScrollPane nodeScrollPane; private javax.swing.JTextField outputPathTextField; From a9b8f04f359ea9e75ac8b13b697953a5180432cb Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 3 Nov 2017 14:57:33 -0400 Subject: [PATCH 049/115] CaseDetails method change --- .../autopsy/experimental/autoingest/AutoIngestManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index b2ca78cda1..b621cb514f 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -2115,7 +2115,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang Case.openAsCurrentCase(metadataFilePath.toString()); } else { caseDirectoryPath = PathUtils.createCaseFolderPath(rootOutputDirectory, caseName); - CaseDetails caseDetails = new CaseDetails(caseName, "", "", "", "", ""); //DLG: Update this. + CaseDetails caseDetails = new CaseDetails(caseName); Case.createAsCurrentCase(CaseType.MULTI_USER_CASE, caseDirectoryPath.toString(), caseDetails); /* * Sleep a bit before releasing the lock to ensure From 0dfdcf9f1c9a60fee59868640e7e9a18280b3475 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 3 Nov 2017 15:10:14 -0400 Subject: [PATCH 050/115] Auto ingest metrics feature --- .../autopsy/casemodule/CaseDeleteAction.java | 3 +- .../autopsy/casemodule/CaseMetadata.java | 11 + .../casemodule/CaseOpenMultiUserAction.java | 36 +- .../autopsy/casemodule/CueBannerPanel.java | 23 +- .../autopsy/casemodule/MultiUserCase.java | 114 +++- .../casemodule/MultiUserCaseManager.java | 4 + .../casemodule/MultiUserCasePanel.form | 230 ------- .../casemodule/MultiUserCasePanel.java | 562 ------------------ .../datamodel/AbstractSqlEamDb.java | 0 .../centralrepository/datamodel/EamDb.java | 0 .../datamodel/SqliteEamDb.java | 0 .../eventlisteners/CaseEventListener.java | 0 .../eventlisteners/IngestEventsListener.java | 0 .../ingestmodule/IngestModule.java | 0 .../autopsy/core/UserPreferences.java | 4 +- .../sleuthkit/autopsy/core/timelineWsmode.xml | 0 .../autopsy/corecomponents/Installer.java | 19 + .../FileSystemDetailsAction.java | 0 .../autoingest/AutoIngestCaseOpenAction.java | 1 - .../autoingest/AutoIngestDashboard.form | 33 +- .../autoingest/AutoIngestDashboard.java | 46 +- .../AutoIngestDashboardOpenAction.java | 1 - .../autoingest/AutoIngestMonitor.java | 107 +++- .../experimental/autoingest/Bundle.properties | 5 + .../autoingest/CaseImportPanel.java | 1 - .../autoingest/dashboardWsmode.xml | 0 .../imagegallery/ImageGalleryWsmode.xml | 0 .../sleuthkit/autopsy/imagegallery/layer.xml | 0 .../keywordsearch/CreditCardValidator.java | 0 .../CreditCardValidatorTest.java | 0 docs/doxygen-user/central_repo.dox | 0 .../images/central_repo_content_viewer.png | Bin .../images/central_repo_interesting_items.png | Bin .../images/central_repo_manage_tags.png | Bin .../images/central_repo_options.png | Bin .../images/central_repo_postgres.png | Bin .../images/central_repo_sqlite.png | Bin .../images/central_repo_tag_file.png | Bin .../images/central_repo_types.png | Bin .../images/email_datasource_tree.png | Bin .../images/messages_datasource_tree.png | Bin ruleset.xml | 0 42 files changed, 312 insertions(+), 888 deletions(-) delete mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasePanel.form delete mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasePanel.java mode change 100644 => 100755 Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java mode change 100644 => 100755 Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java mode change 100644 => 100755 Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java mode change 100644 => 100755 Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java mode change 100644 => 100755 Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java mode change 100644 => 100755 Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java mode change 100644 => 100755 Core/src/org/sleuthkit/autopsy/core/timelineWsmode.xml mode change 100644 => 100755 Core/src/org/sleuthkit/autopsy/directorytree/FileSystemDetailsAction.java mode change 100644 => 100755 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/dashboardWsmode.xml mode change 100644 => 100755 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryWsmode.xml mode change 100644 => 100755 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/layer.xml mode change 100644 => 100755 KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/CreditCardValidator.java mode change 100644 => 100755 KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/CreditCardValidatorTest.java mode change 100644 => 100755 docs/doxygen-user/central_repo.dox mode change 100644 => 100755 docs/doxygen-user/images/central_repo_content_viewer.png mode change 100644 => 100755 docs/doxygen-user/images/central_repo_interesting_items.png mode change 100644 => 100755 docs/doxygen-user/images/central_repo_manage_tags.png mode change 100644 => 100755 docs/doxygen-user/images/central_repo_options.png mode change 100644 => 100755 docs/doxygen-user/images/central_repo_postgres.png mode change 100644 => 100755 docs/doxygen-user/images/central_repo_sqlite.png mode change 100644 => 100755 docs/doxygen-user/images/central_repo_tag_file.png mode change 100644 => 100755 docs/doxygen-user/images/central_repo_types.png mode change 100644 => 100755 docs/doxygen-user/images/email_datasource_tree.png mode change 100644 => 100755 docs/doxygen-user/images/messages_datasource_tree.png mode change 100644 => 100755 ruleset.xml diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java index 3ef30f2594..dcda423c18 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java @@ -33,7 +33,6 @@ import org.openide.util.HelpCtx; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; -import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; /** @@ -51,7 +50,7 @@ final class CaseDeleteAction extends CallableSystemAction { putValue(Action.NAME, NbBundle.getMessage(CaseDeleteAction.class, "CTL_CaseDeleteAction")); this.setEnabled(false); Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> { - setEnabled(null != evt.getNewValue() && UserPreferences.getMode() != UserPreferences.SelectedMode.REVIEW); + setEnabled(null != evt.getNewValue() && ((Case)evt.getNewValue()).getCaseType() != Case.CaseType.MULTI_USER_CASE); }); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index 1f4c5b7912..dee10f0ca1 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -172,6 +172,17 @@ public final class CaseMetadata { public String getCaseDirectory() { return metadataFilePath.getParent().toString(); } + + /** + * Gets the full case directory path. + * + * @return The case directory path. + */ + public String getCaseDirectoryPath() { + String fileName = metadataFilePath.getFileName().toString(); + String caseDirectoryPath = metadataFilePath.toString(); + return caseDirectoryPath.substring(0, caseDirectoryPath.lastIndexOf(fileName)); + } /** * Gets the case type. diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java index aa9b0eac6a..76607210c5 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java @@ -31,16 +31,13 @@ import org.openide.awt.ActionRegistration; import org.openide.util.HelpCtx; import org.openide.util.NbBundle; import org.openide.util.actions.CallableSystemAction; -import org.openide.util.lookup.ServiceProvider; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.core.UserPreferences; -import static org.sleuthkit.autopsy.core.UserPreferences.SelectedMode.REVIEW; import org.sleuthkit.autopsy.coreutils.NetworkUtils; /** - * The action associated with the Case/Open Case menu item via the layer.xml - * file, a toolbar button, and the Create New Case button of the start up window - * that allows a user to open a case. It opens an existing case. + * The action associated with the Open Multi-User Case menu item via the + * layer.xml file. * * This action should only be invoked in the event dispatch thread (EDT). */ @@ -57,27 +54,7 @@ public final class CaseOpenMultiUserAction extends CallableSystemAction implemen private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName(); private static final String REVIEW_MODE_TITLE = "Open Multi-User Case (" + LOCAL_HOST_NAME + ")"; - /** - * Constructs the action associated with the Case/Open Case menu item via - * the layer.xml file, a toolbar button, and the Create New Case button of - * the start up window that allows a user to open a case. It opens an - * existing case. - * - */ - public CaseOpenMultiUserAction() { - multiUserCaseWindow = new JDialog( - WindowManager.getDefault().getMainWindow(), - REVIEW_MODE_TITLE, - Dialog.ModalityType.APPLICATION_MODAL); - multiUserCaseWindow.getRootPane().registerKeyboardAction( - e -> { - multiUserCaseWindow.setVisible(false); - }, - KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); - multiUserCaseWindow.add(new MultiUserCasePanel()); - multiUserCaseWindow.pack(); - multiUserCaseWindow.setResizable(false); - } + public CaseOpenMultiUserAction() {} public static void closeMultiUserCasesWindow() { if (null != multiUserCaseWindow) { @@ -91,13 +68,16 @@ public final class CaseOpenMultiUserAction extends CallableSystemAction implemen } /** - * Pops up a file chooser to allow the user to select a case metadata file - * (.aut file) and attempts to open the case described by the file. + * Pops up a case selection panel to allow the user to selecte a multi-user + * case to open. * * @param e The action event. */ @Override public void actionPerformed(ActionEvent event) { + if(multiUserCaseWindow == null) { + multiUserCaseWindow = MultiUserCasesDialog.getInstance(); + } multiUserCaseWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); multiUserCaseWindow.setVisible(true); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java index 48e54a3f9f..c4c15fdd91 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java @@ -31,7 +31,6 @@ import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.core.UserPreferences; -import org.sleuthkit.autopsy.coreutils.NetworkUtils; /* * The panel in the default Autopsy startup window. @@ -39,8 +38,7 @@ import org.sleuthkit.autopsy.coreutils.NetworkUtils; public class CueBannerPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; - private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName(); - private static final String REVIEW_MODE_TITLE = "Open Multi-User Case (" + LOCAL_HOST_NAME + ")"; + private static final String REVIEW_MODE_TITLE = "Open Multi-User Case"; /* * This is field is static for the sake of the closeOpenRecentCasesWindow * method. @@ -91,7 +89,6 @@ public class CueBannerPanel extends javax.swing.JPanel { private void customizeComponents() { initRecentCasesWindow(); - initMultiUserCasesWindow(); } private void initRecentCasesWindow() { @@ -116,21 +113,6 @@ public class CueBannerPanel extends javax.swing.JPanel { recentCasesWindow.pack(); recentCasesWindow.setResizable(false); } - - private void initMultiUserCasesWindow() { - multiUserCaseWindow = new JDialog( - WindowManager.getDefault().getMainWindow(), - REVIEW_MODE_TITLE, - Dialog.ModalityType.APPLICATION_MODAL); - multiUserCaseWindow.getRootPane().registerKeyboardAction( - e -> { - multiUserCaseWindow.setVisible(false); - }, - KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); - multiUserCaseWindow.add(new MultiUserCasePanel()); - multiUserCaseWindow.pack(); - multiUserCaseWindow.setResizable(false); - } private void enableComponents() { boolean enableOpenRecentCaseButton = (RecentCases.getInstance().getTotalRecentCases() > 0); @@ -306,6 +288,9 @@ public class CueBannerPanel extends javax.swing.JPanel { }//GEN-LAST:event_openRecentCaseButtonActionPerformed private void openMultiUserCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openMultiUserCaseButtonActionPerformed + if(multiUserCaseWindow == null) { + multiUserCaseWindow = MultiUserCasesDialog.getInstance(); + } multiUserCaseWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); multiUserCaseWindow.setVisible(true); }//GEN-LAST:event_openMultiUserCaseButtonActionPerformed diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java index d1a2bc65da..8ecc1c91e2 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java @@ -18,15 +18,16 @@ */ package org.sleuthkit.autopsy.casemodule; +import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; import java.util.Comparator; import java.util.Date; import java.util.Objects; import java.util.logging.Level; -import org.sleuthkit.autopsy.casemodule.CaseMetadata; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.TimeStampUtils; @@ -46,11 +47,27 @@ class MultiUserCase implements Comparable { * Constructs a representation of case created by automated ingest. * * @param caseDirectoryPath The case directory path. + * + * @throws CaseMetadata.CaseMetadataException If the CaseMetadata object + * cannot be constructed for the + * case display name. + * @throws MultiUserCaseException If no case metadata (.aut) + * file is found in the case + * directory. */ - MultiUserCase(Path caseDirectoryPath) { + MultiUserCase(Path caseDirectoryPath) throws CaseMetadata.CaseMetadataException, MultiUserCaseException { + CaseMetadata caseMetadata = null; + + try { + caseMetadata = getCaseMetadataFromCaseDirectoryPath(caseDirectoryPath); + } catch (CaseMetadata.CaseMetadataException ex) { + logger.log(Level.SEVERE, String.format("Error reading the case metadata for %s.", caseDirectoryPath), ex); + throw ex; + } + this.caseDirectoryPath = caseDirectoryPath; - caseName = getCaseNameFromCaseDirectoryPath(caseDirectoryPath); - metadataFilePath = caseDirectoryPath.resolve(caseName + CaseMetadata.getFileExtension()); + caseName = caseMetadata.getCaseDisplayName(); + metadataFilePath = caseMetadata.getFilePath(); BasicFileAttributes fileAttrs = null; try { fileAttrs = Files.readAttributes(metadataFilePath, BasicFileAttributes.class); @@ -103,6 +120,15 @@ class MultiUserCase implements Comparable { Date getLastAccessedDate() { return this.lastAccessedDate; } + + /** + * Gets the full path of the metadata (.aut) file. + * + * @return The metadata file path. + */ + Path getMetadataFilePath() { + return this.metadataFilePath; + } /** * Gets the status of this case based on the auto ingest result file in the @@ -119,19 +145,48 @@ class MultiUserCase implements Comparable { } /** - * Extracts the case name from a case folder path. + * Gets the case metadata from a case directory path. * - * @param caseFolderPath A case folder path. + * @param caseDirectoryPath The case directory path. * - * @return A case name, with the time stamp suffix removed. + * @return Case metadata. + * + * @throws CaseMetadata.CaseMetadataException If the CaseMetadata object + * cannot be constructed. + * @throws MultiUserCaseException If no case metadata (.aut) + * file is found in the case + * directory. */ - static String getCaseNameFromCaseDirectoryPath(Path caseFolderPath) { - String caseName = caseFolderPath.getFileName().toString(); - if (caseName.length() > TimeStampUtils.getTimeStampLength()) { - return caseName.substring(0, caseName.length() - TimeStampUtils.getTimeStampLength()); - } else { - return caseName; + private static CaseMetadata getCaseMetadataFromCaseDirectoryPath(Path caseDirectoryPath) throws CaseMetadata.CaseMetadataException, MultiUserCaseException { + CaseMetadata caseMetadata = null; + + File directory = new File(caseDirectoryPath.toString()); + if (directory.isDirectory()) { + String fileNamePrefix = directory.getName(); + if (TimeStampUtils.endsWithTimeStamp(fileNamePrefix)) { + fileNamePrefix = fileNamePrefix.substring(0, fileNamePrefix.length() - TimeStampUtils.getTimeStampLength()); + } + + File autFile = null; + + /* + * Attempt to find an AUT file via a directory scan. + */ + for (File file : directory.listFiles()) { + if (file.getName().toLowerCase().endsWith(CaseMetadata.getFileExtension()) && file.isFile()) { + autFile = file; + break; + } + } + + if(autFile == null || !autFile.isFile()) { + throw new MultiUserCaseException(String.format("No case metadata (.aut) file found in the case directory '%s'.", caseDirectoryPath.toString())); + } + + caseMetadata = new CaseMetadata(Paths.get(autFile.getAbsolutePath())); } + + return caseMetadata; } /** @@ -169,7 +224,7 @@ class MultiUserCase implements Comparable { /** * Compares this AutopIngestCase object with abnother MultiUserCase object - for order. + * for order. */ @Override public int compareTo(MultiUserCase other) { @@ -183,7 +238,7 @@ class MultiUserCase implements Comparable { /** * Compares two MultiUserCase objects for order based on last accessed - date (descending). + * date (descending). * * @param object The first MultiUserCase object * @param otherObject The second AuotIngestCase object. @@ -196,6 +251,35 @@ class MultiUserCase implements Comparable { return -object.getLastAccessedDate().compareTo(otherObject.getLastAccessedDate()); } } + + /** + * Exception thrown when there is a problem creating a multi-user case. + */ + final static class MultiUserCaseException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructs an exception to throw when there is a problem creating a + * multi-user case. + * + * @param message The exception message. + */ + private MultiUserCaseException(String message) { + super(message); + } + + /** + * Constructs an exception to throw when there is a problem creating a + * multi-user case. + * + * @param message The exception message. + * @param cause The cause of the exception, if it was an exception. + */ + private MultiUserCaseException(String message, Throwable cause) { + super(message, cause); + } + } enum CaseStatus { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java index ec3b42116d..3101461443 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java @@ -78,7 +78,11 @@ final class MultiUserCaseManager { if(caseFolder.exists()) { File[] autFiles = caseFolder.listFiles((dir, name) -> name.toLowerCase().endsWith(".aut")); if(autFiles != null && autFiles.length > 0) { + try { cases.add(new MultiUserCase(casePath)); + } catch (CaseMetadata.CaseMetadataException | MultiUserCase.MultiUserCaseException ex) { + // Ignore and continue. + } } } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasePanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasePanel.form deleted file mode 100755 index a54439c4d3..0000000000 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasePanel.form +++ /dev/null @@ -1,230 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasePanel.java deleted file mode 100755 index 5f3365e8b1..0000000000 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasePanel.java +++ /dev/null @@ -1,562 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2017 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.casemodule; - -import java.awt.Cursor; -import java.awt.Desktop; -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Date; -import java.util.List; -import java.util.logging.Level; -import javax.swing.JOptionPane; -import javax.swing.event.ListSelectionEvent; -import javax.swing.table.DefaultTableModel; -import javax.swing.table.TableColumn; -import org.sleuthkit.autopsy.coreutils.CaseStatusIconCellRenderer; -import org.sleuthkit.autopsy.coreutils.GrayableCellRenderer; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.LongDateCellRenderer; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; - -/** - * A panel that allows a user to open cases created by auto ingest. - */ -public class MultiUserCasePanel extends javax.swing.JPanel { - - private static final long serialVersionUID = 1L; - private static final Logger LOGGER = Logger.getLogger(MultiUserCasePanel.class.getName()); - private static final String LOG_FILE_NAME = "auto_ingest_log.txt"; - private static final MultiUserCase.LastAccessedDateDescendingComparator REVERSE_DATE_MODIFIED_COMPARATOR = new MultiUserCase.LastAccessedDateDescendingComparator(); - private static final int CASE_COL_MIN_WIDTH = 30; - private static final int CASE_COL_MAX_WIDTH = 2000; - private static final int CASE_COL_PREFERRED_WIDTH = 300; - private static final int TIME_COL_MIN_WIDTH = 40; - private static final int TIME_COL_MAX_WIDTH = 250; - private static final int TIME_COL_PREFERRED_WIDTH = 160; - private static final int STATUS_COL_MIN_WIDTH = 55; - private static final int STATUS_COL_MAX_WIDTH = 250; - private static final int STATUS_COL_PREFERRED_WIDTH = 60; - - /* - * The JTable table model for the cases table presented by this view is - * defined by the following string, enum, and array. - * - * TODO (RC): Consider unifying this stuff in an enum as in - * AutoIngestDashboard to make it less error prone. - */ - private static final String CASE_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "ReviewModeCasePanel.CaseHeaderText"); - private static final String CREATEDTIME_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "ReviewModeCasePanel.CreatedTimeHeaderText"); - private static final String COMPLETEDTIME_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "ReviewModeCasePanel.LastAccessedTimeHeaderText"); - private static final String STATUS_ICON_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "ReviewModeCasePanel.StatusIconHeaderText"); - private static final String OUTPUT_FOLDER_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "ReviewModeCasePanel.OutputFolderHeaderText"); - - enum COLUMN_HEADERS { - - CASE, - CREATEDTIME, - COMPLETEDTIME, - STATUS_ICON, - OUTPUTFOLDER - } - private final String[] columnNames = {CASE_HEADER, CREATEDTIME_HEADER, COMPLETEDTIME_HEADER, STATUS_ICON_HEADER, OUTPUT_FOLDER_HEADER}; - private DefaultTableModel caseTableModel; - private Path currentlySelectedCase = null; - - /** - * Constructs a panel that allows a user to open cases created by automated - * ingest. - * - * @param parent The parent dialog for this panel. - */ - MultiUserCasePanel() { - caseTableModel = new DefaultTableModel(columnNames, 0) { - private static final long serialVersionUID = 1L; - - @Override - public boolean isCellEditable(int row, int column) { - return false; - } - - @Override - public Class getColumnClass(int col) { - if (this.getColumnName(col).equals(CREATEDTIME_HEADER) || this.getColumnName(col).equals(COMPLETEDTIME_HEADER)) { - return Date.class; - } else { - return super.getColumnClass(col); - } - } - }; - - initComponents(); - - /* - * Configure the columns of the cases table. - */ - TableColumn theColumn; - theColumn = casesTable.getColumn(CASE_HEADER); - theColumn.setCellRenderer(new GrayableCellRenderer()); - theColumn.setMinWidth(CASE_COL_MIN_WIDTH); - theColumn.setMaxWidth(CASE_COL_MAX_WIDTH); - theColumn.setPreferredWidth(CASE_COL_PREFERRED_WIDTH); - theColumn.setWidth(CASE_COL_PREFERRED_WIDTH); - - theColumn = casesTable.getColumn(CREATEDTIME_HEADER); - theColumn.setCellRenderer(new LongDateCellRenderer()); - theColumn.setMinWidth(TIME_COL_MIN_WIDTH); - theColumn.setMaxWidth(TIME_COL_MAX_WIDTH); - theColumn.setPreferredWidth(TIME_COL_PREFERRED_WIDTH); - theColumn.setWidth(TIME_COL_PREFERRED_WIDTH); - - theColumn = casesTable.getColumn(COMPLETEDTIME_HEADER); - theColumn.setCellRenderer(new LongDateCellRenderer()); - theColumn.setMinWidth(TIME_COL_MIN_WIDTH); - theColumn.setMaxWidth(TIME_COL_MAX_WIDTH); - theColumn.setPreferredWidth(TIME_COL_PREFERRED_WIDTH); - theColumn.setWidth(TIME_COL_PREFERRED_WIDTH); - - theColumn = casesTable.getColumn(STATUS_ICON_HEADER); - theColumn.setCellRenderer(new CaseStatusIconCellRenderer()); - theColumn.setMinWidth(STATUS_COL_MIN_WIDTH); - theColumn.setMaxWidth(STATUS_COL_MAX_WIDTH); - theColumn.setPreferredWidth(STATUS_COL_PREFERRED_WIDTH); - theColumn.setWidth(STATUS_COL_PREFERRED_WIDTH); - - casesTable.removeColumn(casesTable.getColumn(OUTPUT_FOLDER_HEADER)); - - /* - * Listen for row selection changes and set button state for the current - * selection. - */ - casesTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> { - //Ignore extra messages. - if (e.getValueIsAdjusting()) { - return; - } - setButtons(); - }); - refreshCasesTable(); - } - - /** - * Gets the list of cases known to the review mode cases manager and - * refreshes the cases table. - */ - private void refreshCasesTable() { - try { - currentlySelectedCase = getSelectedCase(); - MultiUserCaseManager manager = MultiUserCaseManager.getInstance(); - List cases = manager.getCases(); - cases.sort(REVERSE_DATE_MODIFIED_COMPARATOR); - caseTableModel.setRowCount(0); - long now = new Date().getTime(); - for (MultiUserCase autoIngestCase : cases) { - if (passesTimeFilter(now, autoIngestCase.getLastAccessedDate().getTime())) { - caseTableModel.addRow(new Object[]{ - autoIngestCase.getCaseName(), - autoIngestCase.getCreationDate(), - autoIngestCase.getLastAccessedDate(), - (MultiUserCase.CaseStatus.OK != autoIngestCase.getStatus()), - autoIngestCase.getCaseDirectoryPath().toString()}); - } - } - setSelectedCase(currentlySelectedCase); - setButtons(); - } catch (Exception ex) { - LOGGER.log(Level.SEVERE, "Unexpected exception in refreshCasesTable", ex); //NON-NLS - } - } - - /** - * Gets the current selection in the cases table. - * - * @return A path representing the current selected case, null if there is - * no selection. - */ - private Path getSelectedCase() { - try { - int selectedRow = casesTable.getSelectedRow(); - if (selectedRow >= 0 && selectedRow < casesTable.getRowCount()) { - return Paths.get(caseTableModel.getValueAt(casesTable.convertRowIndexToModel(selectedRow), COLUMN_HEADERS.CASE.ordinal()).toString()); - } - } catch (Exception ignored) { - return null; - } - return null; - } - - /** - * Sets the current selection in the cases table. - * - * @param path The case folder path of the case to select. - */ - private void setSelectedCase(Path path) { - if (path != null) { - try { - for (int row = 0; row < casesTable.getRowCount(); ++row) { - Path temp = Paths.get(caseTableModel.getValueAt(casesTable.convertRowIndexToModel(row), COLUMN_HEADERS.CASE.ordinal()).toString()); - if (temp.compareTo(path) == 0) { // found it - casesTable.setRowSelectionInterval(row, row); - return; - } - } - } catch (Exception ignored) { - casesTable.clearSelection(); - } - } - casesTable.clearSelection(); - } - - /** - * Enables/disables the Open and Show Log buttons based on the case selected - * in the cases table. - */ - private void setButtons() { - boolean openEnabled = casesTable.getSelectedRow() >= 0 && casesTable.getSelectedRow() < casesTable.getRowCount(); - bnOpen.setEnabled(openEnabled); - - Path pathToLog = getSelectedCaseLogFilePath(); - boolean showLogEnabled = openEnabled && pathToLog != null && pathToLog.toFile().exists(); - bnShowLog.setEnabled(showLogEnabled); - } - - /** - * Retrieves the log file path for the selected case in the cases table. - * - * @return The case log path. - */ - private Path getSelectedCaseLogFilePath() { - Path retValue = null; - - int selectedRow = casesTable.getSelectedRow(); - int rowCount = casesTable.getRowCount(); - if (selectedRow >= 0 && selectedRow < rowCount) { - String thePath = (String) caseTableModel.getValueAt(casesTable.convertRowIndexToModel(selectedRow), COLUMN_HEADERS.OUTPUTFOLDER.ordinal()); - retValue = Paths.get(thePath, LOG_FILE_NAME); - } - - return retValue; - } - - /** - * Opens a case. - * - * @param caseMetadataFilePath The path to the case metadata file. - */ - private void openCase(Path caseMetadataFilePath) { - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - try { - StartupWindowProvider.getInstance().close(); - CueBannerPanel.closeMultiUserCasesWindow(); - CaseOpenMultiUserAction.closeMultiUserCasesWindow(); - MultiUserCaseManager.getInstance().openCase(caseMetadataFilePath); - } catch (CaseActionException | MultiUserCaseManager.MultiUserCaseManagerException ex) { - if (null != ex.getCause() && !(ex.getCause() instanceof CaseActionCancelledException)) { - LOGGER.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", caseMetadataFilePath), ex); //NON-NLS - MessageNotifyUtil.Message.error(ex.getCause().getLocalizedMessage()); - } - StartupWindowProvider.getInstance().open(); - } finally { - setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - } - } - - /** - * Indicates whether or not a time satisfies a time filter defined by this - * panel's time filter radio buttons. - * - * @param currentTime The current date and time in milliseconds from the - * Unix epoch. - * @param inputTime The date and time to be tested as milliseconds from - * the Unix epoch. - */ - private boolean passesTimeFilter(long currentTime, long inputTime) { - long numberOfUnits = 10; - long multiplier = 1; - if (rbAllCases.isSelected()) { - return true; - } else if (rbMonths.isSelected()) { - multiplier = 31; - } else if (rbWeeks.isSelected()) { - multiplier = 7; - } else if (rbDays.isSelected()) { - multiplier = 1; - } - return ((currentTime - inputTime) / (1000 * 60 * 60 * 24)) < (numberOfUnits * multiplier); - } - - /** - * 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() { - - rbGroupHistoryLength = new javax.swing.ButtonGroup(); - bnOpen = new javax.swing.JButton(); - scrollPaneTable = new javax.swing.JScrollPane(); - casesTable = new javax.swing.JTable(); - bnRefresh = new javax.swing.JButton(); - panelFilter = new javax.swing.JPanel(); - rbAllCases = new javax.swing.JRadioButton(); - bnShowLog = new javax.swing.JButton(); - rbDays = new javax.swing.JRadioButton(); - rbWeeks = new javax.swing.JRadioButton(); - rbMonths = new javax.swing.JRadioButton(); - rbGroupLabel = new javax.swing.JLabel(); - - setName("Completed Cases"); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(bnOpen, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.bnOpen.text")); // NOI18N - bnOpen.setEnabled(false); - bnOpen.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnOpenActionPerformed(evt); - } - }); - - casesTable.setAutoCreateRowSorter(true); - casesTable.setModel(caseTableModel); - casesTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS); - casesTable.setRowHeight(20); - casesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); - casesTable.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseClicked(java.awt.event.MouseEvent evt) { - casesTableMouseClicked(evt); - } - }); - scrollPaneTable.setViewportView(casesTable); - - org.openide.awt.Mnemonics.setLocalizedText(bnRefresh, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.bnRefresh.text")); // NOI18N - bnRefresh.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnRefreshActionPerformed(evt); - } - }); - - rbGroupHistoryLength.add(rbAllCases); - rbAllCases.setSelected(true); - org.openide.awt.Mnemonics.setLocalizedText(rbAllCases, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.rbAllCases.text")); // NOI18N - rbAllCases.addItemListener(new java.awt.event.ItemListener() { - public void itemStateChanged(java.awt.event.ItemEvent evt) { - rbAllCasesItemStateChanged(evt); - } - }); - - javax.swing.GroupLayout panelFilterLayout = new javax.swing.GroupLayout(panelFilter); - panelFilter.setLayout(panelFilterLayout); - panelFilterLayout.setHorizontalGroup( - panelFilterLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelFilterLayout.createSequentialGroup() - .addComponent(rbAllCases) - .addGap(0, 0, Short.MAX_VALUE)) - ); - panelFilterLayout.setVerticalGroup( - panelFilterLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, panelFilterLayout.createSequentialGroup() - .addGap(0, 0, 0) - .addComponent(rbAllCases)) - ); - - org.openide.awt.Mnemonics.setLocalizedText(bnShowLog, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.bnShowLog.text")); // NOI18N - bnShowLog.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.bnShowLog.toolTipText")); // NOI18N - bnShowLog.setEnabled(false); - bnShowLog.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnShowLogActionPerformed(evt); - } - }); - - rbGroupHistoryLength.add(rbDays); - org.openide.awt.Mnemonics.setLocalizedText(rbDays, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.rbDays.text")); // NOI18N - rbDays.setName(""); // NOI18N - rbDays.addItemListener(new java.awt.event.ItemListener() { - public void itemStateChanged(java.awt.event.ItemEvent evt) { - rbDaysItemStateChanged(evt); - } - }); - - rbGroupHistoryLength.add(rbWeeks); - org.openide.awt.Mnemonics.setLocalizedText(rbWeeks, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.rbWeeks.text")); // NOI18N - rbWeeks.addItemListener(new java.awt.event.ItemListener() { - public void itemStateChanged(java.awt.event.ItemEvent evt) { - rbWeeksItemStateChanged(evt); - } - }); - - rbGroupHistoryLength.add(rbMonths); - org.openide.awt.Mnemonics.setLocalizedText(rbMonths, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.rbMonths.text")); // NOI18N - rbMonths.addItemListener(new java.awt.event.ItemListener() { - public void itemStateChanged(java.awt.event.ItemEvent evt) { - rbMonthsItemStateChanged(evt); - } - }); - - rbGroupLabel.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(rbGroupLabel, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "MultiUserCasePanel.rbGroupLabel.text")); // NOI18N - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(4, 4, 4) - .addComponent(bnOpen, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnShowLog) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(rbGroupLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(rbDays) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(rbWeeks) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(rbMonths) - .addGap(0, 0, 0) - .addComponent(panelFilter, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(bnRefresh) - .addGap(4, 4, 4)) - .addComponent(scrollPaneTable)) - .addContainerGap()) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(6, 6, 6) - .addComponent(scrollPaneTable, javax.swing.GroupLayout.PREFERRED_SIZE, 450, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(bnOpen) - .addComponent(bnShowLog)) - .addComponent(bnRefresh) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(rbDays) - .addComponent(rbWeeks) - .addComponent(rbMonths) - .addComponent(rbGroupLabel)) - .addComponent(panelFilter, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGap(0, 0, 0)) - ); - }// //GEN-END:initComponents - - /** - * Open button action - * - * @param evt -- The event that caused this to be called - */ - private void bnOpenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOpenActionPerformed - int modelRow = casesTable.convertRowIndexToModel(casesTable.getSelectedRow()); - Path caseMetadataFilePath = Paths.get((String) caseTableModel.getValueAt(modelRow, - COLUMN_HEADERS.OUTPUTFOLDER.ordinal()), - caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.CASE.ordinal()) + CaseMetadata.getFileExtension()); - - new Thread(() -> { - openCase(caseMetadataFilePath); - }).start(); - }//GEN-LAST:event_bnOpenActionPerformed - - /** - * Refresh button action - * - * @param evt -- The event that caused this to be called - */ - private void bnRefreshActionPerformed(java.awt.event.ActionEvent evt) { - refreshCasesTable(); - } - - private void rbDaysItemStateChanged(java.awt.event.ItemEvent evt) { - if (rbDays.isSelected()) { - refreshCasesTable(); - } - } - - private void rbAllCasesItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbAllCasesItemStateChanged - if (rbAllCases.isSelected()) { - refreshCasesTable(); - } - }//GEN-LAST:event_rbAllCasesItemStateChanged - - private void rbMonthsItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbMonthsItemStateChanged - if (rbMonths.isSelected()) { - refreshCasesTable(); - } - }//GEN-LAST:event_rbMonthsItemStateChanged - - private void rbWeeksItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbWeeksItemStateChanged - if (rbWeeks.isSelected()) { - refreshCasesTable(); - } - }//GEN-LAST:event_rbWeeksItemStateChanged - - private void bnShowLogActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnShowLogActionPerformed - Path pathToLog = getSelectedCaseLogFilePath(); - if (pathToLog != null) { - try { - if (pathToLog.toFile().exists()) { - Desktop.getDesktop().edit(pathToLog.toFile()); - - } else { - JOptionPane.showMessageDialog(this, org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "DisplayLogDialog.cannotFindLog"), - org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "DisplayLogDialog.unableToShowLogFile"), JOptionPane.ERROR_MESSAGE); - } - } catch (IOException ex) { - LOGGER.log(Level.SEVERE, String.format("Error attempting to open case auto ingest log file %s", pathToLog), ex); - JOptionPane.showMessageDialog(this, - org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "DisplayLogDialog.cannotOpenLog"), - org.openide.util.NbBundle.getMessage(MultiUserCasePanel.class, "DisplayLogDialog.unableToShowLogFile"), - JOptionPane.PLAIN_MESSAGE); - } - } - }//GEN-LAST:event_bnShowLogActionPerformed - - private void casesTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_casesTableMouseClicked - if (evt.getClickCount() == 2) { - int modelRow = casesTable.convertRowIndexToModel(casesTable.getSelectedRow()); - Path caseMetadataFilePath = Paths.get((String) caseTableModel.getValueAt(modelRow, - COLUMN_HEADERS.OUTPUTFOLDER.ordinal()), - caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.CASE.ordinal()) + CaseMetadata.getFileExtension()); - openCase(caseMetadataFilePath); - } - }//GEN-LAST:event_casesTableMouseClicked - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton bnOpen; - private javax.swing.JButton bnRefresh; - private javax.swing.JButton bnShowLog; - private javax.swing.JTable casesTable; - private javax.swing.JPanel panelFilter; - private javax.swing.JRadioButton rbAllCases; - private javax.swing.JRadioButton rbDays; - private javax.swing.ButtonGroup rbGroupHistoryLength; - private javax.swing.JLabel rbGroupLabel; - private javax.swing.JRadioButton rbMonths; - private javax.swing.JRadioButton rbWeeks; - private javax.swing.JScrollPane scrollPaneTable; - // End of variables declaration//GEN-END:variables - -} diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java old mode 100644 new mode 100755 diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java old mode 100644 new mode 100755 diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java old mode 100644 new mode 100755 diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java old mode 100644 new mode 100755 diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java old mode 100644 new mode 100755 diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java old mode 100644 new mode 100755 diff --git a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java index df63b0fa1f..0e7fc3da5e 100755 --- a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java +++ b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2014-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,6 @@ import java.util.prefs.BackingStoreException; import org.sleuthkit.autopsy.events.MessageServiceConnectionInfo; import java.util.prefs.PreferenceChangeListener; import java.util.prefs.Preferences; -import org.openide.util.Exceptions; import org.openide.util.NbPreferences; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; @@ -77,7 +76,6 @@ public final class UserPreferences { STANDALONE, AUTOINGEST, - REVIEW }; /** diff --git a/Core/src/org/sleuthkit/autopsy/core/timelineWsmode.xml b/Core/src/org/sleuthkit/autopsy/core/timelineWsmode.xml old mode 100644 new mode 100755 diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java b/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java index c908f3b35d..060061e205 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java @@ -30,7 +30,10 @@ import org.netbeans.swing.tabcontrol.plaf.DefaultTabbedContainerUI; import org.openide.modules.ModuleInstall; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.StartupWindowProvider; +import org.sleuthkit.autopsy.core.UserPreferences; +import static org.sleuthkit.autopsy.core.UserPreferences.SETTINGS_PROPERTIES; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; /** * Manages this module's life cycle. Opens the startup dialog during startup. @@ -59,6 +62,7 @@ public class Installer extends ModuleInstall { UIManager.put("ViewTabDisplayerUI", "org.sleuthkit.autopsy.corecomponents.NoTabsTabDisplayerUI"); UIManager.put(DefaultTabbedContainerUI.KEY_VIEW_CONTENT_BORDER, BorderFactory.createEmptyBorder()); UIManager.put("TabbedPane.contentBorderInsets", new Insets(0, 0, 0, 0)); + updateConfig(); WindowManager.getDefault().invokeWhenUIReady(() -> { StartupWindowProvider.getInstance().open(); }); @@ -68,6 +72,21 @@ public class Installer extends ModuleInstall { public void uninstalled() { super.uninstalled(); } + + /** + * If the mode in the configuration file is 'REVIEW' (2, now invalid), this + * method will set it to 'STANDALONE' (0) and disable auto ingest. + */ + private void updateConfig() { + String mode = ModuleSettings.getConfigSetting(SETTINGS_PROPERTIES, "AutopsyMode"); + if(mode != null) { + int ordinal = Integer.parseInt(mode); + if(ordinal > 1) { + UserPreferences.setMode(UserPreferences.SelectedMode.STANDALONE); + ModuleSettings.setConfigSetting(UserPreferences.SETTINGS_PROPERTIES, "JoinAutoModeCluster", Boolean.toString(false)); + } + } + } private void setLookAndFeel() { if (System.getProperty("os.name").toLowerCase().contains("mac")) { //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/FileSystemDetailsAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/FileSystemDetailsAction.java old mode 100644 new mode 100755 diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseOpenAction.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseOpenAction.java index 265190663e..6a84946c91 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseOpenAction.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseOpenAction.java @@ -53,7 +53,6 @@ final class AutoIngestCaseOpenAction extends CallableSystemAction implements Act break; case STANDALONE: - case REVIEW: /** * In standalone mode, invoke default Autopsy version of CaseOpenAction. */ diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form index 4a943b4924..9a599877f8 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form @@ -29,8 +29,19 @@ + + - + + + + + + + + + + @@ -39,18 +50,9 @@ - - - - - - - - - @@ -81,6 +83,7 @@ + @@ -255,5 +258,15 @@ + + + + + + + + + + diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java index 5537d07236..38b408de9f 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java @@ -664,6 +664,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer { tbServicesStatusMessage = new javax.swing.JTextField(); prioritizeJobButton = new javax.swing.JButton(); prioritizeCaseButton = new javax.swing.JButton(); + clusterMetricsButton = new javax.swing.JButton(); org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.jButton1.text")); // NOI18N @@ -764,6 +765,13 @@ public final class AutoIngestDashboard extends JPanel implements Observer { } }); + org.openide.awt.Mnemonics.setLocalizedText(clusterMetricsButton, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.clusterMetricsButton.text")); // NOI18N + clusterMetricsButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + clusterMetricsButtonActionPerformed(evt); + } + }); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -772,24 +780,26 @@ public final class AutoIngestDashboard extends JPanel implements Observer { .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(pendingScrollPane) + .addComponent(runningScrollPane, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(completedScrollPane, javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lbPending) - .addComponent(lbCompleted) - .addComponent(lbRunning) - .addGroup(layout.createSequentialGroup() - .addComponent(lbServicesStatus) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(tbServicesStatusMessage, javax.swing.GroupLayout.PREFERRED_SIZE, 861, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() .addComponent(refreshButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(prioritizeJobButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(prioritizeCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGap(0, 0, Short.MAX_VALUE)) - .addComponent(runningScrollPane, javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(completedScrollPane, javax.swing.GroupLayout.Alignment.LEADING)) + .addComponent(prioritizeCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(clusterMetricsButton)) + .addComponent(lbPending, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lbCompleted, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lbRunning, javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(lbServicesStatus) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(tbServicesStatusMessage, javax.swing.GroupLayout.PREFERRED_SIZE, 861, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGap(0, 0, Short.MAX_VALUE))) .addContainerGap()) ); layout.setVerticalGroup( @@ -815,7 +825,8 @@ public final class AutoIngestDashboard extends JPanel implements Observer { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(refreshButton) .addComponent(prioritizeJobButton) - .addComponent(prioritizeCaseButton)) + .addComponent(prioritizeCaseButton) + .addComponent(clusterMetricsButton)) .addContainerGap()) ); }// //GEN-END:initComponents @@ -874,7 +885,12 @@ public final class AutoIngestDashboard extends JPanel implements Observer { } }//GEN-LAST:event_prioritizeCaseButtonActionPerformed + private void clusterMetricsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clusterMetricsButtonActionPerformed + new AutoIngestMetricsDialog(this.getTopLevelAncestor(), autoIngestMonitor); + }//GEN-LAST:event_clusterMetricsButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton clusterMetricsButton; private javax.swing.JScrollPane completedScrollPane; private javax.swing.JTable completedTable; private javax.swing.JButton jButton1; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java index 10ff60da2a..45563a4f4b 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java @@ -25,7 +25,6 @@ import org.openide.util.HelpCtx; import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; import org.sleuthkit.autopsy.core.UserPreferences; -import static org.sleuthkit.autopsy.core.UserPreferences.SelectedMode.REVIEW; import org.sleuthkit.autopsy.coreutils.Logger; @ActionID(category = "Tools", id = "org.sleuthkit.autopsy.experimental.autoingest.AutoIngestDashboardOpenAction") diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java index 9a262bb6d3..09f0c7c949 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java @@ -23,10 +23,12 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Arrays; +import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Observable; import java.util.Set; +import java.util.TreeSet; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.logging.Level; @@ -265,17 +267,94 @@ public final class AutoIngestMonitor extends Observable implements PropertyChang } } catch (InterruptedException ex) { LOGGER.log(Level.SEVERE, String.format("Unexpected interrupt while retrieving coordination service node data for '%s'", node), ex); - } catch (AutoIngestJobNodeData.InvalidDataException | AutoIngestJob.AutoIngestJobException ex) { + } catch (AutoIngestJobNodeData.InvalidDataException ex) { LOGGER.log(Level.SEVERE, String.format("Unable to use node data for '%s'", node), ex); + } catch (AutoIngestJob.AutoIngestJobException ex) { + LOGGER.log(Level.SEVERE, String.format("Failed to create a job for '%s'", node), ex); } } + return newJobsSnapshot; + } catch (CoordinationServiceException ex) { LOGGER.log(Level.SEVERE, "Failed to get node list from coordination service", ex); return new JobsSnapshot(); } } + /** + * Gets a new metrics snapshot from the coordination service for an auto + * ingest cluster. The jobs snapshot will also be updated. + * + * @return The metrics snapshot. + */ + private MetricsSnapshot queryCoordinationServiceForMetrics() { + try { + JobsSnapshot newJobsSnapshot = new JobsSnapshot(); + MetricsSnapshot newMetricsSnapshot = new MetricsSnapshot(); + List nodeList = coordinationService.getNodeList(CoordinationService.CategoryNode.MANIFESTS); + for (String node : nodeList) { + try { + AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.MANIFESTS, node)); + if (nodeData.getVersion() < 1) { + /* + * Ignore version '0' nodes that have not been + * "upgraded" since they don't carry enough data. + */ + continue; + } + AutoIngestJob job = new AutoIngestJob(nodeData); + ProcessingStatus processingStatus = nodeData.getProcessingStatus(); + switch (processingStatus) { + case PENDING: + newJobsSnapshot.addOrReplacePendingJob(job); + break; + case PROCESSING: + newJobsSnapshot.addOrReplaceRunningJob(job); + break; + case COMPLETED: + newJobsSnapshot.addOrReplaceCompletedJob(job); + newMetricsSnapshot.addCompletedJobDate(job.getCompletedDate()); + break; + case DELETED: + break; + default: + LOGGER.log(Level.SEVERE, "Unknown AutoIngestJobData.ProcessingStatus"); + break; + } + } catch (InterruptedException ex) { + LOGGER.log(Level.SEVERE, String.format("Unexpected interrupt while retrieving coordination service node data for '%s'", node), ex); + } catch (AutoIngestJobNodeData.InvalidDataException ex) { + LOGGER.log(Level.SEVERE, String.format("Unable to use node data for '%s'", node), ex); + } catch (AutoIngestJob.AutoIngestJobException ex) { + LOGGER.log(Level.SEVERE, String.format("Failed to create a job for '%s'", node), ex); + } + } + + return newMetricsSnapshot; + + } catch (CoordinationServiceException ex) { + LOGGER.log(Level.SEVERE, "Failed to get node list from coordination service", ex); + return new MetricsSnapshot(); + } + } + + /** + * Gets a new metrics snapshot. The jobs snapshot will also be updated in + * effect. + * + * @return The metrics snapshot. + */ + public MetricsSnapshot getMetricsSnapshot() { + MetricsSnapshot metricsSnapshot; + + synchronized (jobsLock) { + metricsSnapshot = queryCoordinationServiceForMetrics(); + } + + return metricsSnapshot; + } + /** * Bumps the priority of all pending ingest jobs for a specified case. * @@ -522,6 +601,32 @@ public final class AutoIngestMonitor extends Observable implements PropertyChang } + /** + * A snapshot of metrics for an auto ingest cluster. + */ + public static final class MetricsSnapshot { + + private final List completedJobDates = new ArrayList<>(); + + /** + * Gets a list of completed job dates, formatted in milliseconds. + * + * @return The completed job dates, formatted in milliseconds. + */ + List getCompletedJobDates() { + return new ArrayList<>(completedJobDates); + } + + /** + * Adds a new date to the list of completed job dates. + * + * @param date The date to be added. + */ + void addCompletedJobDate(Date date) { + completedJobDates.add(date.getTime()); + } + } + /** * Exception type thrown when there is an error completing an auto ingest * monitor operation. diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties index fc80df5551..c856dbe8bf 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties @@ -227,3 +227,8 @@ AutoIngestDashboard.prioritizeJobButton.toolTipText=Move the selected job to the AutoIngestDashboard.prioritizeJobButton.text=Prioritize &Job AutoIngestDashboard.prioritizeCaseButton.toolTipText=Move all images associated with a case to top of Pending queue. AutoIngestDashboard.prioritizeCaseButton.text=Prioritize &Case +AutoIngestMetricsDialog.reportTextArea.text= +AutoIngestDashboard.clusterMetricsButton.text=Cluster Metrics +AutoIngestMetricsDialog.metricsButton.text=Get Metrics Since... +AutoIngestMetricsDialog.closeButton.text=Close +AutoIngestMetricsDialog.datePicker.toolTipText=Choose a date diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseImportPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseImportPanel.java index a7cd13af72..2e4866b010 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseImportPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseImportPanel.java @@ -672,7 +672,6 @@ public class CaseImportPanel extends javax.swing.JPanel implements ImportDoneCal */ private void enableStartButton() { if (UserPreferences.getIsMultiUserModeEnabled() - && AutoIngestUserPreferences.getJoinAutoModeCluster() && (! RuntimeProperties.runningWithGUI()) && !tbCaseSource.getText().isEmpty() && !tbCaseDestination.getText().isEmpty() diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/dashboardWsmode.xml b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/dashboardWsmode.xml old mode 100644 new mode 100755 diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryWsmode.xml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryWsmode.xml old mode 100644 new mode 100755 diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/layer.xml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/layer.xml old mode 100644 new mode 100755 diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/CreditCardValidator.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/CreditCardValidator.java old mode 100644 new mode 100755 diff --git a/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/CreditCardValidatorTest.java b/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/CreditCardValidatorTest.java old mode 100644 new mode 100755 diff --git a/docs/doxygen-user/central_repo.dox b/docs/doxygen-user/central_repo.dox old mode 100644 new mode 100755 diff --git a/docs/doxygen-user/images/central_repo_content_viewer.png b/docs/doxygen-user/images/central_repo_content_viewer.png old mode 100644 new mode 100755 diff --git a/docs/doxygen-user/images/central_repo_interesting_items.png b/docs/doxygen-user/images/central_repo_interesting_items.png old mode 100644 new mode 100755 diff --git a/docs/doxygen-user/images/central_repo_manage_tags.png b/docs/doxygen-user/images/central_repo_manage_tags.png old mode 100644 new mode 100755 diff --git a/docs/doxygen-user/images/central_repo_options.png b/docs/doxygen-user/images/central_repo_options.png old mode 100644 new mode 100755 diff --git a/docs/doxygen-user/images/central_repo_postgres.png b/docs/doxygen-user/images/central_repo_postgres.png old mode 100644 new mode 100755 diff --git a/docs/doxygen-user/images/central_repo_sqlite.png b/docs/doxygen-user/images/central_repo_sqlite.png old mode 100644 new mode 100755 diff --git a/docs/doxygen-user/images/central_repo_tag_file.png b/docs/doxygen-user/images/central_repo_tag_file.png old mode 100644 new mode 100755 diff --git a/docs/doxygen-user/images/central_repo_types.png b/docs/doxygen-user/images/central_repo_types.png old mode 100644 new mode 100755 diff --git a/docs/doxygen-user/images/email_datasource_tree.png b/docs/doxygen-user/images/email_datasource_tree.png old mode 100644 new mode 100755 diff --git a/docs/doxygen-user/images/messages_datasource_tree.png b/docs/doxygen-user/images/messages_datasource_tree.png old mode 100644 new mode 100755 diff --git a/ruleset.xml b/ruleset.xml old mode 100644 new mode 100755 From 59afda83c67249d4af11fc32b0ac8f763f7eef63 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 3 Nov 2017 15:12:38 -0400 Subject: [PATCH 051/115] Additional files for auto ingest metrics feature --- .../casemodule/MultiUserCasesDialog.java | 81 +++ .../casemodule/MultiUserCasesPanel.form | 230 +++++++ .../casemodule/MultiUserCasesPanel.java | 582 ++++++++++++++++++ .../autoingest/AutoIngestMetricsDialog.form | 113 ++++ .../autoingest/AutoIngestMetricsDialog.java | 178 ++++++ 5 files changed, 1184 insertions(+) create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesDialog.java create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.form create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java create mode 100755 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.form create mode 100755 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesDialog.java new file mode 100755 index 0000000000..b6d9feeb7e --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesDialog.java @@ -0,0 +1,81 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.casemodule; + +import java.awt.Dialog; +import java.awt.event.KeyEvent; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.KeyStroke; +import org.openide.windows.WindowManager; + +/** + * This class extends a JDialog and maintains the MultiUserCasesPanel. + */ +public class MultiUserCasesDialog extends JDialog { + private static final String REVIEW_MODE_TITLE = "Open Multi-User Case"; + private final MultiUserCasesPanel multiUserCasesPanel; + private static MultiUserCasesDialog instance; + + /** + * Gets the instance of the MultiuserCasesDialog. + * + * @return The instance. + */ + static public MultiUserCasesDialog getInstance() { + if(instance == null) { + instance = new MultiUserCasesDialog(); + } + return instance; + } + + /** + * Constructs a MultiUserCasesDialog object. + */ + MultiUserCasesDialog() { + super(WindowManager.getDefault().getMainWindow(), + REVIEW_MODE_TITLE, + Dialog.ModalityType.APPLICATION_MODAL); + + getRootPane().registerKeyboardAction( + e -> { + setVisible(false); + }, + KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); + + multiUserCasesPanel = new MultiUserCasesPanel(); + add(multiUserCasesPanel); + pack(); + setResizable(false); + } + + /** + * Set the dialog visibility. When setting it to visible, the contents will + * refresh. + * + * @param value True or false. + */ + @Override + public void setVisible(boolean value) { + if(value) { + multiUserCasesPanel.refreshCasesTable(); + } + super.setVisible(value); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.form new file mode 100755 index 0000000000..179bc23bb8 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.form @@ -0,0 +1,230 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java new file mode 100755 index 0000000000..d905f36c2c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java @@ -0,0 +1,582 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.casemodule; + +import java.awt.Cursor; +import java.awt.Desktop; +import java.awt.EventQueue; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Date; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import javax.swing.JOptionPane; +import javax.swing.SwingWorker; +import javax.swing.event.ListSelectionEvent; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableColumn; +import org.sleuthkit.autopsy.coreutils.CaseStatusIconCellRenderer; +import org.sleuthkit.autopsy.coreutils.GrayableCellRenderer; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.LongDateCellRenderer; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; + +/** + * A panel that allows a user to open cases created by auto ingest. + */ +public class MultiUserCasesPanel extends javax.swing.JPanel { + + private static final long serialVersionUID = 1L; + private static final Logger LOGGER = Logger.getLogger(MultiUserCasesPanel.class.getName()); + private static final String LOG_FILE_NAME = "auto_ingest_log.txt"; + private static final MultiUserCase.LastAccessedDateDescendingComparator REVERSE_DATE_MODIFIED_COMPARATOR = new MultiUserCase.LastAccessedDateDescendingComparator(); + private static final int CASE_COL_MIN_WIDTH = 30; + private static final int CASE_COL_MAX_WIDTH = 2000; + private static final int CASE_COL_PREFERRED_WIDTH = 300; + private static final int TIME_COL_MIN_WIDTH = 40; + private static final int TIME_COL_MAX_WIDTH = 250; + private static final int TIME_COL_PREFERRED_WIDTH = 160; + private static final int STATUS_COL_MIN_WIDTH = 55; + private static final int STATUS_COL_MAX_WIDTH = 250; + private static final int STATUS_COL_PREFERRED_WIDTH = 60; + + /* + * The JTable table model for the cases table presented by this view is + * defined by the following string, enum, and array. + * + * TODO (RC): Consider unifying this stuff in an enum as in + * AutoIngestDashboard to make it less error prone. + */ + private static final String CASE_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.CaseHeaderText"); + private static final String CREATEDTIME_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.CreatedTimeHeaderText"); + private static final String COMPLETEDTIME_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.LastAccessedTimeHeaderText"); + private static final String STATUS_ICON_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.StatusIconHeaderText"); + private static final String OUTPUT_FOLDER_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.OutputFolderHeaderText"); + + enum COLUMN_HEADERS { + + CASE, + CREATEDTIME, + COMPLETEDTIME, + STATUS_ICON, + OUTPUTFOLDER + } + private final String[] columnNames = {CASE_HEADER, CREATEDTIME_HEADER, COMPLETEDTIME_HEADER, STATUS_ICON_HEADER, OUTPUT_FOLDER_HEADER}; + private DefaultTableModel caseTableModel; + private Path currentlySelectedCase = null; + + /** + * Constructs a panel that allows a user to open cases created by automated + * ingest. + */ + MultiUserCasesPanel() { + caseTableModel = new DefaultTableModel(columnNames, 0) { + private static final long serialVersionUID = 1L; + + @Override + public boolean isCellEditable(int row, int column) { + return false; + } + + @Override + public Class getColumnClass(int col) { + if (this.getColumnName(col).equals(CREATEDTIME_HEADER) || this.getColumnName(col).equals(COMPLETEDTIME_HEADER)) { + return Date.class; + } else { + return super.getColumnClass(col); + } + } + }; + + initComponents(); + + /* + * Configure the columns of the cases table. + */ + TableColumn theColumn; + theColumn = casesTable.getColumn(CASE_HEADER); + theColumn.setCellRenderer(new GrayableCellRenderer()); + theColumn.setMinWidth(CASE_COL_MIN_WIDTH); + theColumn.setMaxWidth(CASE_COL_MAX_WIDTH); + theColumn.setPreferredWidth(CASE_COL_PREFERRED_WIDTH); + theColumn.setWidth(CASE_COL_PREFERRED_WIDTH); + + theColumn = casesTable.getColumn(CREATEDTIME_HEADER); + theColumn.setCellRenderer(new LongDateCellRenderer()); + theColumn.setMinWidth(TIME_COL_MIN_WIDTH); + theColumn.setMaxWidth(TIME_COL_MAX_WIDTH); + theColumn.setPreferredWidth(TIME_COL_PREFERRED_WIDTH); + theColumn.setWidth(TIME_COL_PREFERRED_WIDTH); + + theColumn = casesTable.getColumn(COMPLETEDTIME_HEADER); + theColumn.setCellRenderer(new LongDateCellRenderer()); + theColumn.setMinWidth(TIME_COL_MIN_WIDTH); + theColumn.setMaxWidth(TIME_COL_MAX_WIDTH); + theColumn.setPreferredWidth(TIME_COL_PREFERRED_WIDTH); + theColumn.setWidth(TIME_COL_PREFERRED_WIDTH); + + theColumn = casesTable.getColumn(STATUS_ICON_HEADER); + theColumn.setCellRenderer(new CaseStatusIconCellRenderer()); + theColumn.setMinWidth(STATUS_COL_MIN_WIDTH); + theColumn.setMaxWidth(STATUS_COL_MAX_WIDTH); + theColumn.setPreferredWidth(STATUS_COL_PREFERRED_WIDTH); + theColumn.setWidth(STATUS_COL_PREFERRED_WIDTH); + + casesTable.removeColumn(casesTable.getColumn(OUTPUT_FOLDER_HEADER)); + + /* + * Listen for row selection changes and set button state for the current + * selection. + */ + casesTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> { + //Ignore extra messages. + if (e.getValueIsAdjusting()) { + return; + } + setButtons(); + }); + } + + /** + * Gets the list of cases known to the review mode cases manager and + * refreshes the cases table. + */ + void refreshCasesTable() { + EventQueue.invokeLater(() -> { + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + }); + + new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + try { + currentlySelectedCase = getSelectedCase(); + MultiUserCaseManager manager = MultiUserCaseManager.getInstance(); + List cases = manager.getCases(); + cases.sort(REVERSE_DATE_MODIFIED_COMPARATOR); + caseTableModel.setRowCount(0); + long now = new Date().getTime(); + for (MultiUserCase autoIngestCase : cases) { + if (passesTimeFilter(now, autoIngestCase.getLastAccessedDate().getTime())) { + caseTableModel.addRow(new Object[]{ + autoIngestCase.getCaseName(), + autoIngestCase.getCreationDate(), + autoIngestCase.getLastAccessedDate(), + (MultiUserCase.CaseStatus.OK != autoIngestCase.getStatus()), + autoIngestCase.getMetadataFilePath().toString()}); + } + } + setSelectedCase(currentlySelectedCase); + setButtons(); + } catch (Exception ex) { + LOGGER.log(Level.SEVERE, "Unexpected exception while refreshing the table.", ex); //NON-NLS + } + return null; + } + + @Override + protected void done() { + super.done(); + setCursor(null); + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + LOGGER.log(Level.SEVERE, "Unexpected exception while refreshing the table.", ex); //NON-NLS + } + } + }.execute(); + } + + /** + * Gets the current selection in the cases table. + * + * @return A path representing the current selected case, null if there is + * no selection. + */ + private Path getSelectedCase() { + try { + int selectedRow = casesTable.getSelectedRow(); + if (selectedRow >= 0 && selectedRow < casesTable.getRowCount()) { + return Paths.get(caseTableModel.getValueAt(casesTable.convertRowIndexToModel(selectedRow), COLUMN_HEADERS.CASE.ordinal()).toString()); + } + } catch (Exception ignored) { + return null; + } + return null; + } + + /** + * Sets the current selection in the cases table. + * + * @param path The case folder path of the case to select. + */ + private void setSelectedCase(Path path) { + if (path != null) { + try { + for (int row = 0; row < casesTable.getRowCount(); ++row) { + Path temp = Paths.get(caseTableModel.getValueAt(casesTable.convertRowIndexToModel(row), COLUMN_HEADERS.CASE.ordinal()).toString()); + if (temp.compareTo(path) == 0) { // found it + casesTable.setRowSelectionInterval(row, row); + return; + } + } + } catch (Exception ignored) { + casesTable.clearSelection(); + } + } + casesTable.clearSelection(); + } + + /** + * Enables/disables the Open and Show Log buttons based on the case selected + * in the cases table. + */ + private void setButtons() { + boolean openEnabled = casesTable.getSelectedRow() >= 0 && casesTable.getSelectedRow() < casesTable.getRowCount(); + bnOpen.setEnabled(openEnabled); + + Path pathToLog = getSelectedCaseLogFilePath(); + boolean showLogEnabled = openEnabled && pathToLog != null && pathToLog.toFile().exists(); + bnShowLog.setEnabled(showLogEnabled); + } + + /** + * Retrieves the log file path for the selected case in the cases table. + * + * @return The case log path. + */ + private Path getSelectedCaseLogFilePath() { + Path retValue = null; + + int selectedRow = casesTable.getSelectedRow(); + int rowCount = casesTable.getRowCount(); + if (selectedRow >= 0 && selectedRow < rowCount) { + String thePath = (String) caseTableModel.getValueAt(casesTable.convertRowIndexToModel(selectedRow), COLUMN_HEADERS.OUTPUTFOLDER.ordinal()); + retValue = Paths.get(thePath, LOG_FILE_NAME); + } + + return retValue; + } + + /** + * Opens a case. + * + * @param caseMetadataFilePath The path to the case metadata file. + */ + private void openCase(Path caseMetadataFilePath) { + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + try { + StartupWindowProvider.getInstance().close(); + CueBannerPanel.closeMultiUserCasesWindow(); + CaseOpenMultiUserAction.closeMultiUserCasesWindow(); + MultiUserCaseManager.getInstance().openCase(caseMetadataFilePath); + } catch (CaseActionException | MultiUserCaseManager.MultiUserCaseManagerException ex) { + if (null != ex.getCause() && !(ex.getCause() instanceof CaseActionCancelledException)) { + LOGGER.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", caseMetadataFilePath), ex); //NON-NLS + MessageNotifyUtil.Message.error(ex.getCause().getLocalizedMessage()); + } + StartupWindowProvider.getInstance().open(); + } finally { + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } + } + + /** + * Indicates whether or not a time satisfies a time filter defined by this + * panel's time filter radio buttons. + * + * @param currentTime The current date and time in milliseconds from the + * Unix epoch. + * @param inputTime The date and time to be tested as milliseconds from + * the Unix epoch. + */ + private boolean passesTimeFilter(long currentTime, long inputTime) { + long numberOfUnits = 10; + long multiplier = 1; + if (rbAllCases.isSelected()) { + return true; + } else if (rbMonths.isSelected()) { + multiplier = 31; + } else if (rbWeeks.isSelected()) { + multiplier = 7; + } else if (rbDays.isSelected()) { + multiplier = 1; + } + return ((currentTime - inputTime) / (1000 * 60 * 60 * 24)) < (numberOfUnits * multiplier); + } + + /** + * 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() { + + rbGroupHistoryLength = new javax.swing.ButtonGroup(); + bnOpen = new javax.swing.JButton(); + scrollPaneTable = new javax.swing.JScrollPane(); + casesTable = new javax.swing.JTable(); + bnRefresh = new javax.swing.JButton(); + panelFilter = new javax.swing.JPanel(); + rbAllCases = new javax.swing.JRadioButton(); + bnShowLog = new javax.swing.JButton(); + rbDays = new javax.swing.JRadioButton(); + rbWeeks = new javax.swing.JRadioButton(); + rbMonths = new javax.swing.JRadioButton(); + rbGroupLabel = new javax.swing.JLabel(); + + setName("Completed Cases"); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(bnOpen, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnOpen.text")); // NOI18N + bnOpen.setEnabled(false); + bnOpen.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnOpenActionPerformed(evt); + } + }); + + casesTable.setAutoCreateRowSorter(true); + casesTable.setModel(caseTableModel); + casesTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS); + casesTable.setRowHeight(20); + casesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); + casesTable.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + casesTableMouseClicked(evt); + } + }); + scrollPaneTable.setViewportView(casesTable); + + org.openide.awt.Mnemonics.setLocalizedText(bnRefresh, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnRefresh.text")); // NOI18N + bnRefresh.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnRefreshActionPerformed(evt); + } + }); + + rbGroupHistoryLength.add(rbAllCases); + rbAllCases.setSelected(true); + org.openide.awt.Mnemonics.setLocalizedText(rbAllCases, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbAllCases.text")); // NOI18N + rbAllCases.addItemListener(new java.awt.event.ItemListener() { + public void itemStateChanged(java.awt.event.ItemEvent evt) { + rbAllCasesItemStateChanged(evt); + } + }); + + javax.swing.GroupLayout panelFilterLayout = new javax.swing.GroupLayout(panelFilter); + panelFilter.setLayout(panelFilterLayout); + panelFilterLayout.setHorizontalGroup( + panelFilterLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelFilterLayout.createSequentialGroup() + .addComponent(rbAllCases) + .addGap(0, 0, Short.MAX_VALUE)) + ); + panelFilterLayout.setVerticalGroup( + panelFilterLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, panelFilterLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(rbAllCases)) + ); + + org.openide.awt.Mnemonics.setLocalizedText(bnShowLog, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnShowLog.text")); // NOI18N + bnShowLog.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnShowLog.toolTipText")); // NOI18N + bnShowLog.setEnabled(false); + bnShowLog.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnShowLogActionPerformed(evt); + } + }); + + rbGroupHistoryLength.add(rbDays); + org.openide.awt.Mnemonics.setLocalizedText(rbDays, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbDays.text")); // NOI18N + rbDays.setName(""); // NOI18N + rbDays.addItemListener(new java.awt.event.ItemListener() { + public void itemStateChanged(java.awt.event.ItemEvent evt) { + rbDaysItemStateChanged(evt); + } + }); + + rbGroupHistoryLength.add(rbWeeks); + org.openide.awt.Mnemonics.setLocalizedText(rbWeeks, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbWeeks.text")); // NOI18N + rbWeeks.addItemListener(new java.awt.event.ItemListener() { + public void itemStateChanged(java.awt.event.ItemEvent evt) { + rbWeeksItemStateChanged(evt); + } + }); + + rbGroupHistoryLength.add(rbMonths); + org.openide.awt.Mnemonics.setLocalizedText(rbMonths, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbMonths.text")); // NOI18N + rbMonths.addItemListener(new java.awt.event.ItemListener() { + public void itemStateChanged(java.awt.event.ItemEvent evt) { + rbMonthsItemStateChanged(evt); + } + }); + + rbGroupLabel.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbGroupLabel, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbGroupLabel.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(4, 4, 4) + .addComponent(bnOpen, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bnShowLog) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(rbGroupLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(rbDays) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(rbWeeks) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(rbMonths) + .addGap(0, 0, 0) + .addComponent(panelFilter, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(bnRefresh) + .addGap(4, 4, 4)) + .addComponent(scrollPaneTable)) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(6, 6, 6) + .addComponent(scrollPaneTable, javax.swing.GroupLayout.PREFERRED_SIZE, 450, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(bnOpen) + .addComponent(bnShowLog)) + .addComponent(bnRefresh) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(rbDays) + .addComponent(rbWeeks) + .addComponent(rbMonths) + .addComponent(rbGroupLabel)) + .addComponent(panelFilter, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGap(0, 0, 0)) + ); + }// //GEN-END:initComponents + + /** + * Open button action + * + * @param evt -- The event that caused this to be called + */ + private void bnOpenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOpenActionPerformed + int modelRow = casesTable.convertRowIndexToModel(casesTable.getSelectedRow()); + Path caseMetadataFilePath = Paths.get((String) caseTableModel.getValueAt(modelRow, + COLUMN_HEADERS.OUTPUTFOLDER.ordinal())); + + new Thread(() -> { + openCase(caseMetadataFilePath); + }).start(); + }//GEN-LAST:event_bnOpenActionPerformed + + /** + * Refresh button action + * + * @param evt -- The event that caused this to be called + */ + private void bnRefreshActionPerformed(java.awt.event.ActionEvent evt) { + refreshCasesTable(); + } + + private void rbDaysItemStateChanged(java.awt.event.ItemEvent evt) { + if (rbDays.isSelected()) { + refreshCasesTable(); + } + } + + private void rbAllCasesItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbAllCasesItemStateChanged + if (rbAllCases.isSelected()) { + refreshCasesTable(); + } + }//GEN-LAST:event_rbAllCasesItemStateChanged + + private void rbMonthsItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbMonthsItemStateChanged + if (rbMonths.isSelected()) { + refreshCasesTable(); + } + }//GEN-LAST:event_rbMonthsItemStateChanged + + private void rbWeeksItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbWeeksItemStateChanged + if (rbWeeks.isSelected()) { + refreshCasesTable(); + } + }//GEN-LAST:event_rbWeeksItemStateChanged + + private void bnShowLogActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnShowLogActionPerformed + Path pathToLog = getSelectedCaseLogFilePath(); + if (pathToLog != null) { + try { + if (pathToLog.toFile().exists()) { + Desktop.getDesktop().edit(pathToLog.toFile()); + + } else { + JOptionPane.showMessageDialog(this, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.cannotFindLog"), + org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.unableToShowLogFile"), JOptionPane.ERROR_MESSAGE); + } + } catch (IOException ex) { + LOGGER.log(Level.SEVERE, String.format("Error attempting to open case auto ingest log file %s", pathToLog), ex); + JOptionPane.showMessageDialog(this, + org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.cannotOpenLog"), + org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.unableToShowLogFile"), + JOptionPane.PLAIN_MESSAGE); + } + } + }//GEN-LAST:event_bnShowLogActionPerformed + + private void casesTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_casesTableMouseClicked + if (evt.getClickCount() == 2) { + int modelRow = casesTable.convertRowIndexToModel(casesTable.getSelectedRow()); + Path caseMetadataFilePath = Paths.get((String) caseTableModel.getValueAt(modelRow, + COLUMN_HEADERS.OUTPUTFOLDER.ordinal())); + openCase(caseMetadataFilePath); + } + }//GEN-LAST:event_casesTableMouseClicked + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton bnOpen; + private javax.swing.JButton bnRefresh; + private javax.swing.JButton bnShowLog; + private javax.swing.JTable casesTable; + private javax.swing.JPanel panelFilter; + private javax.swing.JRadioButton rbAllCases; + private javax.swing.JRadioButton rbDays; + private javax.swing.ButtonGroup rbGroupHistoryLength; + private javax.swing.JLabel rbGroupLabel; + private javax.swing.JRadioButton rbMonths; + private javax.swing.JRadioButton rbWeeks; + private javax.swing.JScrollPane scrollPaneTable; + // End of variables declaration//GEN-END:variables + +} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.form new file mode 100755 index 0000000000..49e700ca21 --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.form @@ -0,0 +1,113 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java new file mode 100755 index 0000000000..5502bcb5d5 --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java @@ -0,0 +1,178 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.experimental.autoingest; + +import com.github.lgooddatepicker.datepicker.DatePicker; +import java.awt.Container; +import java.awt.Cursor; +import java.awt.Window; +import java.sql.Date; +import java.text.SimpleDateFormat; +import java.time.ZoneOffset; +import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; + +/** + * Display basic metrics for a cluster. + */ +public class AutoIngestMetricsDialog extends javax.swing.JDialog { + + private final AutoIngestMonitor autoIngestMonitor; + + /** + * Creates new form AutoIngestMetricsDialog + * + * @param parent The parent container. + * @param autoIngestMonitor The auto ingest monitor. + */ + @Messages({ + "AutoIngestMetricsDialog.title.text=Auto Ingest Cluster Metrics", + "AutoIngestMetricsDialog.initReportText=Select a date below and click the 'Get Metrics Since...' button to generate\na metrics report." + }) + public AutoIngestMetricsDialog(Container parent, AutoIngestMonitor autoIngestMonitor) { + super((Window) parent, NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.title.text"), ModalityType.MODELESS); + initComponents(); + reportTextArea.setText(NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.initReportText")); + this.autoIngestMonitor = autoIngestMonitor; + setModal(true); + setSize(getPreferredSize()); + setLocationRelativeTo(parent); + setVisible(true); + } + + /** + * Update the metrics shown in the report text area. + */ + private void updateMetrics() { + if(datePicker.getDate() == null) { + return; + } + + AutoIngestMonitor.MetricsSnapshot metricsSnapshot = autoIngestMonitor.getMetricsSnapshot(); + Object[] completedJobDates = metricsSnapshot.getCompletedJobDates().toArray(); + int count = 0; + long pickedDate = datePicker.getDate().atStartOfDay().toEpochSecond(ZoneOffset.UTC) * 1000; + for(int i = completedJobDates.length - 1; i >= 0; i--) { + if((Long)completedJobDates[i] >= pickedDate) { + count++; + } + } + + SimpleDateFormat dateFormatter = new SimpleDateFormat("MMM d, yyyy"); + reportTextArea.setText(String.format( + "Since %s:\n" + + "\tNumber of Jobs Completed: %d\n", + dateFormatter.format(Date.valueOf(datePicker.getDate())), + count + )); + } + + /** + * 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() { + + closeButton = new javax.swing.JButton(); + jScrollPane1 = new javax.swing.JScrollPane(); + reportTextArea = new javax.swing.JTextArea(); + metricsButton = new javax.swing.JButton(); + datePicker = new DatePicker(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setAlwaysOnTop(true); + setResizable(false); + + org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.closeButton.text")); // NOI18N + closeButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + closeButtonActionPerformed(evt); + } + }); + + reportTextArea.setEditable(false); + reportTextArea.setColumns(20); + reportTextArea.setRows(5); + reportTextArea.setText(org.openide.util.NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.reportTextArea.text")); // NOI18N + jScrollPane1.setViewportView(reportTextArea); + + org.openide.awt.Mnemonics.setLocalizedText(metricsButton, org.openide.util.NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.metricsButton.text")); // NOI18N + metricsButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + metricsButtonActionPerformed(evt); + } + }); + + datePicker.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.datePicker.toolTipText")); // NOI18N + + 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) + .addComponent(jScrollPane1) + .addGroup(layout.createSequentialGroup() + .addComponent(metricsButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(datePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 33, Short.MAX_VALUE) + .addComponent(closeButton, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 128, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(closeButton) + .addComponent(metricsButton)) + .addComponent(datePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + + private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed + setVisible(false); + dispose(); + }//GEN-LAST:event_closeButtonActionPerformed + + private void metricsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_metricsButtonActionPerformed + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + updateMetrics(); + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + }//GEN-LAST:event_metricsButtonActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton closeButton; + private com.github.lgooddatepicker.datepicker.DatePicker datePicker; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JButton metricsButton; + private javax.swing.JTextArea reportTextArea; + // End of variables declaration//GEN-END:variables +} From 9ae63a7d8d722c0ee871c02db2c8e5d83a533cc8 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 3 Nov 2017 17:01:55 -0400 Subject: [PATCH 052/115] Removed unnecessary method. --- .../sleuthkit/autopsy/casemodule/CaseMetadata.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index 3757814aa9..6e47363db5 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -175,17 +175,6 @@ public final class CaseMetadata { public String getCaseDirectory() { return metadataFilePath.getParent().toString(); } - - /** - * Gets the full case directory path. - * - * @return The case directory path. - */ - public String getCaseDirectoryPath() { - String fileName = metadataFilePath.getFileName().toString(); - String caseDirectoryPath = metadataFilePath.toString(); - return caseDirectoryPath.substring(0, caseDirectoryPath.lastIndexOf(fileName)); - } /** * Gets the case type. From 0f0efd6ef0155e95739a8ad74f7df5e5094ba548 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 3 Nov 2017 17:03:55 -0400 Subject: [PATCH 053/115] Removed MultIuserCase class. --- .../autopsy/casemodule/MultiUserCase.java | 290 ------------------ 1 file changed, 290 deletions(-) delete mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java deleted file mode 100755 index 8ecc1c91e2..0000000000 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCase.java +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015-2017 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.casemodule; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Comparator; -import java.util.Date; -import java.util.Objects; -import java.util.logging.Level; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.TimeStampUtils; - -/** - * A representation of a case created by automated ingest. - */ -class MultiUserCase implements Comparable { - - private static final Logger logger = Logger.getLogger(MultiUserCase.class.getName()); - private final Path caseDirectoryPath; - private final String caseName; - private final Path metadataFilePath; - private final Date createDate; - private final Date lastAccessedDate; - - /** - * Constructs a representation of case created by automated ingest. - * - * @param caseDirectoryPath The case directory path. - * - * @throws CaseMetadata.CaseMetadataException If the CaseMetadata object - * cannot be constructed for the - * case display name. - * @throws MultiUserCaseException If no case metadata (.aut) - * file is found in the case - * directory. - */ - MultiUserCase(Path caseDirectoryPath) throws CaseMetadata.CaseMetadataException, MultiUserCaseException { - CaseMetadata caseMetadata = null; - - try { - caseMetadata = getCaseMetadataFromCaseDirectoryPath(caseDirectoryPath); - } catch (CaseMetadata.CaseMetadataException ex) { - logger.log(Level.SEVERE, String.format("Error reading the case metadata for %s.", caseDirectoryPath), ex); - throw ex; - } - - this.caseDirectoryPath = caseDirectoryPath; - caseName = caseMetadata.getCaseDisplayName(); - metadataFilePath = caseMetadata.getFilePath(); - BasicFileAttributes fileAttrs = null; - try { - fileAttrs = Files.readAttributes(metadataFilePath, BasicFileAttributes.class); - } catch (IOException ex) { - logger.log(Level.SEVERE, String.format("Error reading file attributes of case metadata file in %s, will use current time for case createDate/lastModfiedDate", caseDirectoryPath), ex); - } - if (null != fileAttrs) { - createDate = new Date(fileAttrs.creationTime().toMillis()); - lastAccessedDate = new Date(fileAttrs.lastAccessTime().toMillis()); - } else { - createDate = new Date(); - lastAccessedDate = new Date(); - } - } - - /** - * Gets the case directory path. - * - * @return The case directory path. - */ - Path getCaseDirectoryPath() { - return this.caseDirectoryPath; - } - - /** - * Gets the case name. - * - * @return The case name. - */ - String getCaseName() { - return this.caseName; - } - - /** - * Gets the creation date for the case, defined as the create time of the - * case metadata file. - * - * @return The case creation date. - */ - Date getCreationDate() { - return this.createDate; - } - - /** - * Gets the last accessed date for the case, defined as the last accessed - * time of the case metadata file. - * - * @return The last accessed date. - */ - Date getLastAccessedDate() { - return this.lastAccessedDate; - } - - /** - * Gets the full path of the metadata (.aut) file. - * - * @return The metadata file path. - */ - Path getMetadataFilePath() { - return this.metadataFilePath; - } - - /** - * Gets the status of this case based on the auto ingest result file in the - * case directory. - * - * @return See CaseStatus enum definition. - */ - CaseStatus getStatus() { - if(caseDirectoryPath.resolve("autoingest.alert").toFile().exists()) { - return CaseStatus.ALERT; - } else { - return CaseStatus.OK; - } - } - - /** - * Gets the case metadata from a case directory path. - * - * @param caseDirectoryPath The case directory path. - * - * @return Case metadata. - * - * @throws CaseMetadata.CaseMetadataException If the CaseMetadata object - * cannot be constructed. - * @throws MultiUserCaseException If no case metadata (.aut) - * file is found in the case - * directory. - */ - private static CaseMetadata getCaseMetadataFromCaseDirectoryPath(Path caseDirectoryPath) throws CaseMetadata.CaseMetadataException, MultiUserCaseException { - CaseMetadata caseMetadata = null; - - File directory = new File(caseDirectoryPath.toString()); - if (directory.isDirectory()) { - String fileNamePrefix = directory.getName(); - if (TimeStampUtils.endsWithTimeStamp(fileNamePrefix)) { - fileNamePrefix = fileNamePrefix.substring(0, fileNamePrefix.length() - TimeStampUtils.getTimeStampLength()); - } - - File autFile = null; - - /* - * Attempt to find an AUT file via a directory scan. - */ - for (File file : directory.listFiles()) { - if (file.getName().toLowerCase().endsWith(CaseMetadata.getFileExtension()) && file.isFile()) { - autFile = file; - break; - } - } - - if(autFile == null || !autFile.isFile()) { - throw new MultiUserCaseException(String.format("No case metadata (.aut) file found in the case directory '%s'.", caseDirectoryPath.toString())); - } - - caseMetadata = new CaseMetadata(Paths.get(autFile.getAbsolutePath())); - } - - return caseMetadata; - } - - /** - * Indicates whether or not some other object is "equal to" this - * MultiUserCase object. - * - * @param other The other object. - * - * @return True or false. - */ - @Override - public boolean equals(Object other) { - if (!(other instanceof MultiUserCase)) { - return false; - } - if (other == this) { - return true; - } - return this.caseDirectoryPath.toString().equals(((MultiUserCase) other).caseDirectoryPath.toString()); - } - - /** - * Returns a hash code value for this MultiUserCase object. - * - * @return The has code. - */ - @Override - public int hashCode() { - int hash = 7; - hash = 71 * hash + Objects.hashCode(this.caseDirectoryPath); - hash = 71 * hash + Objects.hashCode(this.createDate); - hash = 71 * hash + Objects.hashCode(this.caseName); - return hash; - } - - /** - * Compares this AutopIngestCase object with abnother MultiUserCase object - * for order. - */ - @Override - public int compareTo(MultiUserCase other) { - return -this.lastAccessedDate.compareTo(other.getLastAccessedDate()); - } - - /** - * Comparator for a descending order sort on date created. - */ - static class LastAccessedDateDescendingComparator implements Comparator { - - /** - * Compares two MultiUserCase objects for order based on last accessed - * date (descending). - * - * @param object The first MultiUserCase object - * @param otherObject The second AuotIngestCase object. - * - * @return A negative integer, zero, or a positive integer as the first - * argument is less than, equal to, or greater than the second. - */ - @Override - public int compare(MultiUserCase object, MultiUserCase otherObject) { - return -object.getLastAccessedDate().compareTo(otherObject.getLastAccessedDate()); - } - } - - /** - * Exception thrown when there is a problem creating a multi-user case. - */ - final static class MultiUserCaseException extends Exception { - - private static final long serialVersionUID = 1L; - - /** - * Constructs an exception to throw when there is a problem creating a - * multi-user case. - * - * @param message The exception message. - */ - private MultiUserCaseException(String message) { - super(message); - } - - /** - * Constructs an exception to throw when there is a problem creating a - * multi-user case. - * - * @param message The exception message. - * @param cause The cause of the exception, if it was an exception. - */ - private MultiUserCaseException(String message, Throwable cause) { - super(message, cause); - } - } - - enum CaseStatus { - - OK, - ALERT - } - -} From e793197ec5ec0f2069418a23451725247ee790f5 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 3 Nov 2017 17:05:42 -0400 Subject: [PATCH 054/115] Fixed Java Doc text. --- .../org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java index 589b283d62..7e87ce8947 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java @@ -266,9 +266,9 @@ final class MultiUserCasesPanel extends javax.swing.JPanel { } /** - * Retrieves the log file path for the selected case in the cases table. + * Open a case. * - * @return The case log path. + * @param caseMetadataFilePath The path to the case metadata file. */ private void openCase(Path caseMetadataFilePath) { setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); From 3fab3fdc8bc350d57640890cdc912115b544c233 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 3 Nov 2017 17:13:35 -0400 Subject: [PATCH 055/115] Rolled back Installer to previous content. --- .../autopsy/corecomponents/Installer.java | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java b/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java index 060061e205..c908f3b35d 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java @@ -30,10 +30,7 @@ import org.netbeans.swing.tabcontrol.plaf.DefaultTabbedContainerUI; import org.openide.modules.ModuleInstall; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.StartupWindowProvider; -import org.sleuthkit.autopsy.core.UserPreferences; -import static org.sleuthkit.autopsy.core.UserPreferences.SETTINGS_PROPERTIES; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.ModuleSettings; /** * Manages this module's life cycle. Opens the startup dialog during startup. @@ -62,7 +59,6 @@ public class Installer extends ModuleInstall { UIManager.put("ViewTabDisplayerUI", "org.sleuthkit.autopsy.corecomponents.NoTabsTabDisplayerUI"); UIManager.put(DefaultTabbedContainerUI.KEY_VIEW_CONTENT_BORDER, BorderFactory.createEmptyBorder()); UIManager.put("TabbedPane.contentBorderInsets", new Insets(0, 0, 0, 0)); - updateConfig(); WindowManager.getDefault().invokeWhenUIReady(() -> { StartupWindowProvider.getInstance().open(); }); @@ -72,21 +68,6 @@ public class Installer extends ModuleInstall { public void uninstalled() { super.uninstalled(); } - - /** - * If the mode in the configuration file is 'REVIEW' (2, now invalid), this - * method will set it to 'STANDALONE' (0) and disable auto ingest. - */ - private void updateConfig() { - String mode = ModuleSettings.getConfigSetting(SETTINGS_PROPERTIES, "AutopsyMode"); - if(mode != null) { - int ordinal = Integer.parseInt(mode); - if(ordinal > 1) { - UserPreferences.setMode(UserPreferences.SelectedMode.STANDALONE); - ModuleSettings.setConfigSetting(UserPreferences.SETTINGS_PROPERTIES, "JoinAutoModeCluster", Boolean.toString(false)); - } - } - } private void setLookAndFeel() { if (System.getProperty("os.name").toLowerCase().contains("mac")) { //NON-NLS From 4bd750ef1039cc4618d23b7dc448fe95167c3851 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 3 Nov 2017 17:21:23 -0400 Subject: [PATCH 056/115] Permission change. --- .../autopsy/centralrepository/datamodel/AbstractSqlEamDb.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java old mode 100755 new mode 100644 From 1267234bb2715e53afdff48b1ffcf58856347a70 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 3 Nov 2017 17:24:30 -0400 Subject: [PATCH 057/115] Permissions change. --- .../org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java | 0 .../autopsy/centralrepository/datamodel/SqliteEamDb.java | 0 .../centralrepository/eventlisteners/CaseEventListener.java | 0 .../centralrepository/eventlisteners/IngestEventsListener.java | 0 .../autopsy/centralrepository/ingestmodule/IngestModule.java | 0 Core/src/org/sleuthkit/autopsy/core/timelineWsmode.xml | 0 .../sleuthkit/autopsy/directorytree/FileSystemDetailsAction.java | 0 7 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java mode change 100755 => 100644 Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java mode change 100755 => 100644 Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java mode change 100755 => 100644 Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java mode change 100755 => 100644 Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java mode change 100755 => 100644 Core/src/org/sleuthkit/autopsy/core/timelineWsmode.xml mode change 100755 => 100644 Core/src/org/sleuthkit/autopsy/directorytree/FileSystemDetailsAction.java diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java old mode 100755 new mode 100644 diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java old mode 100755 new mode 100644 diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java old mode 100755 new mode 100644 diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java old mode 100755 new mode 100644 diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java old mode 100755 new mode 100644 diff --git a/Core/src/org/sleuthkit/autopsy/core/timelineWsmode.xml b/Core/src/org/sleuthkit/autopsy/core/timelineWsmode.xml old mode 100755 new mode 100644 diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/FileSystemDetailsAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/FileSystemDetailsAction.java old mode 100755 new mode 100644 From d6af30faf22c6ae36bfaa3c3a073795661706e38 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 3 Nov 2017 17:28:14 -0400 Subject: [PATCH 058/115] Switched auto ingest metrics dialog from public. --- .../experimental/autoingest/AutoIngestMetricsDialog.java | 2 +- .../autopsy/experimental/autoingest/dashboardWsmode.xml | 0 2 files changed, 1 insertion(+), 1 deletion(-) mode change 100755 => 100644 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/dashboardWsmode.xml diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java index 5502bcb5d5..1acb72f005 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java @@ -31,7 +31,7 @@ import org.openide.util.NbBundle.Messages; /** * Display basic metrics for a cluster. */ -public class AutoIngestMetricsDialog extends javax.swing.JDialog { +class AutoIngestMetricsDialog extends javax.swing.JDialog { private final AutoIngestMonitor autoIngestMonitor; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/dashboardWsmode.xml b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/dashboardWsmode.xml old mode 100755 new mode 100644 From 4c44a79477f97452b3ad276ffc0451744ac96412 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 3 Nov 2017 17:40:56 -0400 Subject: [PATCH 059/115] Minor revisions. --- .../autoingest/AutoIngestMetricsDialog.java | 4 ++-- .../experimental/autoingest/AutoIngestMonitor.java | 12 +++++------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java index 1acb72f005..66c6d28581 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java @@ -31,7 +31,7 @@ import org.openide.util.NbBundle.Messages; /** * Display basic metrics for a cluster. */ -class AutoIngestMetricsDialog extends javax.swing.JDialog { +final class AutoIngestMetricsDialog extends javax.swing.JDialog { private final AutoIngestMonitor autoIngestMonitor; @@ -45,7 +45,7 @@ class AutoIngestMetricsDialog extends javax.swing.JDialog { "AutoIngestMetricsDialog.title.text=Auto Ingest Cluster Metrics", "AutoIngestMetricsDialog.initReportText=Select a date below and click the 'Get Metrics Since...' button to generate\na metrics report." }) - public AutoIngestMetricsDialog(Container parent, AutoIngestMonitor autoIngestMonitor) { + AutoIngestMetricsDialog(Container parent, AutoIngestMonitor autoIngestMonitor) { super((Window) parent, NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.title.text"), ModalityType.MODELESS); initComponents(); reportTextArea.setText(NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.initReportText")); diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java index 09f0c7c949..02ad08e4ee 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java @@ -290,7 +290,6 @@ public final class AutoIngestMonitor extends Observable implements PropertyChang */ private MetricsSnapshot queryCoordinationServiceForMetrics() { try { - JobsSnapshot newJobsSnapshot = new JobsSnapshot(); MetricsSnapshot newMetricsSnapshot = new MetricsSnapshot(); List nodeList = coordinationService.getNodeList(CoordinationService.CategoryNode.MANIFESTS); for (String node : nodeList) { @@ -307,17 +306,16 @@ public final class AutoIngestMonitor extends Observable implements PropertyChang ProcessingStatus processingStatus = nodeData.getProcessingStatus(); switch (processingStatus) { case PENDING: - newJobsSnapshot.addOrReplacePendingJob(job); - break; case PROCESSING: - newJobsSnapshot.addOrReplaceRunningJob(job); + case DELETED: + /* + * These are not jobs we care about for metrics, so + * we will ignore them. + */ break; case COMPLETED: - newJobsSnapshot.addOrReplaceCompletedJob(job); newMetricsSnapshot.addCompletedJobDate(job.getCompletedDate()); break; - case DELETED: - break; default: LOGGER.log(Level.SEVERE, "Unknown AutoIngestJobData.ProcessingStatus"); break; From 06fa96f6cc3e817b2a764f9d71cfabd9de6361da Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 3 Nov 2017 17:43:12 -0400 Subject: [PATCH 060/115] Minor revision. --- .../autopsy/experimental/autoingest/AutoIngestMonitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java index 02ad08e4ee..d6ec19d48b 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java @@ -284,7 +284,7 @@ public final class AutoIngestMonitor extends Observable implements PropertyChang /** * Gets a new metrics snapshot from the coordination service for an auto - * ingest cluster. The jobs snapshot will also be updated. + * ingest cluster. * * @return The metrics snapshot. */ From 2bc4a03f0aa242e44aa3a30f6d8ddc79853dbd7f Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Fri, 3 Nov 2017 17:46:10 -0400 Subject: [PATCH 061/115] 3180: correct typo --- ...ntestFileFiltersTest.java => IngestFileFiltersTest.java} | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) rename Core/test/unit/src/org/sleuthkit/autopsy/ingest/{IntestFileFiltersTest.java => IngestFileFiltersTest.java} (88%) diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/ingest/IntestFileFiltersTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java similarity index 88% rename from Core/test/unit/src/org/sleuthkit/autopsy/ingest/IntestFileFiltersTest.java rename to Core/test/unit/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java index b952462de8..4dbec8bdc8 100755 --- a/Core/test/unit/src/org/sleuthkit/autopsy/ingest/IntestFileFiltersTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java @@ -22,10 +22,11 @@ import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import org.openide.modules.Places; -public class IntestFileFiltersTest { +public class IngestFileFiltersTest { - public IntestFileFiltersTest() { + public IngestFileFiltersTest() { } @BeforeClass @@ -46,6 +47,7 @@ public class IntestFileFiltersTest { @Test public void testFilters() { + Places.getUserDirectory().getAbsoluteFile(); System.out.println("Test filter"); } } From 21da396cf5eed08e3ee4487feb4994c8ff93181b Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 3 Nov 2017 18:03:13 -0400 Subject: [PATCH 062/115] Permission changes. --- .../experimental/autoingest/AutoIngestMonitor.java | 10 ++-------- .../autopsy/imagegallery/ImageGalleryWsmode.xml | 0 .../org/sleuthkit/autopsy/imagegallery/layer.xml | 0 .../autopsy/keywordsearch/CreditCardValidator.java | 0 .../keywordsearch/CreditCardValidatorTest.java | 0 docs/doxygen-user/central_repo.dox | 0 .../images/central_repo_content_viewer.png | Bin .../images/central_repo_interesting_items.png | Bin .../images/central_repo_manage_tags.png | Bin docs/doxygen-user/images/central_repo_options.png | Bin docs/doxygen-user/images/central_repo_postgres.png | Bin docs/doxygen-user/images/central_repo_sqlite.png | Bin docs/doxygen-user/images/central_repo_tag_file.png | Bin docs/doxygen-user/images/central_repo_types.png | Bin docs/doxygen-user/images/email_datasource_tree.png | Bin .../images/messages_datasource_tree.png | Bin ruleset.xml | 0 17 files changed, 2 insertions(+), 8 deletions(-) mode change 100755 => 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryWsmode.xml mode change 100755 => 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/layer.xml mode change 100755 => 100644 KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/CreditCardValidator.java mode change 100755 => 100644 KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/CreditCardValidatorTest.java mode change 100755 => 100644 docs/doxygen-user/central_repo.dox mode change 100755 => 100644 docs/doxygen-user/images/central_repo_content_viewer.png mode change 100755 => 100644 docs/doxygen-user/images/central_repo_interesting_items.png mode change 100755 => 100644 docs/doxygen-user/images/central_repo_manage_tags.png mode change 100755 => 100644 docs/doxygen-user/images/central_repo_options.png mode change 100755 => 100644 docs/doxygen-user/images/central_repo_postgres.png mode change 100755 => 100644 docs/doxygen-user/images/central_repo_sqlite.png mode change 100755 => 100644 docs/doxygen-user/images/central_repo_tag_file.png mode change 100755 => 100644 docs/doxygen-user/images/central_repo_types.png mode change 100755 => 100644 docs/doxygen-user/images/email_datasource_tree.png mode change 100755 => 100644 docs/doxygen-user/images/messages_datasource_tree.png mode change 100755 => 100644 ruleset.xml diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java index d6ec19d48b..37c635b9f0 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java @@ -45,7 +45,7 @@ import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJob.ProcessingSta * An auto ingest monitor responsible for monitoring and reporting the * processing of auto ingest jobs. */ -public final class AutoIngestMonitor extends Observable implements PropertyChangeListener { +final class AutoIngestMonitor extends Observable implements PropertyChangeListener { private static final Logger LOGGER = Logger.getLogger(AutoIngestMonitor.class.getName()); private static final int NUM_COORD_SVC_QUERY_THREADS = 1; @@ -344,13 +344,7 @@ public final class AutoIngestMonitor extends Observable implements PropertyChang * @return The metrics snapshot. */ public MetricsSnapshot getMetricsSnapshot() { - MetricsSnapshot metricsSnapshot; - - synchronized (jobsLock) { - metricsSnapshot = queryCoordinationServiceForMetrics(); - } - - return metricsSnapshot; + return queryCoordinationServiceForMetrics(); } /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryWsmode.xml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryWsmode.xml old mode 100755 new mode 100644 diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/layer.xml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/layer.xml old mode 100755 new mode 100644 diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/CreditCardValidator.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/CreditCardValidator.java old mode 100755 new mode 100644 diff --git a/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/CreditCardValidatorTest.java b/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/CreditCardValidatorTest.java old mode 100755 new mode 100644 diff --git a/docs/doxygen-user/central_repo.dox b/docs/doxygen-user/central_repo.dox old mode 100755 new mode 100644 diff --git a/docs/doxygen-user/images/central_repo_content_viewer.png b/docs/doxygen-user/images/central_repo_content_viewer.png old mode 100755 new mode 100644 diff --git a/docs/doxygen-user/images/central_repo_interesting_items.png b/docs/doxygen-user/images/central_repo_interesting_items.png old mode 100755 new mode 100644 diff --git a/docs/doxygen-user/images/central_repo_manage_tags.png b/docs/doxygen-user/images/central_repo_manage_tags.png old mode 100755 new mode 100644 diff --git a/docs/doxygen-user/images/central_repo_options.png b/docs/doxygen-user/images/central_repo_options.png old mode 100755 new mode 100644 diff --git a/docs/doxygen-user/images/central_repo_postgres.png b/docs/doxygen-user/images/central_repo_postgres.png old mode 100755 new mode 100644 diff --git a/docs/doxygen-user/images/central_repo_sqlite.png b/docs/doxygen-user/images/central_repo_sqlite.png old mode 100755 new mode 100644 diff --git a/docs/doxygen-user/images/central_repo_tag_file.png b/docs/doxygen-user/images/central_repo_tag_file.png old mode 100755 new mode 100644 diff --git a/docs/doxygen-user/images/central_repo_types.png b/docs/doxygen-user/images/central_repo_types.png old mode 100755 new mode 100644 diff --git a/docs/doxygen-user/images/email_datasource_tree.png b/docs/doxygen-user/images/email_datasource_tree.png old mode 100755 new mode 100644 diff --git a/docs/doxygen-user/images/messages_datasource_tree.png b/docs/doxygen-user/images/messages_datasource_tree.png old mode 100755 new mode 100644 diff --git a/ruleset.xml b/ruleset.xml old mode 100755 new mode 100644 From c95fa28c4942da407a0596310df80a6c929eab5c Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Mon, 6 Nov 2017 13:03:28 -0500 Subject: [PATCH 063/115] Tracking auto ingest alerts via case nodes. --- .../autoingest/AutoIngestAlertFile.java | 108 ---------- .../autoingest/AutoIngestManager.java | 202 ++++++++++-------- 2 files changed, 111 insertions(+), 199 deletions(-) delete mode 100755 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestAlertFile.java diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestAlertFile.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestAlertFile.java deleted file mode 100755 index 40fff351eb..0000000000 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestAlertFile.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015 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.experimental.autoingest; - -import java.io.IOException; -import java.nio.file.FileAlreadyExistsException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.logging.Level; - -/** - * Utility for creating and checking for the existence of an automated ingest - * alert file. The purpose of the file is to put a marker in the case directory - * when an error or warning occurs in connection with an automated ingest job. - */ -final class AutoIngestAlertFile { - - private static final String ERROR_FILE_NAME = "autoingest.alert"; - - /** - * Checks whether an automated ingest alert file exists in a case directory. - * - * @param caseDirectoryPath The case directory path. - * - * @return True or false. - */ - static boolean exists(Path caseDirectoryPath) { - return caseDirectoryPath.resolve(ERROR_FILE_NAME).toFile().exists(); - } - - /** - * Creates an automated ingest alert file in a case directory if such a file - * does not already exist. - * - * @param caseDirectoryPath The case directory path. - * - * @return True or false. - */ - static void create(Path caseDirectoryPath) throws AutoIngestAlertFileException { - try { - Files.createFile(caseDirectoryPath.resolve(ERROR_FILE_NAME)); - } catch (FileAlreadyExistsException ignored) { - /* - * The file already exists, the exception is not exceptional. - */ - } catch (IOException ex) { - /* - * FileAlreadyExistsException implementation is optional, so check - * for that case. - */ - if (!exists(caseDirectoryPath)) { - throw new AutoIngestAlertFileException(String.format("Error creating automated ingest alert file in %s", caseDirectoryPath), ex); - } - } - } - - /** - * Exception thrown when there is a problem creating an alert file. - */ - final static class AutoIngestAlertFileException extends Exception { - - private static final long serialVersionUID = 1L; - - /** - * Constructs an exception to throw when there is a problem creating an - * alert file. - * - * @param message The exception message. - */ - private AutoIngestAlertFileException(String message) { - super(message); - } - - /** - * Constructs an exception to throw when there is a problem creating an - * alert file. - * - * @param message The exception message. - * @param cause The cause of the exception, if it was an exception. - */ - private AutoIngestAlertFileException(String message, Throwable cause) { - super(message, cause); - } - } - - /** - * Prevents instantiation of this utility class. - */ - private AutoIngestAlertFile() { - } - -} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index b621cb514f..a0168cd9ee 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -64,6 +64,7 @@ import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.casemodule.CaseActionException; import org.sleuthkit.autopsy.casemodule.CaseDetails; import org.sleuthkit.autopsy.casemodule.CaseMetadata; +import org.sleuthkit.autopsy.casemodule.CaseNodeData; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.Lock; @@ -78,7 +79,6 @@ import org.sleuthkit.autopsy.coreutils.NetworkUtils; import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.autopsy.events.AutopsyEventException; import org.sleuthkit.autopsy.events.AutopsyEventPublisher; -import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestAlertFile.AutoIngestAlertFileException; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJobLogger.AutoIngestJobLoggerException; import org.sleuthkit.autopsy.experimental.autoingest.FileExporter.FileExportException; import org.sleuthkit.autopsy.experimental.autoingest.ManifestFileParser.ManifestFileParserException; @@ -98,6 +98,7 @@ import org.sleuthkit.autopsy.ingest.IngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestJobStartResult; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestModuleError; +import org.sleuthkit.datamodel.Content; /** * An auto ingest manager is responsible for processing auto ingest jobs defined @@ -554,7 +555,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang ++maxPriority; for (AutoIngestJob job : prioritizedJobs) { try { - this.updateCoordinationServiceNode(job); + this.updateCoordinationServiceManifestNode(job); job.setPriority(maxPriority); } catch (CoordinationServiceException | InterruptedException ex) { throw new AutoIngestManagerException("Error updating case priority", ex); @@ -602,13 +603,13 @@ public final class AutoIngestManager extends Observable implements PropertyChang } /* - * Bump the priority by one and update the coordination service node - * data for the job. + * Bump the priority by one and update the coordination service + * manifest node data for the job. */ if (null != prioritizedJob) { ++maxPriority; try { - this.updateCoordinationServiceNode(prioritizedJob); + this.updateCoordinationServiceManifestNode(prioritizedJob); } catch (CoordinationServiceException | InterruptedException ex) { throw new AutoIngestManagerException("Error updating job priority", ex); } @@ -649,7 +650,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang /* * Add the job to the pending jobs queue and update the coordination - * service node data for the job. + * service manifest node data for the job. */ if (null != completedJob && !completedJob.getCaseDirectoryPath().toString().isEmpty()) { try { @@ -661,7 +662,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang completedJob.setCompletedDate(new Date(0)); completedJob.setProcessingStatus(PENDING); completedJob.setProcessingStage(AutoIngestJob.Stage.PENDING, Date.from(Instant.now())); - updateCoordinationServiceNode(completedJob); + updateCoordinationServiceManifestNode(completedJob); pendingJobs.add(completedJob); } catch (CoordinationServiceException ex) { SYS_LOGGER.log(Level.SEVERE, String.format("Coordination service error while reprocessing %s", manifestPath), ex); @@ -755,7 +756,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestPath.toString())); AutoIngestJob deletedJob = new AutoIngestJob(nodeData); deletedJob.setProcessingStatus(AutoIngestJob.ProcessingStatus.DELETED); - this.updateCoordinationServiceNode(deletedJob); + this.updateCoordinationServiceManifestNode(deletedJob); } catch (AutoIngestJobNodeData.InvalidDataException | AutoIngestJobException ex) { SYS_LOGGER.log(Level.WARNING, String.format("Invalid auto ingest job node data for %s", manifestPath), ex); return CaseDeletionResult.PARTIALLY_DELETED; @@ -865,20 +866,31 @@ public final class AutoIngestManager extends Observable implements PropertyChang } /** - * Sets the coordination service node data for an auto ingest job. + * Sets the coordination service manifest node. * - * Note that a new auto ingest node data object will be created from the job - * passed in. Thus, if the data version of the node has changed, the node - * will be "upgraded" as well as updated. + * Note that a new auto ingest job node data object will be created from + * the job passed in. Thus, if the data version of the node has changed, + * the node will be "upgraded" as well as updated. * * @param job The auto ingest job. */ - void updateCoordinationServiceNode(AutoIngestJob job) throws CoordinationServiceException, InterruptedException { + void updateCoordinationServiceManifestNode(AutoIngestJob job) throws CoordinationServiceException, InterruptedException { AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(job); String manifestNodePath = job.getManifest().getFilePath().toString(); byte[] rawData = nodeData.toArray(); coordinationService.setNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestNodePath, rawData); } + + /** + * Sets the coordination service case node. + * + * @param caseNodeData The case node data. + * @param caseDirectoryPath The case directory. + */ + void updateCoordinationServiceCaseNode(CaseNodeData caseNodeData, Path caseDirectoryPath) throws CoordinationServiceException, InterruptedException { + byte[] rawData = caseNodeData.toArray(); + coordinationService.setNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString(), rawData); + } /** * A task that submits an input directory scan task to the input directory @@ -1147,8 +1159,8 @@ public final class AutoIngestManager extends Observable implements PropertyChang } /* - * Try to upgrade/update the coordination service node data for - * the job. + * Try to upgrade/update the coordination service manifest node + * data for the job. * * An exclusive lock is obtained before doing so because another * host may have already found the job, obtained an exclusive @@ -1161,7 +1173,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang */ try (Lock manifestLock = coordinationService.tryGetExclusiveLock(CoordinationService.CategoryNode.MANIFESTS, manifest.getFilePath().toString())) { if (null != manifestLock) { - updateCoordinationServiceNode(job); + updateCoordinationServiceManifestNode(job); } } catch (CoordinationServiceException ex) { SYS_LOGGER.log(Level.SEVERE, String.format("Error attempting to set node data for %s", manifest.getFilePath()), ex); @@ -1186,9 +1198,9 @@ public final class AutoIngestManager extends Observable implements PropertyChang */ private void addNewPendingJob(Manifest manifest) throws InterruptedException, AutoIngestJobException { /* - * Create the coordination service node data for the job. Note that - * getting the lock will create the node for the job (with no data) - * if it does not already exist. + * Create the coordination service manifest node data for the job. + * Note that getting the lock will create the node for the job + * (with no data) if it does not already exist. * * An exclusive lock is obtained before creating the node data * because another host may have already found the job, obtained an @@ -1202,7 +1214,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang try (Lock manifestLock = coordinationService.tryGetExclusiveLock(CoordinationService.CategoryNode.MANIFESTS, manifest.getFilePath().toString())) { if (null != manifestLock) { AutoIngestJob job = new AutoIngestJob(manifest); - updateCoordinationServiceNode(job); + updateCoordinationServiceManifestNode(job); newPendingJobsList.add(job); } } catch (CoordinationServiceException ex) { @@ -1219,14 +1231,14 @@ public final class AutoIngestManager extends Observable implements PropertyChang * status was not updated. * * @param manifest The manifest for upgrading the node. - * @param nodeData The node data. + * @param jobNodeData The auto ingest job node data. * * @throws InterruptedException if the thread running the input * directory scan task is interrupted while * blocked, i.e., if auto ingest is * shutting down. */ - private void doRecoveryIfCrashed(Manifest manifest, AutoIngestJobNodeData nodeData) throws InterruptedException, AutoIngestJobException { + private void doRecoveryIfCrashed(Manifest manifest, AutoIngestJobNodeData jobNodeData) throws InterruptedException, AutoIngestJobException { /* * Try to get an exclusive lock on the coordination service node for * the job. If the lock cannot be obtained, another host in the auto @@ -1240,7 +1252,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang /* * Create the recovery job. */ - AutoIngestJob job = new AutoIngestJob(nodeData); + AutoIngestJob job = new AutoIngestJob(jobNodeData); int numberOfCrashes = job.getNumberOfCrashes(); ++numberOfCrashes; job.setNumberOfCrashes(numberOfCrashes); @@ -1254,15 +1266,16 @@ public final class AutoIngestManager extends Observable implements PropertyChang } /* - * Update the coordination service node for the job. If - * this fails, leave the recovery to another host. + * Update the coordination service manifest node for + * the job. If this fails, leave the recovery to + * another host. */ try { - updateCoordinationServiceNode(job); + updateCoordinationServiceManifestNode(job); if (numberOfCrashes <= AutoIngestUserPreferences.getMaxNumTimesToProcessImage()) { newPendingJobsList.add(job); } else { - newCompletedJobsList.add(new AutoIngestJob(nodeData)); + newCompletedJobsList.add(new AutoIngestJob(jobNodeData)); } } catch (CoordinationServiceException ex) { SYS_LOGGER.log(Level.SEVERE, String.format("Error attempting to set node data for %s", manifestPath), ex); @@ -1270,13 +1283,15 @@ public final class AutoIngestManager extends Observable implements PropertyChang } /* - * Write the alert file and do the logging. + * Update the case node data and do the logging. */ if (null != caseDirectoryPath) { try { - AutoIngestAlertFile.create(nodeData.getCaseDirectoryPath()); - } catch (AutoIngestAlertFileException ex) { - SYS_LOGGER.log(Level.SEVERE, String.format("Error creating alert file for crashed job for %s", manifestPath), ex); + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + } catch (CaseNodeData.InvalidDataException ex) { + SYS_LOGGER.log(Level.SEVERE, String.format("Error attempting to get case node data for %s", caseDirectoryPath), ex); } } if (numberOfCrashes <= AutoIngestUserPreferences.getMaxNumTimesToProcessImage()) { @@ -1292,7 +1307,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang job.setProcessingStatus(AutoIngestJob.ProcessingStatus.COMPLETED); if (null != caseDirectoryPath) { try { - new AutoIngestJobLogger(manifest.getFilePath(), manifest.getDataSourceFileName(), nodeData.getCaseDirectoryPath()).logCrashRecoveryNoRetry(); + new AutoIngestJobLogger(manifest.getFilePath(), manifest.getDataSourceFileName(), jobNodeData.getCaseDirectoryPath()).logCrashRecoveryNoRetry(); } catch (AutoIngestJobLoggerException ex) { SYS_LOGGER.log(Level.SEVERE, String.format("Error creating case auto ingest log entry for crashed job for %s", manifestPath), ex); } @@ -1352,15 +1367,16 @@ public final class AutoIngestManager extends Observable implements PropertyChang job.setProcessingStatus(AutoIngestJob.ProcessingStatus.COMPLETED); /* - * Try to upgrade/update the coordination service node data - * for the job. It is possible that two hosts will both try - * to obtain the lock to do the upgrade operation at the - * same time. If this happens, the host that is holding the - * lock will complete the upgrade operation. + * Try to upgrade/update the coordination service manifest + * node data for the job. It is possible that two hosts + * will both try to obtain the lock to do the upgrade + * operation at the same time. If this happens, the host + * that is holding the lock will complete the upgrade + * operation. */ try (Lock manifestLock = coordinationService.tryGetExclusiveLock(CoordinationService.CategoryNode.MANIFESTS, manifest.getFilePath().toString())) { if (null != manifestLock) { - updateCoordinationServiceNode(job); + updateCoordinationServiceManifestNode(job); } } catch (CoordinationServiceException ex) { SYS_LOGGER.log(Level.SEVERE, String.format("Error attempting to set node data for %s", manifest.getFilePath()), ex); @@ -1507,8 +1523,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang errorState = ErrorState.ANALYSIS_STARTUP_ERROR; } else if (ex instanceof FileExportException) { errorState = ErrorState.FILE_EXPORT_ERROR; - } else if (ex instanceof AutoIngestAlertFileException) { - errorState = ErrorState.ALERT_FILE_ERROR; } else if (ex instanceof AutoIngestJobLoggerException) { errorState = ErrorState.JOB_LOGGER_ERROR; } else if (ex instanceof AutoIngestDataSourceProcessorException) { @@ -1691,9 +1705,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang * @throws FileExportException if there is an * error exporting * files. - * @throws AutoIngestAlertFileException if there is an - * error creating an - * alert file. * @throws AutoIngestJobLoggerException if there is an * error writing to * the auto ingest @@ -1710,7 +1721,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang * auto ingest node * data objects. */ - private void processJobs() throws CoordinationServiceException, SharedConfigurationException, ServicesMonitorException, DatabaseServerDownException, KeywordSearchServerDownException, CaseManagementException, AnalysisStartupException, FileExportException, AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException, AutoIngestJobNodeData.InvalidDataException { + private void processJobs() throws CoordinationServiceException, SharedConfigurationException, ServicesMonitorException, DatabaseServerDownException, KeywordSearchServerDownException, CaseManagementException, AnalysisStartupException, FileExportException, AutoIngestJobLoggerException, InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException, AutoIngestJobNodeData.InvalidDataException, CaseNodeData.InvalidDataException { SYS_LOGGER.log(Level.INFO, "Started processing pending jobs queue"); Lock manifestLock = JobProcessingTask.this.dequeueAndLockNextJob(); while (null != manifestLock) { @@ -1890,9 +1901,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang * @throws FileExportException if there is an * error exporting * files. - * @throws AutoIngestAlertFileException if there is an - * error creating an - * alert file. * @throws AutoIngestJobLoggerException if there is an * error writing to * the auto ingest @@ -1909,13 +1917,13 @@ public final class AutoIngestManager extends Observable implements PropertyChang * auto ingest node * data objects. */ - private void processJob() throws CoordinationServiceException, SharedConfigurationException, ServicesMonitorException, DatabaseServerDownException, KeywordSearchServerDownException, CaseManagementException, AnalysisStartupException, FileExportException, AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException, AutoIngestJobNodeData.InvalidDataException { + private void processJob() throws CoordinationServiceException, SharedConfigurationException, ServicesMonitorException, DatabaseServerDownException, KeywordSearchServerDownException, CaseManagementException, AnalysisStartupException, FileExportException, AutoIngestJobLoggerException, InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException, CaseNodeData.InvalidDataException { Path manifestPath = currentJob.getManifest().getFilePath(); SYS_LOGGER.log(Level.INFO, "Started processing of {0}", manifestPath); currentJob.setProcessingStatus(AutoIngestJob.ProcessingStatus.PROCESSING); currentJob.setProcessingStage(AutoIngestJob.Stage.STARTING, Date.from(Instant.now())); currentJob.setProcessingHostName(AutoIngestManager.LOCAL_HOST_NAME); - updateCoordinationServiceNode(currentJob); + updateCoordinationServiceManifestNode(currentJob); setChanged(); notifyObservers(Event.JOB_STARTED); eventPublisher.publishRemotely(new AutoIngestJobStartedEvent(currentJob)); @@ -1939,14 +1947,16 @@ public final class AutoIngestManager extends Observable implements PropertyChang currentJob.setProcessingStatus(AutoIngestJob.ProcessingStatus.PENDING); } currentJob.setProcessingHostName(""); - updateCoordinationServiceNode(currentJob); + updateCoordinationServiceManifestNode(currentJob); boolean retry = (!currentJob.isCanceled() && !currentJob.isCompleted()); SYS_LOGGER.log(Level.INFO, "Completed processing of {0}, retry = {1}", new Object[]{manifestPath, retry}); if (currentJob.isCanceled()) { Path caseDirectoryPath = currentJob.getCaseDirectoryPath(); if (null != caseDirectoryPath) { - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); AutoIngestJobLogger jobLogger = new AutoIngestJobLogger(manifestPath, currentJob.getManifest().getDataSourceFileName(), caseDirectoryPath); jobLogger.logJobCancelled(); } @@ -1994,7 +2004,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang * i.e., if auto ingest is * shutting down. */ - private void attemptJob() throws CoordinationServiceException, SharedConfigurationException, ServicesMonitorException, DatabaseServerDownException, KeywordSearchServerDownException, CaseManagementException, AnalysisStartupException, FileExportException, AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException { + private void attemptJob() throws CoordinationServiceException, SharedConfigurationException, ServicesMonitorException, DatabaseServerDownException, KeywordSearchServerDownException, CaseManagementException, AnalysisStartupException, FileExportException, AutoIngestJobLoggerException, InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException, CaseNodeData.InvalidDataException { updateConfiguration(); if (currentJob.isCanceled() || jobProcessingTaskFuture.isCancelled()) { return; @@ -2159,8 +2169,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang * level ingest modules. * @throws FileExportException if there is an error exporting * files. - * @throws AutoIngestAlertFileException if there is an error creating an - * alert file. * @throws AutoIngestJobLoggerException if there is an error writing to * the auto ingest log for the * case. @@ -2169,7 +2177,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang * while blocked, i.e., if auto * ingest is shutting down. */ - private void runIngestForJob(Case caseForJob) throws CoordinationServiceException, AnalysisStartupException, FileExportException, AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException { + private void runIngestForJob(Case caseForJob) throws CoordinationServiceException, AnalysisStartupException, FileExportException, AutoIngestJobLoggerException, InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException, CaseNodeData.InvalidDataException { try { if (currentJob.isCanceled() || jobProcessingTaskFuture.isCancelled()) { return; @@ -2197,8 +2205,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang * level ingest modules. * @throws FileExportException if there is an error exporting * files. - * @throws AutoIngestAlertFileException if there is an error creating an - * alert file. * @throws AutoIngestJobLoggerException if there is an error writing to * the auto ingest log for the * case. @@ -2207,7 +2213,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang * while blocked, i.e., if auto * ingest is shutting down. */ - private void ingestDataSource(Case caseForJob) throws AnalysisStartupException, FileExportException, AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException { + private void ingestDataSource(Case caseForJob) throws AnalysisStartupException, FileExportException, AutoIngestJobLoggerException, InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException, CaseNodeData.InvalidDataException, CoordinationServiceException { if (currentJob.isCanceled() || jobProcessingTaskFuture.isCancelled()) { return; } @@ -2255,8 +2261,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang * * @return A data source object. * - * @throws AutoIngestAlertFileException if there is an error creating an - * alert file. * @throws AutoIngestJobLoggerException if there is an error writing to * the auto ingest log for the * case. @@ -2265,7 +2269,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang * interrupted while blocked, i.e., * if auto ingest is shutting down. */ - private DataSource identifyDataSource() throws AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException { + private DataSource identifyDataSource() throws AutoIngestJobLoggerException, InterruptedException, CaseNodeData.InvalidDataException, CoordinationServiceException { Manifest manifest = currentJob.getManifest(); Path manifestPath = manifest.getFilePath(); SYS_LOGGER.log(Level.INFO, "Identifying data source for {0} ", manifestPath); @@ -2277,22 +2281,22 @@ public final class AutoIngestManager extends Observable implements PropertyChang if (!dataSource.exists()) { SYS_LOGGER.log(Level.SEVERE, "Missing data source for {0}", manifestPath); currentJob.setErrorsOccurred(true); - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); jobLogger.logMissingDataSource(); return null; } String deviceId = manifest.getDeviceId(); return new DataSource(deviceId, dataSourcePath); } - + /** * Passes the data source for the current job through a data source * processor that adds it to the case database. * * @param dataSource The data source. * - * @throws AutoIngestAlertFileException if there is an error creating an - * alert file. * @throws AutoIngestJobLoggerException if there is an error writing to * the auto ingest log for the * case. @@ -2301,7 +2305,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang * while blocked, i.e., if auto * ingest is shutting down. */ - private void runDataSourceProcessor(Case caseForJob, DataSource dataSource) throws InterruptedException, AutoIngestAlertFileException, AutoIngestJobLoggerException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException { + private void runDataSourceProcessor(Case caseForJob, DataSource dataSource) throws InterruptedException, AutoIngestJobLoggerException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException, CaseNodeData.InvalidDataException, CoordinationServiceException { Manifest manifest = currentJob.getManifest(); Path manifestPath = manifest.getFilePath(); SYS_LOGGER.log(Level.INFO, "Adding data source for {0} ", manifestPath); @@ -2327,7 +2331,9 @@ public final class AutoIngestManager extends Observable implements PropertyChang // did we find a data source processor that can process the data source if (validDataSourceProcessorsMap.isEmpty()) { // This should never happen. We should add all unsupported data sources as logical files. - AutoIngestAlertFile.create(caseDirectoryPath); + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); currentJob.setErrorsOccurred(true); jobLogger.logFailedToIdentifyDataSource(); SYS_LOGGER.log(Level.WARNING, "Unsupported data source {0} for {1}", new Object[]{dataSource.getPath(), manifestPath}); // NON-NLS @@ -2353,7 +2359,9 @@ public final class AutoIngestManager extends Observable implements PropertyChang // Log that the current DSP failed and set the error flag. We consider it an error // if a DSP fails even if a later one succeeds since we expected to be able to process // the data source which each DSP on the list. - AutoIngestAlertFile.create(caseDirectoryPath); + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); currentJob.setErrorsOccurred(true); jobLogger.logDataSourceProcessorError(selectedProcessor.getDataSourceType()); SYS_LOGGER.log(Level.SEVERE, "Exception while processing {0} with data source processor {1}", new Object[]{dataSource.getPath(), selectedProcessor.getDataSourceType()}); @@ -2377,8 +2385,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang * * @param dataSource The data source. * - * @throws AutoIngestAlertFileException if there is an error creating an - * alert file. * @throws AutoIngestJobLoggerException if there is an error writing to * the auto ingest log for the * case. @@ -2387,7 +2393,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang * while blocked, i.e., if auto * ingest is shutting down. */ - private void logDataSourceProcessorResult(DataSource dataSource) throws AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException { + private void logDataSourceProcessorResult(DataSource dataSource) throws AutoIngestJobLoggerException, InterruptedException, CaseNodeData.InvalidDataException, CoordinationServiceException { Manifest manifest = currentJob.getManifest(); Path manifestPath = manifest.getFilePath(); Path caseDirectoryPath = currentJob.getCaseDirectoryPath(); @@ -2399,7 +2405,9 @@ public final class AutoIngestManager extends Observable implements PropertyChang jobLogger.logDataSourceAdded(); if (dataSource.getContent().isEmpty()) { currentJob.setErrorsOccurred(true); - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); jobLogger.logNoDataSourceContent(); } break; @@ -2411,7 +2419,9 @@ public final class AutoIngestManager extends Observable implements PropertyChang jobLogger.logDataSourceAdded(); if (dataSource.getContent().isEmpty()) { currentJob.setErrorsOccurred(true); - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); jobLogger.logNoDataSourceContent(); } break; @@ -2421,7 +2431,9 @@ public final class AutoIngestManager extends Observable implements PropertyChang SYS_LOGGER.log(Level.SEVERE, "Critical error running data source processor for {0}: {1}", new Object[]{manifestPath, errorMessage}); } currentJob.setErrorsOccurred(true); - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); jobLogger.logFailedToAddDataSource(); break; } @@ -2435,7 +2447,9 @@ public final class AutoIngestManager extends Observable implements PropertyChang */ SYS_LOGGER.log(Level.WARNING, "Cancellation while waiting for data source processor for {0}", manifestPath); currentJob.setErrorsOccurred(true); - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); jobLogger.logDataSourceProcessorCancelled(); } } @@ -2449,8 +2463,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang * * @throws AnalysisStartupException if there is an error analyzing * the data source. - * @throws AutoIngestAlertFileException if there is an error creating an - * alert file. * @throws AutoIngestJobLoggerException if there is an error writing to * the auto ingest log for the * case. @@ -2459,7 +2471,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang * while blocked, i.e., if auto * ingest is shutting down. */ - private void analyze(DataSource dataSource) throws AnalysisStartupException, AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException { + private void analyze(DataSource dataSource) throws AnalysisStartupException, AutoIngestJobLoggerException, InterruptedException, CaseNodeData.InvalidDataException, CoordinationServiceException { Manifest manifest = currentJob.getManifest(); Path manifestPath = manifest.getFilePath(); SYS_LOGGER.log(Level.INFO, "Starting ingest modules analysis for {0} ", manifestPath); @@ -2491,7 +2503,9 @@ public final class AutoIngestManager extends Observable implements PropertyChang if (!cancelledModules.isEmpty()) { SYS_LOGGER.log(Level.WARNING, String.format("Ingest module(s) cancelled for %s", manifestPath)); currentJob.setErrorsOccurred(true); - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); for (String module : snapshot.getCancelledDataSourceIngestModules()) { SYS_LOGGER.log(Level.WARNING, String.format("%s ingest module cancelled for %s", module, manifestPath)); jobLogger.logIngestModuleCancelled(module); @@ -2501,7 +2515,9 @@ public final class AutoIngestManager extends Observable implements PropertyChang } else { currentJob.setProcessingStage(AutoIngestJob.Stage.CANCELLING, Date.from(Instant.now())); currentJob.setErrorsOccurred(true); - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); jobLogger.logAnalysisCancelled(); CancellationReason cancellationReason = snapshot.getCancellationReason(); if (CancellationReason.NOT_CANCELLED != cancellationReason && CancellationReason.USER_CANCELLED != cancellationReason) { @@ -2514,13 +2530,17 @@ public final class AutoIngestManager extends Observable implements PropertyChang SYS_LOGGER.log(Level.SEVERE, String.format("%s ingest module startup error for %s", error.getModuleDisplayName(), manifestPath), error.getThrowable()); } currentJob.setErrorsOccurred(true); - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); jobLogger.logIngestModuleStartupErrors(); throw new AnalysisStartupException(String.format("Error(s) during ingest module startup for %s", manifestPath)); } else { SYS_LOGGER.log(Level.SEVERE, String.format("Ingest manager ingest job start error for %s", manifestPath), ingestJobStartResult.getStartupException()); currentJob.setErrorsOccurred(true); - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); jobLogger.logAnalysisStartupError(); throw new AnalysisStartupException("Ingest manager error starting job", ingestJobStartResult.getStartupException()); } @@ -2529,7 +2549,9 @@ public final class AutoIngestManager extends Observable implements PropertyChang SYS_LOGGER.log(Level.SEVERE, "Ingest job settings error for {0}: {1}", new Object[]{manifestPath, warning}); } currentJob.setErrorsOccurred(true); - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); jobLogger.logIngestJobSettingsErrors(); throw new AnalysisStartupException("Error(s) in ingest job settings"); } @@ -2548,8 +2570,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang * * @throws FileExportException if there is an error exporting * the files. - * @throws AutoIngestAlertFileException if there is an error creating an - * alert file. * @throws AutoIngestJobLoggerException if there is an error writing to * the auto ingest log for the * case. @@ -2558,7 +2578,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang * while blocked, i.e., if auto * ingest is shutting down. */ - private void exportFiles(DataSource dataSource) throws FileExportException, AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException { + private void exportFiles(DataSource dataSource) throws FileExportException, AutoIngestJobLoggerException, InterruptedException, CaseNodeData.InvalidDataException, CoordinationServiceException { Manifest manifest = currentJob.getManifest(); Path manifestPath = manifest.getFilePath(); SYS_LOGGER.log(Level.INFO, "Exporting files for {0}", manifestPath); @@ -2574,11 +2594,13 @@ public final class AutoIngestManager extends Observable implements PropertyChang } catch (FileExportException ex) { SYS_LOGGER.log(Level.SEVERE, String.format("Error doing file export for %s", manifestPath), ex); currentJob.setErrorsOccurred(true); - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); jobLogger.logFileExportError(); } } - + /** * A data source processor progress monitor does nothing. There is * currently no mechanism for showing or recording data source processor @@ -2740,7 +2762,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang currentJob.getProcessingStageDetails(); setChanged(); notifyObservers(Event.JOB_STATUS_UPDATED); - updateCoordinationServiceNode(currentJob); + updateCoordinationServiceManifestNode(currentJob); eventPublisher.publishRemotely(new AutoIngestJobStatusEvent(currentJob)); } @@ -2843,7 +2865,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang CASE_MANAGEMENT_ERROR("Case management error"), ANALYSIS_STARTUP_ERROR("Analysis startup error"), FILE_EXPORT_ERROR("File export error"), - ALERT_FILE_ERROR("Alert file error"), JOB_LOGGER_ERROR("Job logger error"), DATA_SOURCE_PROCESSOR_ERROR("Data source processor error"), UNEXPECTED_EXCEPTION("Unknown error"); @@ -2918,7 +2939,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang PARTIALLY_DELETED, FULLY_DELETED } - static final class AutoIngestManagerException extends Exception { private static final long serialVersionUID = 1L; From a17f2126675a3b815258e6c4ae0e8f1f5a9aca0d Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Mon, 6 Nov 2017 13:10:02 -0500 Subject: [PATCH 064/115] Cleanup. --- .../autopsy/casemodule/CaseNodeData.java | 141 ++++++++++++++++++ .../autoingest/AutoIngestManager.java | 3 +- 2 files changed, 142 insertions(+), 2 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/CaseNodeData.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseNodeData.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseNodeData.java new file mode 100755 index 0000000000..a97f48c10d --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseNodeData.java @@ -0,0 +1,141 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.casemodule; + +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; + +/** + * An object that converts case data for a case directory coordination service + * node to and from byte arrays. + */ +public class CaseNodeData { + + private static final int CURRENT_VERSION = 0; + + private int version; + private boolean errorsOccurred; + + /** + * Gets the current version of the case directory coordination service node + * data. + * + * @return The version number. + */ + public static int getCurrentVersion() { + return CaseNodeData.CURRENT_VERSION; + } + + /** + * Uses coordination service node data to construct an object that converts + * case data for a case directory coordination service node to and from byte + * arrays. + * + * @param nodeData The raw bytes received from the coordination service. + * + * @throws InvalidDataException If the node data buffer is smaller than + * expected. + */ + public CaseNodeData(byte[] nodeData) throws InvalidDataException { + if(nodeData == null || nodeData.length == 0) { + this.version = CURRENT_VERSION; + this.errorsOccurred = false; + } else { + /* + * Get fields from node data. + */ + ByteBuffer buffer = ByteBuffer.wrap(nodeData); + try { + if (buffer.hasRemaining()) { + this.version = buffer.getInt(); + + /* + * Flags bit format: 76543210 + * 0-6 --> reserved for future use + * 7 --> errorsOccurred + */ + byte flags = buffer.get(); + this.errorsOccurred = (flags < 0); + } + } catch (BufferUnderflowException ex) { + throw new InvalidDataException("Node data is incomplete", ex); + } + } + } + + /** + * Gets whether or not any errors occurred during the processing of the job. + * + * @return True or false. + */ + public boolean getErrorsOccurred() { + return this.errorsOccurred; + } + + /** + * Sets whether or not any errors occurred during the processing of job. + * + * @param errorsOccurred True or false. + */ + public void setErrorsOccurred(boolean errorsOccurred) { + this.errorsOccurred = errorsOccurred; + } + + /** + * Gets the node data version number. + * + * @return The version number. + */ + public int getVersion() { + return this.version; + } + + /** + * Gets the node data as a byte array that can be sent to the coordination + * service. + * + * @return The node data as a byte array. + */ + public byte[] toArray() { + ByteBuffer buffer = ByteBuffer.allocate(5); + + buffer.putInt(this.version); + buffer.put((byte)(this.errorsOccurred ? 0x80 : 0)); + + // Prepare the array + byte[] array = new byte[buffer.position()]; + buffer.rewind(); + buffer.get(array, 0, array.length); + + return array; + } + + public final static class InvalidDataException extends Exception { + + private static final long serialVersionUID = 1L; + + private InvalidDataException(String message) { + super(message); + } + + private InvalidDataException(String message, Throwable cause) { + super(message, cause); + } + } +} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index a0168cd9ee..2ce6e2cba8 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -98,7 +98,6 @@ import org.sleuthkit.autopsy.ingest.IngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestJobStartResult; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestModuleError; -import org.sleuthkit.datamodel.Content; /** * An auto ingest manager is responsible for processing auto ingest jobs defined @@ -114,7 +113,7 @@ import org.sleuthkit.datamodel.Content; * The activities of the auto ingest nodes in a cluster are coordinated by way * of a coordination service and the nodes communicate via event messages. */ -public final class AutoIngestManager extends Observable implements PropertyChangeListener { +final class AutoIngestManager extends Observable implements PropertyChangeListener { private static final int NUM_INPUT_SCAN_SCHEDULING_THREADS = 1; private static final String INPUT_SCAN_SCHEDULER_THREAD_NAME = "AIM-input-scan-scheduler-%d"; From ab77d2c5aadbad4e43171a3ac709bc8dafa1871f Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Mon, 6 Nov 2017 13:11:34 -0500 Subject: [PATCH 065/115] Cleanup. --- Core/src/org/sleuthkit/autopsy/casemodule/CaseNodeData.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseNodeData.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseNodeData.java index a97f48c10d..1eceb084e6 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseNodeData.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseNodeData.java @@ -25,7 +25,7 @@ import java.nio.ByteBuffer; * An object that converts case data for a case directory coordination service * node to and from byte arrays. */ -public class CaseNodeData { +public final class CaseNodeData { private static final int CURRENT_VERSION = 0; From a87ea617920d572546d9a0d25658c32ae7b7d0a8 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 6 Nov 2017 14:10:10 -0500 Subject: [PATCH 066/115] ConcurrentModification bug fix --- .../autoingest/AddArchiveTask.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index b14255caff..a1a82cf0da 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -23,6 +23,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.UUID; @@ -245,7 +246,12 @@ class AddArchiveTask implements Runnable { } } - + /** + * + * @param dataSourcePath + * @param errorMessages + * @return + */ private List getValidDataSourceProcessors(Path dataSourcePath, List errorMessages) { Map validDataSourceProcessorsMap; try { @@ -263,21 +269,15 @@ class AddArchiveTask implements Runnable { // Get an ordered list of data source processors to try List validDataSourceProcessors = DataSourceProcessorUtility.orderDataSourceProcessorsByConfidence(validDataSourceProcessorsMap); - for (AutoIngestDataSourceProcessor selectedProcessor : validDataSourceProcessors) { + for (Iterator iterator = validDataSourceProcessors.iterator(); iterator.hasNext();) { + AutoIngestDataSourceProcessor selectedProcessor = iterator.next(); - // skip local files and local disk DSPs, only looking for "valid" data sources - if (selectedProcessor instanceof LocalDiskDSProcessor) { - validDataSourceProcessors.remove(selectedProcessor); - continue; - } - if (selectedProcessor instanceof LocalFilesDSProcessor) { - validDataSourceProcessors.remove(selectedProcessor); - continue; - } + // skip local files and local disk DSPs, only looking for "valid" data sources. // also skip nested archive files, those will be ingested as logical files and extracted during ingest - if (selectedProcessor instanceof ArchiveExtractorDSProcessor) { - validDataSourceProcessors.remove(selectedProcessor); - continue; + if ( (selectedProcessor instanceof LocalDiskDSProcessor) || + (selectedProcessor instanceof LocalFilesDSProcessor) || + (selectedProcessor instanceof ArchiveExtractorDSProcessor) ) { + iterator.remove(); } } From 63caed024a36bd7a94b41db9a83a5da9cd3c6c5d Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 6 Nov 2017 15:04:55 -0500 Subject: [PATCH 067/115] Added comments and java docs --- .../autoingest/AddArchiveTask.java | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index a1a82cf0da..9b92010916 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -247,10 +247,14 @@ class AddArchiveTask implements Runnable { } /** - * - * @param dataSourcePath - * @param errorMessages - * @return + * Get a list of data source processors that can process the data source of + * interest. The list is sorted by confidence in decreasing order. + * LocalDisk, LocalFiles, and ArchiveDSP are removed from the list. + * + * @param dataSourcePath Full path to the data source + * @param errorMessages List for error messages + * + * @return Ordered list of applicable DSPs */ private List getValidDataSourceProcessors(Path dataSourcePath, List errorMessages) { Map validDataSourceProcessorsMap; @@ -285,6 +289,15 @@ class AddArchiveTask implements Runnable { } + /** + * Create a directory in ModuleOutput folder based on input file name. A + * time stamp is appended to the directory name. + * + * @param fileName File name + * @param baseDirectory Base directory. Typically the case output directory. + * + * @return Full path to the new directory + */ private Path createDirectoryForFile(String fileName, String baseDirectory) { // get file name without full path or extension String fileNameNoExt = FilenameUtils.getBaseName(fileName); From d86b120d2b786e1ce1e23f125c4de48e4c3dab87 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 6 Nov 2017 15:52:12 -0500 Subject: [PATCH 068/115] Removed unused imports --- .../autopsy/experimental/autoingest/AddArchiveTask.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index 0e462d0b61..3d4a0761d7 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -30,7 +30,6 @@ import java.util.UUID; import java.util.logging.Level; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; -import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.LocalDiskDSProcessor; import org.sleuthkit.autopsy.casemodule.LocalFilesDSProcessor; From 83261afcb61895efd79cb0d4b1678d9c40abf0d3 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 6 Nov 2017 16:16:49 -0500 Subject: [PATCH 069/115] Removed unused imports --- .../experimental/autoingest/ArchiveExtractorDSProcessor.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java index dee9879dec..00d7245b33 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java @@ -24,9 +24,7 @@ import java.util.UUID; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; import javax.swing.JPanel; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProviders; From a46e406f60aadc1aefdaf1176449bd7d2bf56850 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 6 Nov 2017 17:49:52 -0500 Subject: [PATCH 070/115] Code review feedback --- .../autoingest/AddArchiveTask.java | 12 ++-- .../autoingest/AddDataSourceCallback.java | 7 --- .../ArchiveExtractorDSProcessor.java | 63 +------------------ 3 files changed, 8 insertions(+), 74 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index 3d4a0761d7..d883a9b34f 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -97,11 +97,6 @@ class AddArchiveTask implements Runnable { logger.log(Level.INFO, "Using Archive Extractor DSP to process archive {0} ", archivePath); // extract the archive and pass the extracted folder as input - UUID taskId = UUID.randomUUID(); - if (callback instanceof AddDataSourceCallback) { - // if running as part of automated ingest - re-use the task ID - taskId = ((AddDataSourceCallback) callback).getTaskId(); - } try { Case currentCase = Case.getCurrentCase(); @@ -135,7 +130,7 @@ class AddArchiveTask implements Runnable { * folder and then add the data source from that folder. This is * necessary because after all valid data sources have been * identified, we are going to add the remaining extracted - * contents of the archive as a single logacl file set. Hence, + * contents of the archive as a single logical file set. Hence, * if we do not move the data sources out of the extracted * contents folder, those data source files will get added twice * and can potentially result in duplicate keyword hits. @@ -154,12 +149,13 @@ class AddArchiveTask implements Runnable { Path newFilePath = Paths.get(newFolder.toString(), FilenameUtils.getName(file)); // Try each DSP in decreasing order of confidence + UUID taskId = UUID.randomUUID(); + currentCase.notifyAddingDataSource(taskId); boolean success = false; for (AutoIngestDataSourceProcessor selectedProcessor : validDataSourceProcessors) { logger.log(Level.INFO, "Using {0} to process extracted file {1} ", new Object[]{selectedProcessor.getDataSourceType(), file}); - // ELTBD - do we want to log this in case log and/or system admin log? synchronized (archiveDspLock) { try { DataSource internalDataSource = new DataSource(deviceId, newFilePath); @@ -210,6 +206,8 @@ class AddArchiveTask implements Runnable { progressMonitor.setProgressText(String.format("Adding: %s", destinationFolder.toString())); logger.log(Level.INFO, "Adding directory {0} as logical file set", destinationFolder.toString()); synchronized (archiveDspLock) { + UUID taskId = UUID.randomUUID(); + currentCase.notifyAddingDataSource(taskId); DataSource internalDataSource = new DataSource(deviceId, destinationFolder); DataSourceProcessorCallback internalArchiveDspCallBack = new AddDataSourceCallback(currentCase, internalDataSource, taskId, archiveDspLock); diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java index 181ad4d4d2..db19fc2fbc 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java @@ -54,13 +54,6 @@ class AddDataSourceCallback extends DataSourceProcessorCallback { this.taskId = taskId; this.lock = lock; } - - /** - * @return the taskId - */ - public UUID getTaskId() { - return taskId; - } /** * Called by the data source processor when it finishes running in its own diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java index 00d7245b33..3c31d8d2d0 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java @@ -28,7 +28,6 @@ import javax.swing.JPanel; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProviders; -import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; @@ -40,12 +39,11 @@ import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; * be used independently of the wizard. */ @ServiceProviders(value={ - @ServiceProvider(service=DataSourceProcessor.class), @ServiceProvider(service=AutoIngestDataSourceProcessor.class)} ) @NbBundle.Messages({ "ArchiveDSP.dsType.text=Archive file"}) -public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIngestDataSourceProcessor { +public class ArchiveExtractorDSProcessor implements AutoIngestDataSourceProcessor { private final static String DATA_SOURCE_TYPE = Bundle.ArchiveDSP_dsType_text(); @@ -163,20 +161,11 @@ public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIng } /** - * Requests cancellation of the background task that adds a data source to - * the case database, after the task is started using the run method. This - * is a "best effort" cancellation, with no guarantees that the case - * database will be unchanged. If cancellation succeeded, the list of new - * data sources returned by the background task will be empty. + * This DSP is a service to AutoIngestDataSourceProcessor only. Hence it is + * only used by AIM. AIM currently doesn't support DSP cancellation. */ @Override public void cancel() { - if (null != jobProcessingTaskFuture) { - jobProcessingTaskFuture.cancel(true); - jobProcessingExecutor.shutdown(); - // ELTBD - do we want to wait for the cancellation to complete? I think not, - // given that the cancelation is of "best effort" variety - } } @Override @@ -186,50 +175,4 @@ public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIng configPanel.reset(); setDataSourceOptionsCalled = false; } - - /** - * Extracts the contents of a ZIP archive submitted as a data source to a - * subdirectory of the auto ingest module output directory. - * - * @throws IOException if there is a problem extracting the data source from - * the archive. - - private static Path extractDataSource(Path outputDirectoryPath, Path dataSourcePath) throws IOException { - String dataSourceFileNameNoExt = FilenameUtils.removeExtension(dataSourcePath.getFileName().toString()); - Path destinationFolder = Paths.get(outputDirectoryPath.toString(), - AUTO_INGEST_MODULE_OUTPUT_DIR, - dataSourceFileNameNoExt + "_" + TimeStampUtils.createTimeStamp()); - Files.createDirectories(destinationFolder); - - int BUFFER_SIZE = 524288; // Read/write 500KB at a time - File sourceZipFile = dataSourcePath.toFile(); - ZipFile zipFile; - zipFile = new ZipFile(sourceZipFile, ZipFile.OPEN_READ); - Enumeration zipFileEntries = zipFile.entries(); - try { - while (zipFileEntries.hasMoreElements()) { - ZipEntry entry = zipFileEntries.nextElement(); - String currentEntry = entry.getName(); - File destFile = new File(destinationFolder.toString(), currentEntry); - destFile = new File(destinationFolder.toString(), destFile.getName()); - File destinationParent = destFile.getParentFile(); - destinationParent.mkdirs(); - if (!entry.isDirectory()) { - BufferedInputStream is = new BufferedInputStream(zipFile.getInputStream(entry)); - int currentByte; - byte data[] = new byte[BUFFER_SIZE]; - try (FileOutputStream fos = new FileOutputStream(destFile); BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER_SIZE)) { - currentByte = is.read(data, 0, BUFFER_SIZE); - while (currentByte != -1) { - dest.write(data, 0, currentByte); - currentByte = is.read(data, 0, BUFFER_SIZE); - } - } - } - } - } finally { - zipFile.close(); - } - return destinationFolder; - } */ } From a8648cdbb14527ffaed14dde5da34d6bc5aa811c Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Tue, 7 Nov 2017 13:45:21 -0500 Subject: [PATCH 071/115] 3180: Move unit test to qa-functional test and adding Case creation and deletion --- Core/nbproject/project.xml | 40 ++++++++++ .../autopsy/ingest/IngestFileFiltersTest.java | 73 +++++++++++++++++++ .../testutils/FunctionalTestDspCallback.java} | 4 +- .../FunctionalTestDspProgressMonitor.java} | 2 +- .../autopsy/ingest/IngestFileFiltersTest.java | 53 -------------- 5 files changed, 116 insertions(+), 56 deletions(-) create mode 100755 Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java rename Core/test/{unit/src/org/sleuthkit/autopsy/testutils/UnitTestDspCallback.java => qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspCallback.java} (97%) rename Core/test/{unit/src/org/sleuthkit/autopsy/testutils/UnitTestDspProgressMonitor.java => qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspProgressMonitor.java} (95%) delete mode 100755 Core/test/unit/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 25e17dd3eb..07b6d666f8 100755 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -244,6 +244,46 @@ org.netbeans.libs.junit4 + + org.netbeans.modules.jellytools.java + + + + org.netbeans.modules.jellytools.platform + + + + org.netbeans.modules.jemmy + + + + org.netbeans.modules.nbjunit + + + + + qa-functional + + org.netbeans.libs.junit4 + + + + org.netbeans.modules.jellytools.java + + + + org.netbeans.modules.jellytools.platform + + + + org.netbeans.modules.jemmy + + + + org.netbeans.modules.nbjunit + + + diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java new file mode 100755 index 0000000000..bc74a6f653 --- /dev/null +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java @@ -0,0 +1,73 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.ingest; + +import static junit.framework.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import junit.framework.TestCase; +import org.netbeans.junit.NbModuleSuite; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.CaseActionException; +import org.sleuthkit.autopsy.casemodule.CaseDetails; +import junit.framework.Test; +import org.apache.commons.io.FileUtils; +import org.openide.util.Exceptions; + +public class IngestFileFiltersTest extends TestCase { + + private static final Path caseDirectoryPath = Paths.get(System.getProperty("java.io.tmpdir"), "IngestFileFiltersTest"); + private static final File CASE_DIR = new File(caseDirectoryPath.toString()); + + public static Test suite() { + NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(IngestFileFiltersTest.class). + clusters(".*"). + enableModules(".*"); + return conf.suite(); + } + + @Override + public void setUp() { + try { + Case.createAsCurrentCase(Case.CaseType.SINGLE_USER_CASE, caseDirectoryPath.toString(), new CaseDetails("IngestFiltersTest")); + } catch (CaseActionException ex) { + Exceptions.printStackTrace(ex); + } + assertTrue(CASE_DIR.exists()); + } + + @Override + public void tearDown() { + try { + Case.closeCurrentCase(); + FileUtils.deleteDirectory(CASE_DIR); + + } catch (CaseActionException | IOException ex) { + Exceptions.printStackTrace(ex); + } + assertFalse(CASE_DIR.exists()); + } + + public void testFilter() { + System.out.println("testFilter"); + } +} diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/testutils/UnitTestDspCallback.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspCallback.java similarity index 97% rename from Core/test/unit/src/org/sleuthkit/autopsy/testutils/UnitTestDspCallback.java rename to Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspCallback.java index c6adb1f24c..cfa9f3dc59 100755 --- a/Core/test/unit/src/org/sleuthkit/autopsy/testutils/UnitTestDspCallback.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspCallback.java @@ -31,7 +31,7 @@ import org.sleuthkit.datamodel.Content; * thread. */ @Immutable -public class UnitTestDspCallback extends DataSourceProcessorCallback { +public class FunctionalTestDspCallback extends DataSourceProcessorCallback { private final Object monitor; private final List errorMessages = new ArrayList<>(); @@ -46,7 +46,7 @@ public class UnitTestDspCallback extends DataSourceProcessorCallback { * @param monitor A monitor for the callback to signal when the data source * processor completes its processing. */ - UnitTestDspCallback(Object monitor) { + FunctionalTestDspCallback(Object monitor) { this.monitor = monitor; } diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/testutils/UnitTestDspProgressMonitor.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspProgressMonitor.java similarity index 95% rename from Core/test/unit/src/org/sleuthkit/autopsy/testutils/UnitTestDspProgressMonitor.java rename to Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspProgressMonitor.java index 1f856e6500..03d26eb9b2 100755 --- a/Core/test/unit/src/org/sleuthkit/autopsy/testutils/UnitTestDspProgressMonitor.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspProgressMonitor.java @@ -25,7 +25,7 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgress * A data source processor progress monitor for unit testing. */ @Immutable -public class UnitTestDspProgressMonitor implements DataSourceProcessorProgressMonitor { +public class FunctionalTestDspProgressMonitor implements DataSourceProcessorProgressMonitor { /** * Switches the progress indicator to indeterminate mode (the total number diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java deleted file mode 100755 index 4dbec8bdc8..0000000000 --- a/Core/test/unit/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2017 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.ingest; - -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.openide.modules.Places; - -public class IngestFileFiltersTest { - - public IngestFileFiltersTest() { - } - - @BeforeClass - public static void setUpClass() { - } - - @AfterClass - public static void tearDownClass() { - } - - @Before - public void setUp() { - } - - @After - public void tearDown() { - } - - @Test - public void testFilters() { - Places.getUserDirectory().getAbsoluteFile(); - System.out.println("Test filter"); - } -} From 82ec21ac1a6b2eb2b282a7143d7579eefa88c82e Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Tue, 7 Nov 2017 13:49:19 -0500 Subject: [PATCH 072/115] 3180: delete unused import --- .../src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java index bc74a6f653..843e9e53fa 100755 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java @@ -18,8 +18,6 @@ */ package org.sleuthkit.autopsy.ingest; -import static junit.framework.Assert.assertTrue; - import java.io.File; import java.io.IOException; import java.nio.file.Path; From 635537496ae886795e1d1197c83567ff37395100 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 7 Nov 2017 13:54:35 -0500 Subject: [PATCH 073/115] fixed height of External Viewer Global Settings Panel --- .../ExternalViewerGlobalSettingsPanel.form | 83 +++++++++++++------ .../ExternalViewerGlobalSettingsPanel.java | 59 +++++++------ 2 files changed, 94 insertions(+), 48 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form index e00c4a966f..50706d661f 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form @@ -3,7 +3,7 @@
- + @@ -32,19 +32,24 @@ + + + + + - + - + @@ -55,7 +60,7 @@ - + @@ -81,13 +86,18 @@ - + + + + + + @@ -103,7 +113,7 @@ - + @@ -114,7 +124,7 @@ - + @@ -137,6 +147,11 @@ + + + + + @@ -149,42 +164,35 @@ - - - - - - - - - - - + + + + - + - + - - - + + + - + @@ -224,6 +232,15 @@ + + + + + + + + + @@ -237,6 +254,15 @@ + + + + + + + + + @@ -250,6 +276,15 @@ + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java index b2497baed8..f87c6b4e33 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java @@ -93,13 +93,17 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme editRuleButton = new javax.swing.JButton(); deleteRuleButton = new javax.swing.JButton(); - setPreferredSize(new java.awt.Dimension(750, 500)); + setPreferredSize(new java.awt.Dimension(701, 453)); + + jPanel1.setPreferredSize(new java.awt.Dimension(701, 453)); org.openide.awt.Mnemonics.setLocalizedText(externalViewerTitleLabel, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.externalViewerTitleLabel.text")); // NOI18N - jSplitPane1.setDividerLocation(350); + jSplitPane1.setDividerLocation(365); jSplitPane1.setDividerSize(1); + exePanel.setPreferredSize(new java.awt.Dimension(311, 224)); + org.openide.awt.Mnemonics.setLocalizedText(exePathLabel, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.exePathLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(exePathNameLabel, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.exePathNameLabel.text")); // NOI18N @@ -113,7 +117,7 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme .addGroup(exePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(exePathLabel) .addComponent(exePathNameLabel)) - .addContainerGap(159, Short.MAX_VALUE)) + .addContainerGap(47, Short.MAX_VALUE)) ); exePanelLayout.setVerticalGroup( exePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -122,17 +126,22 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme .addComponent(exePathLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(exePathNameLabel) - .addContainerGap(408, Short.MAX_VALUE)) + .addContainerGap(361, Short.MAX_VALUE)) ); jSplitPane1.setRightComponent(exePanel); + rulesPanel.setPreferredSize(new java.awt.Dimension(365, 406)); + org.openide.awt.Mnemonics.setLocalizedText(ruleListLabel, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.ruleListLabel.text")); // NOI18N rulesScrollPane.setViewportView(rulesList); newRuleButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add16.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(newRuleButton, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.newRuleButton.text")); // NOI18N + newRuleButton.setMaximumSize(new java.awt.Dimension(111, 25)); + newRuleButton.setMinimumSize(new java.awt.Dimension(111, 25)); + newRuleButton.setPreferredSize(new java.awt.Dimension(111, 25)); newRuleButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { newRuleButtonActionPerformed(evt); @@ -141,6 +150,9 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme editRuleButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/edit16.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(editRuleButton, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.editRuleButton.text")); // NOI18N + editRuleButton.setMaximumSize(new java.awt.Dimension(111, 25)); + editRuleButton.setMinimumSize(new java.awt.Dimension(111, 25)); + editRuleButton.setPreferredSize(new java.awt.Dimension(111, 25)); editRuleButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { editRuleButtonActionPerformed(evt); @@ -149,6 +161,9 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme deleteRuleButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/delete16.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(deleteRuleButton, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.deleteRuleButton.text")); // NOI18N + deleteRuleButton.setMaximumSize(new java.awt.Dimension(111, 25)); + deleteRuleButton.setMinimumSize(new java.awt.Dimension(111, 25)); + deleteRuleButton.setPreferredSize(new java.awt.Dimension(111, 25)); deleteRuleButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { deleteRuleButtonActionPerformed(evt); @@ -162,20 +177,16 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme .addGroup(rulesPanelLayout.createSequentialGroup() .addContainerGap() .addGroup(rulesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(rulesPanelLayout.createSequentialGroup() - .addGroup(rulesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(ruleListLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(rulesPanelLayout.createSequentialGroup() - .addComponent(rulesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 311, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE))) - .addContainerGap()) - .addGroup(rulesPanelLayout.createSequentialGroup() - .addComponent(newRuleButton) + .addComponent(ruleListLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(rulesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 345, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, rulesPanelLayout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(newRuleButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(editRuleButton) + .addComponent(editRuleButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(deleteRuleButton) - .addGap(0, 0, Short.MAX_VALUE)))) + .addComponent(deleteRuleButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap()) ); rulesPanelLayout.setVerticalGroup( rulesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -183,12 +194,12 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme .addContainerGap() .addComponent(ruleListLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(rulesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(rulesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 328, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(rulesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(newRuleButton) - .addComponent(editRuleButton) - .addComponent(deleteRuleButton)) + .addComponent(newRuleButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(editRuleButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(deleteRuleButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap()) ); @@ -202,12 +213,12 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() - .addComponent(externalViewerTitleLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 777, Short.MAX_VALUE) + .addComponent(externalViewerTitleLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 681, Short.MAX_VALUE) .addContainerGap()) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 777, Short.MAX_VALUE) + .addComponent(jScrollPane1) .addContainerGap())) ); jPanel1Layout.setVerticalGroup( @@ -215,7 +226,7 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() .addComponent(externalViewerTitleLabel) - .addContainerGap(475, Short.MAX_VALUE)) + .addContainerGap(428, Short.MAX_VALUE)) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addGap(32, 32, 32) From b85a41b4b9f5ade8e5a6cdde7bada63d53cacf06 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 7 Nov 2017 13:54:58 -0500 Subject: [PATCH 074/115] fixed height of File ext mismatch settings Panel --- .../FileExtMismatchSettingsPanel.form | 87 +++++++++++++------ .../FileExtMismatchSettingsPanel.java | 62 ++++++++----- 2 files changed, 101 insertions(+), 48 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.form index 162aef8994..f8ffc03428 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.form @@ -1,6 +1,11 @@ + + + + + @@ -16,12 +21,12 @@ - + - + @@ -29,7 +34,7 @@ - + @@ -37,36 +42,45 @@ - - - + + + - + - + + + + - + + + + + + + @@ -76,23 +90,26 @@ - + - + + + + + - + - + - + - @@ -101,14 +118,14 @@ - - - + + + - + - + @@ -142,6 +159,15 @@ + + + + + + + + + @@ -166,6 +192,11 @@ + + + + + @@ -198,16 +229,16 @@ - + - - - + + + - + @@ -221,6 +252,12 @@ + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.java index 1d5470b4df..85cf916f2c 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.java @@ -154,11 +154,18 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel removeExtButton = new javax.swing.JButton(); extHeaderLabel = new javax.swing.JLabel(); - jPanel1.setPreferredSize(new java.awt.Dimension(687, 450)); + setPreferredSize(new java.awt.Dimension(718, 430)); - jSplitPane1.setDividerLocation(430); + jPanel1.setPreferredSize(new java.awt.Dimension(718, 430)); + + jScrollPane1.setRequestFocusEnabled(false); + + jSplitPane1.setDividerLocation(365); jSplitPane1.setDividerSize(1); + mimePanel.setPreferredSize(new java.awt.Dimension(369, 424)); + mimePanel.setRequestFocusEnabled(false); + jLabel1.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class, "FileExtMismatchSettingsPanel.jLabel1.text")); // NOI18N mimeTable.setModel(mimeTableModel); @@ -166,6 +173,9 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel newTypeButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add16.png"))); // NOI18N newTypeButton.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class, "FileExtMismatchSettingsPanel.newTypeButton.text")); // NOI18N + newTypeButton.setMaximumSize(new java.awt.Dimension(111, 25)); + newTypeButton.setMinimumSize(new java.awt.Dimension(111, 25)); + newTypeButton.setPreferredSize(new java.awt.Dimension(111, 25)); newTypeButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { newTypeButtonActionPerformed(evt); @@ -188,16 +198,18 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel .addGroup(mimePanelLayout.createSequentialGroup() .addContainerGap() .addGroup(mimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addGroup(mimePanelLayout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(jLabel1) + .addGap(286, 286, 286)) .addGroup(mimePanelLayout.createSequentialGroup() .addGroup(mimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabel1) + .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 349, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(mimePanelLayout.createSequentialGroup() - .addComponent(newTypeButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(newTypeButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(10, 10, 10) .addComponent(removeTypeButton))) - .addGap(0, 191, Short.MAX_VALUE))) - .addContainerGap()) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) ); mimePanelLayout.setVerticalGroup( mimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -205,18 +217,22 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel .addContainerGap() .addComponent(jLabel1) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 427, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 348, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(mimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(newTypeButton) + .addComponent(newTypeButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(removeTypeButton, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap()) ); jSplitPane1.setLeftComponent(mimePanel); + extensionPanel.setPreferredSize(new java.awt.Dimension(344, 424)); + newExtButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add16.png"))); // NOI18N newExtButton.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class, "FileExtMismatchSettingsPanel.newExtButton.text")); // NOI18N + newExtButton.setMaximumSize(new java.awt.Dimension(111, 25)); + newExtButton.setMinimumSize(new java.awt.Dimension(111, 25)); newExtButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { newExtButtonActionPerformed(evt); @@ -248,7 +264,7 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel .addGroup(extensionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(extHeaderLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 324, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(extensionPanelLayout.createSequentialGroup() - .addComponent(newExtButton) + .addComponent(newExtButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(removeExtButton))) .addGap(0, 0, Short.MAX_VALUE))) @@ -260,10 +276,10 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel .addContainerGap() .addComponent(extHeaderLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 427, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 348, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(extensionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(newExtButton) + .addComponent(newExtButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(removeExtButton)) .addContainerGap()) ); @@ -277,27 +293,27 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 797, Short.MAX_VALUE) - .addContainerGap()) + .addGap(0, 0, 0) + .addComponent(jScrollPane1) + .addGap(0, 0, 0)) ); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 504, Short.MAX_VALUE) - .addContainerGap()) + .addGap(0, 0, 0) + .addComponent(jScrollPane1) + .addGap(0, 0, 0)) ); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 817, Short.MAX_VALUE) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 526, Short.MAX_VALUE) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); }// //GEN-END:initComponents From e1546bd51043b4931e265efebadfcc5936e7839d Mon Sep 17 00:00:00 2001 From: esaunders Date: Tue, 7 Nov 2017 16:12:06 -0500 Subject: [PATCH 075/115] Only create one KeywordHit instance per document for a given hit. --- .../sleuthkit/autopsy/keywordsearch/RegexQuery.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java index 9c92cdea5d..a0383ef03b 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java @@ -236,6 +236,8 @@ final class RegexQuery implements KeywordSearchQuery { private List createKeywordHits(SolrDocument solrDoc) throws TskCoreException { + final HashMap keywordsFoundInThisDocument = new HashMap<>(); + List hits = new ArrayList<>(); final String docId = solrDoc.getFieldValue(Server.Schema.ID.toString()).toString(); final Integer chunkSize = (Integer) solrDoc.getFieldValue(Server.Schema.CHUNK_SIZE.toString()); @@ -283,9 +285,14 @@ final class RegexQuery implements KeywordSearchQuery { hit = hit.replaceAll("[^0-9]$", ""); } - // Optimization to reduce the number of String objects created. + // We will only create one KeywordHit instance per document for + // a given hit. + if (keywordsFoundInThisDocument.containsKey(hit)) { + continue; + } + keywordsFoundInThisDocument.put(hit, hit); + if (keywordsFoundAcrossAllDocuments.containsKey(hit)) { - // Use an existing String reference if it exists. hit = keywordsFoundAcrossAllDocuments.get(hit); } else { keywordsFoundAcrossAllDocuments.put(hit, hit); From 0a6b3bc62b55c2a05533988b8b5c55015605e29a Mon Sep 17 00:00:00 2001 From: esaunders Date: Tue, 7 Nov 2017 16:48:11 -0500 Subject: [PATCH 076/115] Use String interning instead of our own hashmap to reuse hits. --- .../autopsy/keywordsearch/RegexQuery.java | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java index a0383ef03b..7702cfdc7e 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java @@ -100,15 +100,6 @@ final class RegexQuery implements KeywordSearchQuery { private String escapedQuery; private String field = Server.Schema.CONTENT_STR.toString(); - /** - * The following map is an optimization to ensure that we reuse - * the same keyword hit String object across all hits. Even though we - * benefit from G1GC String deduplication, the overhead associated with - * creating a new String object for every KeywordHit can be significant - * when the number of hits gets large. - */ - private final HashMap keywordsFoundAcrossAllDocuments; - /** * Constructor with query to process. * @@ -122,7 +113,6 @@ final class RegexQuery implements KeywordSearchQuery { this.queryStringContainsWildcardPrefix = this.keywordString.startsWith(".*"); this.queryStringContainsWildcardSuffix = this.keywordString.endsWith(".*"); - this.keywordsFoundAcrossAllDocuments = new HashMap<>(); } @Override @@ -285,6 +275,16 @@ final class RegexQuery implements KeywordSearchQuery { hit = hit.replaceAll("[^0-9]$", ""); } + /** + * The use of String interning is an optimization to ensure + * that we reuse the same keyword hit String object across + * all hits. Even though we benefit from G1GC String + * deduplication, the overhead associated with creating a + * new String object for every KeywordHit can be significant + * when the number of hits gets large. + */ + hit = hit.intern(); + // We will only create one KeywordHit instance per document for // a given hit. if (keywordsFoundInThisDocument.containsKey(hit)) { @@ -292,12 +292,6 @@ final class RegexQuery implements KeywordSearchQuery { } keywordsFoundInThisDocument.put(hit, hit); - if (keywordsFoundAcrossAllDocuments.containsKey(hit)) { - hit = keywordsFoundAcrossAllDocuments.get(hit); - } else { - keywordsFoundAcrossAllDocuments.put(hit, hit); - } - if (artifactAttributeType == null) { hits.add(new KeywordHit(docId, makeSnippet(content, hitMatcher, hit), hit)); } else { From 88d668ffeb7c7f4039d5156350601d21424298fa Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 8 Nov 2017 00:54:53 -0500 Subject: [PATCH 077/115] Wait cursor set for 'Ingest Module Settings' button. --- .../experimental/configuration/AutoIngestSettingsPanel.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java index 0d449fdb02..58f68f3b54 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.experimental.configuration; import java.awt.BorderLayout; +import java.awt.Cursor; import java.io.File; import java.nio.file.Files; import java.util.List; @@ -513,7 +514,8 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } private void displayIngestJobSettingsPanel() { - + this.getParent().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + IngestJobSettings ingestJobSettings = new IngestJobSettings(AutoIngestUserPreferences.getAutoModeIngestModuleContextString()); showWarnings(ingestJobSettings); IngestJobSettingsPanel ingestJobSettingsPanel = new IngestJobSettingsPanel(ingestJobSettings); @@ -526,6 +528,8 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { ingestJobSettings.save(); showWarnings(ingestJobSettings); } + + this.getParent().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } private static void showWarnings(IngestJobSettings ingestJobSettings) { From 35ce34137239fff2c8eb97719b44c3e88f8c2208 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 8 Nov 2017 17:41:10 -0500 Subject: [PATCH 078/115] Workaround for JComponent.addPropertyChangeListener calls in ctor --- .../autopsy/ingest/IngestOptionsPanel.java | 32 +++++++++++++++++-- .../autopsy/ingest/ProfilePanel.java | 24 +++++++++++++- .../GlobalListSettingsPanel.java | 27 ++++++++++++++-- .../KeywordSearchGlobalSettingsPanel.java | 31 ++++++++++++++++-- 4 files changed, 105 insertions(+), 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java index 1c761e8578..edd98b5034 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java @@ -140,9 +140,35 @@ public class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implemen @Override public void addPropertyChangeListener(PropertyChangeListener l) { - filterPanel.addPropertyChangeListener(l); - settingsPanel.addPropertyChangeListener(l); - profilePanel.addPropertyChangeListener(l); + super.addPropertyChangeListener(l); + /* + * There is at least one look and feel library that follows the bad + * practice of calling overrideable methods in a constructor, e.g.: + * + * at + * javax.swing.plaf.synth.SynthPanelUI.installListeners(SynthPanelUI.java:83) + * at + * javax.swing.plaf.synth.SynthPanelUI.installUI(SynthPanelUI.java:63) + * at javax.swing.JComponent.setUI(JComponent.java:666) at + * javax.swing.JPanel.setUI(JPanel.java:153) at + * javax.swing.JPanel.updateUI(JPanel.java:126) at + * javax.swing.JPanel.(JPanel.java:86) at + * javax.swing.JPanel.(JPanel.java:109) at + * javax.swing.JPanel.(JPanel.java:117) + * + * When this happens, the following child components of this panel have + * not been constructed yet, since this panel's constructor has not been + * called yet. + */ + if (null != filterPanel) { + filterPanel.addPropertyChangeListener(l); + } + if (null != settingsPanel) { + settingsPanel.addPropertyChangeListener(l); + } + if (null != profilePanel) { + profilePanel.addPropertyChangeListener(l); + } } @Override diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java index 3110947488..250435ae38 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java @@ -174,7 +174,29 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { @Override public void addPropertyChangeListener(PropertyChangeListener l) { - ingestSettingsPanel.addPropertyChangeListener(l); + super.addPropertyChangeListener(l); + /* + * There is at least one look and feel library that follows the bad + * practice of calling overrideable methods in a constructor, e.g.: + * + * at + * javax.swing.plaf.synth.SynthPanelUI.installListeners(SynthPanelUI.java:83) + * at + * javax.swing.plaf.synth.SynthPanelUI.installUI(SynthPanelUI.java:63) + * at javax.swing.JComponent.setUI(JComponent.java:666) at + * javax.swing.JPanel.setUI(JPanel.java:153) at + * javax.swing.JPanel.updateUI(JPanel.java:126) at + * javax.swing.JPanel.(JPanel.java:86) at + * javax.swing.JPanel.(JPanel.java:109) at + * javax.swing.JPanel.(JPanel.java:117) + * + * When this happens, the following child components of this panel have + * not been constructed yet, since this panel's constructor has not been + * called yet. + */ + if (null != ingestSettingsPanel) { + ingestSettingsPanel.addPropertyChangeListener(l); + } } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel jPanel1; diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListSettingsPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListSettingsPanel.java index e28cd75654..f5294db294 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListSettingsPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListSettingsPanel.java @@ -139,8 +139,31 @@ final class GlobalListSettingsPanel extends javax.swing.JPanel implements Option @Override public void addPropertyChangeListener(PropertyChangeListener l) { super.addPropertyChangeListener(l); - listsManagementPanel.addPropertyChangeListener(l); - editListPanel.addPropertyChangeListener(l); + /* + * There is at least one look and feel library that follows the bad + * practice of calling overrideable methods in a constructor, e.g.: + * + * at + * javax.swing.plaf.synth.SynthPanelUI.installListeners(SynthPanelUI.java:83) + * at + * javax.swing.plaf.synth.SynthPanelUI.installUI(SynthPanelUI.java:63) + * at javax.swing.JComponent.setUI(JComponent.java:666) at + * javax.swing.JPanel.setUI(JPanel.java:153) at + * javax.swing.JPanel.updateUI(JPanel.java:126) at + * javax.swing.JPanel.(JPanel.java:86) at + * javax.swing.JPanel.(JPanel.java:109) at + * javax.swing.JPanel.(JPanel.java:117) + * + * When this happens, the following child components of this panel have + * not been constructed yet, since this panel's constructor has not been + * called yet. + */ + if (null != listsManagementPanel) { + listsManagementPanel.addPropertyChangeListener(l); + } + if (null != editListPanel) { + editListPanel.addPropertyChangeListener(l); + } } @Override diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java index 8e820b4c74..bd2dc11a43 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java @@ -52,9 +52,34 @@ final class KeywordSearchGlobalSettingsPanel extends IngestModuleGlobalSettingsP @Override public void addPropertyChangeListener(PropertyChangeListener l) { super.addPropertyChangeListener(l); - listsPanel.addPropertyChangeListener(l); - languagesPanel.addPropertyChangeListener(l); - generalPanel.addPropertyChangeListener(l); + /* + * There is at least one look and feel library that follows the bad + * practice of calling overrideable methods in a constructor, e.g.: + * + * at + * javax.swing.plaf.synth.SynthPanelUI.installListeners(SynthPanelUI.java:83) + * at + * javax.swing.plaf.synth.SynthPanelUI.installUI(SynthPanelUI.java:63) + * at javax.swing.JComponent.setUI(JComponent.java:666) at + * javax.swing.JPanel.setUI(JPanel.java:153) at + * javax.swing.JPanel.updateUI(JPanel.java:126) at + * javax.swing.JPanel.(JPanel.java:86) at + * javax.swing.JPanel.(JPanel.java:109) at + * javax.swing.JPanel.(JPanel.java:117) + * + * When this happens, the following child components of this panel have + * not been constructed yet, since this panel's constructor has not been + * called yet. + */ + if (null != listsPanel) { + listsPanel.addPropertyChangeListener(l); + } + if (null != languagesPanel) { + languagesPanel.addPropertyChangeListener(l); + } + if (null != generalPanel) { + generalPanel.addPropertyChangeListener(l); + } } @Override From b4d2cbd447de2759c94d588dee40b012827ec62f Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 8 Nov 2017 17:45:39 -0500 Subject: [PATCH 079/115] Update comment in some JPanel subclasses --- .../org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java | 6 +++--- Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java | 6 +++--- .../autopsy/keywordsearch/GlobalListSettingsPanel.java | 6 +++--- .../keywordsearch/KeywordSearchGlobalSettingsPanel.java | 6 +++--- .../core.jar/org/netbeans/core/startup/Bundle.properties | 4 ++-- .../org/netbeans/core/windows/view/ui/Bundle.properties | 6 +++--- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java index edd98b5034..40f3d1c298 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java @@ -156,9 +156,9 @@ public class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implemen * javax.swing.JPanel.(JPanel.java:109) at * javax.swing.JPanel.(JPanel.java:117) * - * When this happens, the following child components of this panel have - * not been constructed yet, since this panel's constructor has not been - * called yet. + * When this happens, the following child components of this JPanel + * subclass have not been constructed yet, since this panel's + * constructor has not been called yet. */ if (null != filterPanel) { filterPanel.addPropertyChangeListener(l); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java index 250435ae38..75588d5ab1 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java @@ -190,9 +190,9 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { * javax.swing.JPanel.(JPanel.java:109) at * javax.swing.JPanel.(JPanel.java:117) * - * When this happens, the following child components of this panel have - * not been constructed yet, since this panel's constructor has not been - * called yet. + * When this happens, the following child components of this JPanel + * subclass have not been constructed yet, since this panel's + * constructor has not been called yet. */ if (null != ingestSettingsPanel) { ingestSettingsPanel.addPropertyChangeListener(l); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListSettingsPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListSettingsPanel.java index f5294db294..862635ad4a 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListSettingsPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListSettingsPanel.java @@ -154,9 +154,9 @@ final class GlobalListSettingsPanel extends javax.swing.JPanel implements Option * javax.swing.JPanel.(JPanel.java:109) at * javax.swing.JPanel.(JPanel.java:117) * - * When this happens, the following child components of this panel have - * not been constructed yet, since this panel's constructor has not been - * called yet. + * When this happens, the following child components of this JPanel + * subclass have not been constructed yet, since this panel's + * constructor has not been called yet. */ if (null != listsManagementPanel) { listsManagementPanel.addPropertyChangeListener(l); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java index bd2dc11a43..c34e672a1c 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java @@ -67,9 +67,9 @@ final class KeywordSearchGlobalSettingsPanel extends IngestModuleGlobalSettingsP * javax.swing.JPanel.(JPanel.java:109) at * javax.swing.JPanel.(JPanel.java:117) * - * When this happens, the following child components of this panel have - * not been constructed yet, since this panel's constructor has not been - * called yet. + * When this happens, the following child components of this JPanel + * subclass have not been constructed yet, since this panel's + * constructor has not been called yet. */ if (null != listsPanel) { listsPanel.addPropertyChangeListener(l); diff --git a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties index 2922cd2054..0de39782ca 100644 --- a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties +++ b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Thu, 07 Sep 2017 13:53:53 -0400 +#Wed, 08 Nov 2017 17:45:11 -0500 LBL_splash_window_title=Starting Autopsy SPLASH_HEIGHT=314 SPLASH_WIDTH=538 @@ -8,4 +8,4 @@ SplashRunningTextBounds=0,289,538,18 SplashRunningTextColor=0x0 SplashRunningTextFontSize=19 -currentVersion=Autopsy 4.4.2 +currentVersion=Autopsy 4.5.0 diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties index 2ac51b0cbd..fa55dddb62 100644 --- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties +++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties @@ -1,4 +1,4 @@ #Updated by build script -#Thu, 07 Sep 2017 13:53:53 -0400 -CTL_MainWindow_Title=Autopsy 4.4.2 -CTL_MainWindow_Title_No_Project=Autopsy 4.4.2 +#Wed, 08 Nov 2017 17:45:11 -0500 +CTL_MainWindow_Title=Autopsy 4.5.0 +CTL_MainWindow_Title_No_Project=Autopsy 4.5.0 From dd34e770d800219167088f3dac0fa2b53d43bb58 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 9 Nov 2017 12:24:29 -0500 Subject: [PATCH 080/115] Fixed a bug in AIMs use of taskId and data source addition notification --- .../autoingest/AutoIngestManager.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index 855a93da71..d12d0e7f0b 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -2320,18 +2320,15 @@ public final class AutoIngestManager extends Observable implements PropertyChang Path manifestPath = manifest.getFilePath(); SYS_LOGGER.log(Level.INFO, "Adding data source for {0} ", manifestPath); currentJob.setProcessingStage(AutoIngestJob.Stage.ADDING_DATA_SOURCE, Date.from(Instant.now())); - UUID taskId = UUID.randomUUID(); - DataSourceProcessorCallback callBack = new AddDataSourceCallback(caseForJob, dataSource, taskId, ingestLock); DataSourceProcessorProgressMonitor progressMonitor = new DoNothingDSPProgressMonitor(); Path caseDirectoryPath = currentJob.getCaseDirectoryPath(); AutoIngestJobLogger jobLogger = new AutoIngestJobLogger(manifestPath, manifest.getDataSourceFileName(), caseDirectoryPath); try { - caseForJob.notifyAddingDataSource(taskId); - Map validDataSourceProcessorsMap; + // Get an ordered list of data source processors to try + List validDataSourceProcessors; try { - // lookup all AutomatedIngestDataSourceProcessors and poll which ones are able to process the current data source - validDataSourceProcessorsMap = DataSourceProcessorUtility.getDataSourceProcessor(dataSource.getPath()); + validDataSourceProcessors = DataSourceProcessorUtility.getOrderedListOfDataSourceProcessors(dataSource.getPath()); } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) { SYS_LOGGER.log(Level.SEVERE, "Exception while determining best data source processor for {0}", dataSource.getPath()); // rethrow the exception. It will get caught & handled upstream and will result in AIM auto-pause. @@ -2339,7 +2336,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang } // did we find a data source processor that can process the data source - if (validDataSourceProcessorsMap.isEmpty()) { + if (validDataSourceProcessors.isEmpty()) { // This should never happen. We should add all unsupported data sources as logical files. AutoIngestAlertFile.create(caseDirectoryPath); currentJob.setErrorsOccurred(true); @@ -2348,12 +2345,13 @@ public final class AutoIngestManager extends Observable implements PropertyChang return; } - // Get an ordered list of data source processors to try - List validDataSourceProcessors = DataSourceProcessorUtility.orderDataSourceProcessorsByConfidence(validDataSourceProcessorsMap); - synchronized (ingestLock) { // Try each DSP in decreasing order of confidence for (AutoIngestDataSourceProcessor selectedProcessor : validDataSourceProcessors) { + UUID taskId = UUID.randomUUID(); + caseForJob.notifyAddingDataSource(taskId); + DataSourceProcessorCallback callBack = new AddDataSourceCallback(caseForJob, dataSource, taskId, ingestLock); + caseForJob.notifyAddingDataSource(taskId); jobLogger.logDataSourceProcessorSelected(selectedProcessor.getDataSourceType()); SYS_LOGGER.log(Level.INFO, "Identified data source type for {0} as {1}", new Object[]{manifestPath, selectedProcessor.getDataSourceType()}); try { From cb7a93d0819faa14b88e952313490f7b69fb5e43 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 9 Nov 2017 12:25:27 -0500 Subject: [PATCH 081/115] Added simpler interfaces that require only one method call --- .../DataSourceProcessorUtility.java | 49 +++++++++++++++++-- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSourceProcessorUtility.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSourceProcessorUtility.java index a8aafe4236..4878f7fa7d 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSourceProcessorUtility.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSourceProcessorUtility.java @@ -47,11 +47,7 @@ class DataSourceProcessorUtility { * @throws * org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException */ - static Map getDataSourceProcessor(Path dataSourcePath) throws AutoIngestDataSourceProcessorException { - - // lookup all AutomatedIngestDataSourceProcessors - Collection processorCandidates = Lookup.getDefault().lookupAll(AutoIngestDataSourceProcessor.class); - + static Map getDataSourceProcessorForFile(Path dataSourcePath, Collection processorCandidates) throws AutoIngestDataSourceProcessorException { Map validDataSourceProcessorsMap = new HashMap<>(); for (AutoIngestDataSourceProcessor processor : processorCandidates) { int confidence = processor.canProcess(dataSourcePath); @@ -62,6 +58,49 @@ class DataSourceProcessorUtility { return validDataSourceProcessorsMap; } + + /** + * A utility method to find all Data Source Processors (DSP) that are able + * to process the input data source. Only the DSPs that implement + * AutoIngestDataSourceProcessor interface are used. Returns ordered list of + * data source processors. DSPs are ordered in descending order from highest + * confidence to lowest. + * + * @param dataSourcePath Full path to the data source + * + * @return Ordered list of data source processors. DSPs are ordered in + * descending order from highest confidence to lowest. + * + * @throws + * org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException + */ + static List getOrderedListOfDataSourceProcessors(Path dataSourcePath) throws AutoIngestDataSourceProcessorException { + // lookup all AutomatedIngestDataSourceProcessors + Collection processorCandidates = Lookup.getDefault().lookupAll(AutoIngestDataSourceProcessor.class); + return getOrderedListOfDataSourceProcessors(dataSourcePath, processorCandidates); + } + + /** + * A utility method to find all Data Source Processors (DSP) that are able + * to process the input data source. Only the DSPs that implement + * AutoIngestDataSourceProcessor interface are used. Returns ordered list of + * data source processors. DSPs are ordered in descending order from highest + * confidence to lowest. + * + * @param dataSourcePath Full path to the data source + * @param processorCandidates Collection of AutoIngestDataSourceProcessor objects to use + * + * @return Ordered list of data source processors. DSPs are ordered in + * descending order from highest confidence to lowest. + * + * @throws + * org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException + */ + static List getOrderedListOfDataSourceProcessors(Path dataSourcePath, Collection processorCandidates) throws AutoIngestDataSourceProcessorException { + Map validDataSourceProcessorsMap = getDataSourceProcessorForFile(dataSourcePath, processorCandidates); + return orderDataSourceProcessorsByConfidence(validDataSourceProcessorsMap); + } + /** * A utility method to get an ordered list of data source processors. DSPs From 0c46e2d2d75d0c44ce8025fee7ca466b9c307dd2 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 9 Nov 2017 12:26:25 -0500 Subject: [PATCH 082/115] Only adding logical file set if there are files remaining. Bug fixes. Optimizations --- .../autoingest/AddArchiveTask.java | 73 ++++++++++++------- .../ArchiveExtractorDSProcessor.java | 2 + 2 files changed, 47 insertions(+), 28 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index d883a9b34f..e0f80780fc 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -22,6 +22,7 @@ import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -30,6 +31,7 @@ import java.util.UUID; import java.util.logging.Level; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; +import org.openide.util.Lookup; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.LocalDiskDSProcessor; import org.sleuthkit.autopsy.casemodule.LocalFilesDSProcessor; @@ -113,11 +115,23 @@ class AddArchiveTask implements Runnable { // extract contents of ZIP archive into destination folder progressMonitor.setProgressText(String.format("Extracting archive contents to: %s", destinationFolder.toString())); List extractedFiles = ArchiveUtil.unpackArchiveFile(archivePath, destinationFolder.toString()); + int numExtractedFilesRemaining = extractedFiles.size(); + + // lookup all AutomatedIngestDataSourceProcessors so that we only do it once + Collection processorCandidates = Lookup.getDefault().lookupAll(AutoIngestDataSourceProcessor.class); // do processing - for (String file : extractedFiles) { + for (String file : extractedFiles) { + + // we only care about files, skip directories + File fileObject = new File(file); + if (fileObject.isDirectory()) { + numExtractedFilesRemaining--; + continue; + } + // identify all "valid" DSPs that can process this file - List validDataSourceProcessors = getValidDataSourceProcessors(Paths.get(file), errorMessages); + List validDataSourceProcessors = getValidDataSourceProcessors(Paths.get(file), errorMessages, processorCandidates); if (validDataSourceProcessors.isEmpty()) { continue; } @@ -145,7 +159,7 @@ class AddArchiveTask implements Runnable { } // Copy it to a different folder - FileUtils.copyFileToDirectory(new File(file), newFolder.toFile()); + FileUtils.copyFileToDirectory(fileObject, newFolder.toFile()); Path newFilePath = Paths.get(newFolder.toString(), FilenameUtils.getName(file)); // Try each DSP in decreasing order of confidence @@ -192,7 +206,8 @@ class AddArchiveTask implements Runnable { // one of the DSPs successfully processed the data source. delete the // copy of the data source in the original extracted archive folder. // otherwise the data source is going to be added again as a logical file. - FileUtils.deleteQuietly(Paths.get(file).toFile()); + numExtractedFilesRemaining--; + FileUtils.deleteQuietly(fileObject); } else { // none of the DSPs were able to process the data source. delete the // copy of the data source in the temporary folder. the data source is @@ -203,28 +218,30 @@ class AddArchiveTask implements Runnable { // after all archive contents have been examined (and moved to separate folders if necessary), // add remaining extracted contents as one logical file set - progressMonitor.setProgressText(String.format("Adding: %s", destinationFolder.toString())); - logger.log(Level.INFO, "Adding directory {0} as logical file set", destinationFolder.toString()); - synchronized (archiveDspLock) { - UUID taskId = UUID.randomUUID(); - currentCase.notifyAddingDataSource(taskId); - DataSource internalDataSource = new DataSource(deviceId, destinationFolder); - DataSourceProcessorCallback internalArchiveDspCallBack = new AddDataSourceCallback(currentCase, internalDataSource, taskId, archiveDspLock); + if (numExtractedFilesRemaining > 0) { + progressMonitor.setProgressText(String.format("Adding: %s", destinationFolder.toString())); + logger.log(Level.INFO, "Adding directory {0} as logical file set", destinationFolder.toString()); + synchronized (archiveDspLock) { + UUID taskId = UUID.randomUUID(); + currentCase.notifyAddingDataSource(taskId); + DataSource internalDataSource = new DataSource(deviceId, destinationFolder); + DataSourceProcessorCallback internalArchiveDspCallBack = new AddDataSourceCallback(currentCase, internalDataSource, taskId, archiveDspLock); - // folder where archive was extracted to - List pathsList = new ArrayList<>(); - pathsList.add(destinationFolder.toString()); + // folder where archive was extracted to + List pathsList = new ArrayList<>(); + pathsList.add(destinationFolder.toString()); - // use archive file name as the name of the logical file set - String archiveFileName = FilenameUtils.getName(archivePath); + // use archive file name as the name of the logical file set + String archiveFileName = FilenameUtils.getName(archivePath); - LocalFilesDSProcessor localFilesDSP = new LocalFilesDSProcessor(); - localFilesDSP.run(deviceId, archiveFileName, pathsList, progressMonitor, internalArchiveDspCallBack); + LocalFilesDSProcessor localFilesDSP = new LocalFilesDSProcessor(); + localFilesDSP.run(deviceId, archiveFileName, pathsList, progressMonitor, internalArchiveDspCallBack); - archiveDspLock.wait(); + archiveDspLock.wait(); - // at this point we got the content object(s) from the current DSP - newDataSources.addAll(internalDataSource.getContent()); + // at this point we got the content object(s) from the current DSP + newDataSources.addAll(internalDataSource.getContent()); + } } } catch (Exception ex) { criticalErrorOccurred = true; @@ -254,23 +271,23 @@ class AddArchiveTask implements Runnable { * * @return Ordered list of applicable DSPs */ - private List getValidDataSourceProcessors(Path dataSourcePath, List errorMessages) { - Map validDataSourceProcessorsMap; + private List getValidDataSourceProcessors(Path dataSourcePath, List errorMessages, + Collection processorCandidates) { + + // Get an ordered list of data source processors to try + List validDataSourceProcessors; try { - validDataSourceProcessorsMap = DataSourceProcessorUtility.getDataSourceProcessor(dataSourcePath); + validDataSourceProcessors = DataSourceProcessorUtility.getOrderedListOfDataSourceProcessors(dataSourcePath, processorCandidates); } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) { criticalErrorOccurred = true; errorMessages.add(ex.getMessage()); logger.log(Level.SEVERE, String.format("Critical error occurred while extracting archive %s", archivePath), ex); //NON-NLS return Collections.emptyList(); } - if (validDataSourceProcessorsMap.isEmpty()) { + if (validDataSourceProcessors.isEmpty()) { return Collections.emptyList(); } - // Get an ordered list of data source processors to try - List validDataSourceProcessors = DataSourceProcessorUtility.orderDataSourceProcessorsByConfidence(validDataSourceProcessorsMap); - for (Iterator iterator = validDataSourceProcessors.iterator(); iterator.hasNext();) { AutoIngestDataSourceProcessor selectedProcessor = iterator.next(); diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java index 3c31d8d2d0..81d3ab9f8f 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java @@ -28,6 +28,7 @@ import javax.swing.JPanel; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProviders; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; @@ -39,6 +40,7 @@ import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; * be used independently of the wizard. */ @ServiceProviders(value={ + @ServiceProvider(service=DataSourceProcessor.class), @ServiceProvider(service=AutoIngestDataSourceProcessor.class)} ) @NbBundle.Messages({ From 3c433fcee3af7f5d318a5c07d5c9b1862dd2385f Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 9 Nov 2017 13:13:06 -0500 Subject: [PATCH 083/115] Optimization for getting, storing, and sorting DSP list only once --- .../autoingest/AddArchiveTask.java | 90 +++++++++++-------- 1 file changed, 51 insertions(+), 39 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index e0f80780fc..b743d7ab0b 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.Map; import java.util.UUID; import java.util.logging.Level; +import java.util.stream.Collectors; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.openide.util.Lookup; @@ -95,7 +96,7 @@ class AddArchiveTask implements Runnable { result = DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS; callback.done(result, errorMessages, newDataSources); } - + logger.log(Level.INFO, "Using Archive Extractor DSP to process archive {0} ", archivePath); // extract the archive and pass the extracted folder as input @@ -116,22 +117,23 @@ class AddArchiveTask implements Runnable { progressMonitor.setProgressText(String.format("Extracting archive contents to: %s", destinationFolder.toString())); List extractedFiles = ArchiveUtil.unpackArchiveFile(archivePath, destinationFolder.toString()); int numExtractedFilesRemaining = extractedFiles.size(); - - // lookup all AutomatedIngestDataSourceProcessors so that we only do it once - Collection processorCandidates = Lookup.getDefault().lookupAll(AutoIngestDataSourceProcessor.class); + // lookup all AutomatedIngestDataSourceProcessors so that we only do it once. + // LocalDisk, LocalFiles, and ArchiveDSP are removed from the list. + List processorCandidates = getListOfValidDataSourceProcessors(); + // do processing for (String file : extractedFiles) { - + // we only care about files, skip directories File fileObject = new File(file); if (fileObject.isDirectory()) { numExtractedFilesRemaining--; continue; } - + // identify all "valid" DSPs that can process this file - List validDataSourceProcessors = getValidDataSourceProcessors(Paths.get(file), errorMessages, processorCandidates); + List validDataSourceProcessors = getDataSourceProcessorsForFile(Paths.get(file), errorMessages, processorCandidates); if (validDataSourceProcessors.isEmpty()) { continue; } @@ -168,7 +170,7 @@ class AddArchiveTask implements Runnable { boolean success = false; for (AutoIngestDataSourceProcessor selectedProcessor : validDataSourceProcessors) { - logger.log(Level.INFO, "Using {0} to process extracted file {1} ", new Object[]{selectedProcessor.getDataSourceType(), file}); + logger.log(Level.INFO, "Using {0} to process extracted file {1} ", new Object[]{selectedProcessor.getDataSourceType(), file}); synchronized (archiveDspLock) { try { @@ -179,12 +181,12 @@ class AddArchiveTask implements Runnable { // at this point we got the content object(s) from the current DSP. // check whether the data source was processed successfully - if ((internalDataSource.getResultDataSourceProcessorResultCode() == CRITICAL_ERRORS) || - internalDataSource.getContent().isEmpty()) { + if ((internalDataSource.getResultDataSourceProcessorResultCode() == CRITICAL_ERRORS) + || internalDataSource.getContent().isEmpty()) { // move onto the the next DSP that can process this data source continue; } - + // if we are here it means the data source was addedd successfully success = true; newDataSources.addAll(internalDataSource.getContent()); @@ -201,7 +203,7 @@ class AddArchiveTask implements Runnable { } } } - + if (success) { // one of the DSPs successfully processed the data source. delete the // copy of the data source in the original extracted archive folder. @@ -260,55 +262,65 @@ class AddArchiveTask implements Runnable { callback.done(result, errorMessages, newDataSources); } } - + + /** + * Get a list of data source processors. LocalDisk, LocalFiles, and + * ArchiveDSP are removed from the list. + * + * @return List of data source processors + */ + private List getListOfValidDataSourceProcessors() { + + Collection processorCandidates = Lookup.getDefault().lookupAll(AutoIngestDataSourceProcessor.class); + + List validDataSourceProcessors = processorCandidates.stream().collect(Collectors.toList()); + + for (Iterator iterator = validDataSourceProcessors.iterator(); iterator.hasNext();) { + AutoIngestDataSourceProcessor selectedProcessor = iterator.next(); + + // skip local files and local disk DSPs, only looking for "valid" data sources. + // also skip nested archive files, those will be ingested as logical files and extracted during ingest + if ((selectedProcessor instanceof LocalDiskDSProcessor) + || (selectedProcessor instanceof LocalFilesDSProcessor) + || (selectedProcessor instanceof ArchiveExtractorDSProcessor)) { + iterator.remove(); + } + } + + return validDataSourceProcessors; + } + /** * Get a list of data source processors that can process the data source of * interest. The list is sorted by confidence in decreasing order. - * LocalDisk, LocalFiles, and ArchiveDSP are removed from the list. * * @param dataSourcePath Full path to the data source - * @param errorMessages List for error messages + * @param errorMessages List for error messages + * @param errorMessages List of AutoIngestDataSourceProcessor to try * * @return Ordered list of applicable DSPs */ - private List getValidDataSourceProcessors(Path dataSourcePath, List errorMessages, - Collection processorCandidates) { - + private List getDataSourceProcessorsForFile(Path dataSourcePath, List errorMessages, + List processorCandidates) { + // Get an ordered list of data source processors to try - List validDataSourceProcessors; + List validDataSourceProcessorsForFile = Collections.emptyList(); try { - validDataSourceProcessors = DataSourceProcessorUtility.getOrderedListOfDataSourceProcessors(dataSourcePath, processorCandidates); + validDataSourceProcessorsForFile = DataSourceProcessorUtility.getOrderedListOfDataSourceProcessors(dataSourcePath, processorCandidates); } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) { criticalErrorOccurred = true; errorMessages.add(ex.getMessage()); logger.log(Level.SEVERE, String.format("Critical error occurred while extracting archive %s", archivePath), ex); //NON-NLS return Collections.emptyList(); } - if (validDataSourceProcessors.isEmpty()) { - return Collections.emptyList(); - } - - for (Iterator iterator = validDataSourceProcessors.iterator(); iterator.hasNext();) { - AutoIngestDataSourceProcessor selectedProcessor = iterator.next(); - - // skip local files and local disk DSPs, only looking for "valid" data sources. - // also skip nested archive files, those will be ingested as logical files and extracted during ingest - if ( (selectedProcessor instanceof LocalDiskDSProcessor) || - (selectedProcessor instanceof LocalFilesDSProcessor) || - (selectedProcessor instanceof ArchiveExtractorDSProcessor) ) { - iterator.remove(); - } - } - - return validDataSourceProcessors; + return validDataSourceProcessorsForFile; } - /** * Create a directory in ModuleOutput folder based on input file name. A * time stamp is appended to the directory name. * - * @param fileName File name + * @param fileName File name * @param baseDirectory Base directory. Typically the case output directory. * * @return Full path to the new directory From c1808f4a034211d124652efee4b0d2320b88bd6d Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 9 Nov 2017 13:23:58 -0500 Subject: [PATCH 084/115] Bug fix --- .../autopsy/experimental/autoingest/AddArchiveTask.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index b743d7ab0b..5914b95160 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -165,15 +165,14 @@ class AddArchiveTask implements Runnable { Path newFilePath = Paths.get(newFolder.toString(), FilenameUtils.getName(file)); // Try each DSP in decreasing order of confidence - UUID taskId = UUID.randomUUID(); - currentCase.notifyAddingDataSource(taskId); boolean success = false; for (AutoIngestDataSourceProcessor selectedProcessor : validDataSourceProcessors) { logger.log(Level.INFO, "Using {0} to process extracted file {1} ", new Object[]{selectedProcessor.getDataSourceType(), file}); - synchronized (archiveDspLock) { try { + UUID taskId = UUID.randomUUID(); + currentCase.notifyAddingDataSource(taskId); DataSource internalDataSource = new DataSource(deviceId, newFilePath); DataSourceProcessorCallback internalArchiveDspCallBack = new AddDataSourceCallback(currentCase, internalDataSource, taskId, archiveDspLock); selectedProcessor.process(deviceId, newFilePath, progressMonitor, internalArchiveDspCallBack); From 3c95a7a70a5c2c2b858ea768c9e01893f1053119 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 9 Nov 2017 13:28:00 -0500 Subject: [PATCH 085/115] ArchiveExtractorDSProcessor no longer implements ArchiveExtractorDSProcessor interface --- .../autopsy/experimental/autoingest/AddArchiveTask.java | 1 - .../autoingest/ArchiveExtractorDSProcessor.java | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index 5914b95160..be6a047bc3 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -26,7 +26,6 @@ import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.UUID; import java.util.logging.Level; import java.util.stream.Collectors; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java index 81d3ab9f8f..0eba2b8f95 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java @@ -23,12 +23,10 @@ import java.nio.file.Path; import java.util.UUID; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.Future; import javax.swing.JPanel; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProviders; -import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; @@ -40,7 +38,6 @@ import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; * be used independently of the wizard. */ @ServiceProviders(value={ - @ServiceProvider(service=DataSourceProcessor.class), @ServiceProvider(service=AutoIngestDataSourceProcessor.class)} ) @NbBundle.Messages({ @@ -55,7 +52,6 @@ public class ArchiveExtractorDSProcessor implements AutoIngestDataSourceProcesso private boolean setDataSourceOptionsCalled; private final ExecutorService jobProcessingExecutor; - private Future jobProcessingTaskFuture; private static final String ARCHIVE_DSP_THREAD_NAME = "Archive-DSP-%d"; private AddArchiveTask addArchiveTask; @@ -159,7 +155,7 @@ public class ArchiveExtractorDSProcessor implements AutoIngestDataSourceProcesso */ public void run(String deviceId, String archivePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { addArchiveTask = new AddArchiveTask(deviceId, archivePath, progressMonitor, callback); - jobProcessingTaskFuture = jobProcessingExecutor.submit(addArchiveTask); + jobProcessingExecutor.submit(addArchiveTask); } /** From a38763a85f3c07081ebc03e828f493bc78fcc7c9 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Thu, 9 Nov 2017 14:46:33 -0500 Subject: [PATCH 086/115] 3155: Busy cursor in ingest inbox --- .../BlackboardResultViewer.java | 3 + .../autopsy/directorytree/Bundle.properties | 2 - .../directorytree/Bundle_ja.properties | 4 +- .../DirectoryTreeTopComponent.java | 20 +---- .../ingest/IngestMessageDetailsPanel.java | 80 +++++-------------- 5 files changed, 26 insertions(+), 83 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/BlackboardResultViewer.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/BlackboardResultViewer.java index c196adae4c..f32d82148e 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/BlackboardResultViewer.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/BlackboardResultViewer.java @@ -24,7 +24,10 @@ import org.sleuthkit.datamodel.BlackboardArtifact; /** * Additional functionality of viewers supporting black board results such as * the directory tree + * + *@deprecated No longer used. */ +@Deprecated public interface BlackboardResultViewer { public static final String FINISHED_DISPLAY_EVT = "FINISHED_DISPLAY_EVT"; //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties index aa8f1f3a90..647c6f70d3 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties @@ -59,8 +59,6 @@ DirectoryTreeFilterNode.action.collapseAll.text=Collapse All DirectoryTreeFilterNode.action.openFileSrcByAttr.text=Open File Search by Attributes DirectoryTreeFilterNode.action.runIngestMods.text=Run Ingest Modules DirectoryTreeTopComponent.action.viewArtContent.text=View Artifact Content -DirectoryTreeTopComponent.moduleErr=Module Error -DirectoryTreeTopComponent.moduleErr.msg=A module caused an error listening to DirectoryTreeTopComponent updates. See log to determine which module. Some data could be incomplete. DirectoryTreeTopComponent.showRejectedCheckBox.text=Show Rejected Results ExplorerNodeActionVisitor.action.imgDetails.title=Image Details ExplorerNodeActionVisitor.action.extUnallocToSingleFiles=Extract Unallocated Space to Single Files diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle_ja.properties index 2fb64c5bea..6f208c3300 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle_ja.properties @@ -56,8 +56,6 @@ DataResultFilterNode.action.viewInDir.text=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\ DirectoryTreeFilterNode.action.openFileSrcByAttr.text=\u5c5e\u6027\u306b\u3088\u308b\u30d5\u30a1\u30a4\u30eb\u691c\u7d22\u3092\u958b\u304f DirectoryTreeFilterNode.action.runIngestMods.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u3092\u5b9f\u884c DirectoryTreeTopComponent.action.viewArtContent.text=\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u30b3\u30f3\u30c6\u30f3\u30c4\u3092\u8868\u793a -DirectoryTreeTopComponent.moduleErr=\u30e2\u30b8\u30e5\u30fc\u30eb\u30a8\u30e9\u30fc -DirectoryTreeTopComponent.moduleErr.msg=DirectoryTreeTopComponent\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u3092\u78ba\u8a8d\u4e2d\u306b\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u30a8\u30e9\u30fc\u3092\u8d77\u3053\u3057\u307e\u3057\u305f\u3002\u3069\u306e\u30e2\u30b8\u30e5\u30fc\u30eb\u304b\u30ed\u30b0\u3092\u78ba\u8a8d\u3057\u3066\u4e0b\u3055\u3044\u3002\u4e00\u90e8\u306e\u30c7\u30fc\u30bf\u304c\u4e0d\u5b8c\u5168\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002 ExplorerNodeActionVisitor.action.imgDetails.title=\u30a4\u30e1\u30fc\u30b8\u8a73\u7d30 ExplorerNodeActionVisitor.action.extUnallocToSingleFiles=\u672a\u5272\u308a\u5f53\u3066\u9818\u57df\u5185\u306e\u30c7\u30fc\u30bf\u3092\u30b7\u30f3\u30b0\u30eb\u30d5\u30a1\u30a4\u30eb\u306b\u62bd\u51fa ExplorerNodeActionVisitor.action.fileSystemDetails.title=\u30d5\u30a1\u30a4\u30eb\u30b7\u30b9\u30c6\u30e0\u8a73\u7d30 @@ -87,4 +85,4 @@ ExtractUnallocAction.done.notifyMsg.completedExtract.msg=\u30d5\u30a1\u30a4\u30e ExtractUnallocAction.done.errMsg.title=\u62bd\u51fa\u30a8\u30e9\u30fc ExtractUnallocAction.done.errMsg.msg=\u672a\u5272\u308a\u5f53\u3066\u9818\u57df\u3092\u62bd\u51fa\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\uff1a{0} DirectoryTreeFilterNode.action.collapseAll.text=\u3059\u3079\u3066\u30b3\u30e9\u30d7\u30b9 -ExtractAction.done.notifyMsg.extractErr=\u4e0b\u8a18\u306e\u30d5\u30a1\u30a4\u30eb\u306e\u62bd\u51fa\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\uff1a {0} \ No newline at end of file +ExtractAction.done.notifyMsg.extractErr=\u4e0b\u8a18\u306e\u30d5\u30a1\u30a4\u30eb\u306e\u62bd\u51fa\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\uff1a {0} diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 03c265daee..9738f1f4a6 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -27,7 +27,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; -import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -56,13 +55,11 @@ import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.core.UserPreferences; -import org.sleuthkit.autopsy.corecomponentinterfaces.BlackboardResultViewer; import org.sleuthkit.autopsy.corecomponentinterfaces.CoreComponentControl; import org.sleuthkit.autopsy.corecomponentinterfaces.DataExplorer; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.corecomponents.TableFilterNode; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.datamodel.ArtifactNodeSelectionInfo; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; import org.sleuthkit.autopsy.datamodel.CreditCards; @@ -99,7 +96,7 @@ import org.sleuthkit.datamodel.TskCoreException; @Messages({ "DirectoryTreeTopComponent.resultsView.title=Listing" }) -public final class DirectoryTreeTopComponent extends TopComponent implements DataExplorer, ExplorerManager.Provider, BlackboardResultViewer { +public final class DirectoryTreeTopComponent extends TopComponent implements DataExplorer, ExplorerManager.Provider { private final transient ExplorerManager em = new ExplorerManager(); private static DirectoryTreeTopComponent instance; @@ -851,7 +848,6 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat return false; } - @Override public void viewArtifact(final BlackboardArtifact art) { int typeID = art.getArtifactTypeID(); String typeName = art.getArtifactTypeName(); @@ -1064,28 +1060,14 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat // Another thread is needed because we have to wait for dataResult to populate } - @Override public void viewArtifactContent(BlackboardArtifact art) { new ViewContextAction( NbBundle.getMessage(this.getClass(), "DirectoryTreeTopComponent.action.viewArtContent.text"), new BlackboardArtifactNode(art)).actionPerformed(null); } - @Override public void addOnFinishedListener(PropertyChangeListener l) { DirectoryTreeTopComponent.this.addPropertyChangeListener(l); } - void fireViewerComplete() { - - try { - firePropertyChange(BlackboardResultViewer.FINISHED_DISPLAY_EVT, 0, 1); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "DirectoryTreeTopComponent listener threw exception", e); //NON-NLS - MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "DirectoryTreeTopComponent.moduleErr"), - NbBundle.getMessage(this.getClass(), - "DirectoryTreeTopComponent.moduleErr.msg"), - MessageNotifyUtil.MessageType.ERROR); - } - } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageDetailsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageDetailsPanel.java index 0a8222bca0..2659ce400a 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageDetailsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageDetailsPanel.java @@ -21,14 +21,11 @@ package org.sleuthkit.autopsy.ingest; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; import javax.swing.JMenuItem; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.StyleSheet; -import org.openide.util.Lookup; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.corecomponentinterfaces.BlackboardResultViewer; +import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; import org.sleuthkit.autopsy.ingest.IngestMessagePanel.IngestMessageGroup; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -40,7 +37,8 @@ import org.sleuthkit.datamodel.TskException; */ class IngestMessageDetailsPanel extends javax.swing.JPanel { - private IngestMessageMainPanel mainPanel; + private final IngestMessageMainPanel mainPanel; + private final DirectoryTreeTopComponent dtc = DirectoryTreeTopComponent.findInstance(); /** * Creates new form IngestMessageDetailsPanel @@ -69,18 +67,6 @@ class IngestMessageDetailsPanel extends javax.swing.JPanel { styleSheet.addRule("td {white-space:pre-wrap;overflow:hidden;}"); //NON-NLS styleSheet.addRule("th {font-weight:bold;}"); //NON-NLS - BlackboardResultViewer v = Lookup.getDefault().lookup(BlackboardResultViewer.class); - v.addOnFinishedListener(new PropertyChangeListener() { - - @Override - public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(BlackboardResultViewer.FINISHED_DISPLAY_EVT)) { - artifactViewerFinished(); - } - } - - }); - //right click messageDetailsPane.setComponentPopupMenu(rightClickMenu); ActionListener actList = new ActionListener() { @@ -193,11 +179,27 @@ class IngestMessageDetailsPanel extends javax.swing.JPanel { }// //GEN-END:initComponents private void viewContentButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewContentButtonActionPerformed - viewContent(evt); + messageDetailsPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + final IngestMessageGroup messageGroup = mainPanel.getMessagePanel().getSelectedMessage(); + if (messageGroup != null) { + BlackboardArtifact art = messageGroup.getData(); + if (art != null) { + dtc.viewArtifactContent(art); + } + } + messageDetailsPane.setCursor(null); }//GEN-LAST:event_viewContentButtonActionPerformed private void viewArtifactButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewArtifactButtonActionPerformed - viewArtifact(evt); + messageDetailsPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + final IngestMessageGroup messageGroup = mainPanel.getMessagePanel().getSelectedMessage(); + if (messageGroup != null) { + BlackboardArtifact art = messageGroup.getData(); + if (art != null) { + dtc.viewArtifact(art); + } + } + messageDetailsPane.setCursor(null); }//GEN-LAST:event_viewArtifactButtonActionPerformed private void backButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_backButtonActionPerformed @@ -216,46 +218,6 @@ class IngestMessageDetailsPanel extends javax.swing.JPanel { private javax.swing.JButton viewContentButton; // End of variables declaration//GEN-END:variables - private void viewArtifact(java.awt.event.ActionEvent evt) { - artifactViewerInvoked(); - - final IngestMessageGroup messageGroup = mainPanel.getMessagePanel().getSelectedMessage(); - if (messageGroup != null) { - BlackboardArtifact art = messageGroup.getData(); - if (art != null) { - BlackboardResultViewer v = Lookup.getDefault().lookup(BlackboardResultViewer.class); - v.viewArtifact(art); - } - } - - } - - private void viewContent(java.awt.event.ActionEvent evt) { - artifactViewerInvoked(); - - final IngestMessageGroup messageGroup = mainPanel.getMessagePanel().getSelectedMessage(); - if (messageGroup != null) { - BlackboardArtifact art = messageGroup.getData(); - if (art != null) { - BlackboardResultViewer v = Lookup.getDefault().lookup(BlackboardResultViewer.class); - v.viewArtifactContent(art); - } - } - } - - private void artifactViewerInvoked() { - //viewArtifactButton.setEnabled(false); - //viewContentButton.setEnabled(false); - messageDetailsPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - - } - - private void artifactViewerFinished() { - //viewArtifactButton.setEnabled(true); - //viewContentButton.setEnabled(true); - messageDetailsPane.setCursor(null); - } - /** * Display the details of a given message * From ca64d9a3977450207a1c17bea13ded8599c902b0 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 10 Nov 2017 10:28:47 -0500 Subject: [PATCH 087/115] Pulling node data to determine case status. --- .../casemodule/MultiUserCaseManager.java | 142 ++++++++++++------ .../CaseNodeData.java | 2 +- .../autoingest/AutoIngestManager.java | 117 ++++++--------- 3 files changed, 145 insertions(+), 116 deletions(-) rename Core/src/org/sleuthkit/autopsy/{casemodule => coordinationservice}/CaseNodeData.java (98%) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java index d0baf94bc9..bedc09d799 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java @@ -30,6 +30,7 @@ import java.util.Date; import java.util.List; import java.util.Objects; import java.util.logging.Level; +import org.sleuthkit.autopsy.coordinationservice.CaseNodeData; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; import org.sleuthkit.autopsy.coreutils.Logger; @@ -40,7 +41,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; final class MultiUserCaseManager { private static final Logger LOGGER = Logger.getLogger(MultiUserCaseManager.class.getName()); - private static final String LOG_FILE_NAME = "auto_ingest_log.txt"; + private static final String ALERT_FILE_NAME = "autoingest.alert"; private static MultiUserCaseManager instance; private CoordinationService coordinationService; @@ -82,19 +83,74 @@ final class MultiUserCaseManager { List cases = new ArrayList<>(); List nodeList = coordinationService.getNodeList(CoordinationService.CategoryNode.CASES); for (String node : nodeList) { - Path casePath = Paths.get(node); - File caseFolder = casePath.toFile(); - if(caseFolder.exists()) { - File[] autFiles = caseFolder.listFiles((dir, name) -> name.toLowerCase().endsWith(".aut")); - if(autFiles != null && autFiles.length > 0) { - try { - CaseMetadata caseMetadata = new CaseMetadata(Paths.get(autFiles[0].getAbsolutePath())); - cases.add(new MultiUserCase(casePath, caseMetadata)); - } catch (CaseMetadata.CaseMetadataException | MultiUserCase.MultiUserCaseException ex) { - LOGGER.log(Level.SEVERE, String.format("Error reading case metadata file '%s'.", autFiles[0].getAbsolutePath()), ex); + Path casePath = Paths.get(node); + File caseFolder = casePath.toFile(); + if (caseFolder.exists()) { + /* + * Search for '*.aut' and 'autoingest.alert' files. + */ + File[] fileArray = caseFolder.listFiles(); + if (fileArray == null) { + continue; + } + String autFilePath = null; + boolean alertFileFound = false; + for (File file : fileArray) { + String name = file.getName().toLowerCase(); + if (autFilePath == null && name.endsWith(".aut")) { + autFilePath = file.getAbsolutePath(); + if (!alertFileFound) { + continue; + } + } + if (!alertFileFound && name.endsWith(ALERT_FILE_NAME)) { + alertFileFound = true; + } + if (autFilePath != null && alertFileFound) { + break; + } + } + + if (autFilePath != null) { + try { + CaseStatus caseStatus; + if (alertFileFound) { + /* + * When an alert file exists, ignore the node data + * and use the ALERT status. + */ + caseStatus = CaseStatus.ALERT; + } else { + byte[] rawData = coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, node); + if (rawData != null && rawData.length > 0) { + /* + * When node data exists, use the status stored + * in the node data. + */ + CaseNodeData caseNodeData = new CaseNodeData(rawData); + if (caseNodeData.getErrorsOccurred()) { + caseStatus = CaseStatus.ALERT; + } else { + caseStatus = CaseStatus.OK; + } + } else { + /* + * When no node data is available, use the 'OK' + * status to avoid confusing the end-user. + */ + caseStatus = CaseStatus.OK; } } + + CaseMetadata caseMetadata = new CaseMetadata(Paths.get(autFilePath)); + cases.add(new MultiUserCase(casePath, caseMetadata, caseStatus)); + } catch (CaseMetadata.CaseMetadataException | MultiUserCase.MultiUserCaseException ex) { + LOGGER.log(Level.SEVERE, String.format("Error reading case metadata file '%s'.", autFilePath), ex); + } catch (InterruptedException | CaseNodeData.InvalidDataException ex) { + LOGGER.log(Level.SEVERE, String.format("Error reading case node data for '%s'.", node), ex); + } } + } } return cases; } @@ -112,7 +168,7 @@ final class MultiUserCaseManager { */ Case.openAsCurrentCase(caseMetadataFilePath.toString()); } - + /** * Exception type thrown when there is an error completing a multi-user case * manager operation. @@ -143,7 +199,7 @@ final class MultiUserCaseManager { } } - + /** * A representation of a multi-user case. */ @@ -154,21 +210,22 @@ final class MultiUserCaseManager { private final String metadataFileName; private final Date createDate; private final Date lastAccessedDate; + private CaseStatus status; /** * Constructs a representation of a multi-user case * * @param caseDirectoryPath The case directory path. - * @param caseMetadata The case metadata. - * - * @throws MultiUserCaseException If no case metadata (.aut) - * file is found in the case - * directory. + * @param caseMetadata The case metadata. + * + * @throws MultiUserCaseException If no case metadata (.aut) file is + * found in the case directory. */ - MultiUserCase(Path caseDirectoryPath, CaseMetadata caseMetadata) throws MultiUserCaseException { + MultiUserCase(Path caseDirectoryPath, CaseMetadata caseMetadata, CaseStatus status) throws MultiUserCaseException { this.caseDirectoryPath = caseDirectoryPath; caseDisplayName = caseMetadata.getCaseDisplayName(); metadataFileName = caseMetadata.getFilePath().getFileName().toString(); + this.status = status; BasicFileAttributes fileAttrs = null; try { fileAttrs = Files.readAttributes(Paths.get(caseDirectoryPath.toString(), metadataFileName), BasicFileAttributes.class); @@ -194,8 +251,8 @@ final class MultiUserCaseManager { } /** - * Gets the case display name. This may differ from the name supplied to the - * directory or metadata file names if a case has been renamed. + * Gets the case display name. This may differ from the name supplied to + * the directory or metadata file names if a case has been renamed. * * @return The case display name. */ @@ -204,8 +261,8 @@ final class MultiUserCaseManager { } /** - * Gets the creation date for the case, defined as the create time of the - * case metadata file. + * Gets the creation date for the case, defined as the create time of + * the case metadata file. * * @return The case creation date. */ @@ -214,8 +271,8 @@ final class MultiUserCaseManager { } /** - * Gets the last accessed date for the case, defined as the last accessed - * time of the case metadata file. + * Gets the last accessed date for the case, defined as the last + * accessed time of the case metadata file. * * @return The last accessed date. */ @@ -225,7 +282,7 @@ final class MultiUserCaseManager { /** * Gets metadata (.aut) file name. - * + * * @return The metadata file name. */ String getMetadataFileName() { @@ -233,17 +290,12 @@ final class MultiUserCaseManager { } /** - * Gets the status of this case based on the auto ingest result file in the - * case directory. + * Gets the status of this case. * * @return See CaseStatus enum definition. */ CaseStatus getStatus() { - if(caseDirectoryPath.resolve("autoingest.alert").toFile().exists()) { - return CaseStatus.ALERT; - } else { - return CaseStatus.OK; - } + return status; } /** @@ -252,7 +304,7 @@ final class MultiUserCaseManager { * @param caseDirectoryPath The case directory path. * * @return Case metadata. - * + * * @throws CaseMetadata.CaseMetadataException If the CaseMetadata object * cannot be constructed. * @throws MultiUserCaseException If no case metadata (.aut) @@ -276,7 +328,7 @@ final class MultiUserCaseManager { } } - if(autFile == null || !autFile.isFile()) { + if (autFile == null || !autFile.isFile()) { throw new MultiUserCaseException(String.format("No case metadata (.aut) file found in the case directory '%s'.", caseDirectoryPath.toString())); } @@ -334,14 +386,15 @@ final class MultiUserCaseManager { static class LastAccessedDateDescendingComparator implements Comparator { /** - * Compares two MultiUserCase objects for order based on last accessed - * date (descending). + * Compares two MultiUserCase objects for order based on last + * accessed date (descending). * * @param object The first MultiUserCase object * @param otherObject The second MultiUserCase object. * - * @return A negative integer, zero, or a positive integer as the first - * argument is less than, equal to, or greater than the second. + * @return A negative integer, zero, or a positive integer as the + * first argument is less than, equal to, or greater than + * the second. */ @Override public int compare(MultiUserCase object, MultiUserCase otherObject) { @@ -357,8 +410,8 @@ final class MultiUserCaseManager { private static final long serialVersionUID = 1L; /** - * Constructs an exception to throw when there is a problem creating a - * multi-user case. + * Constructs an exception to throw when there is a problem creating + * a multi-user case. * * @param message The exception message. */ @@ -367,11 +420,12 @@ final class MultiUserCaseManager { } /** - * Constructs an exception to throw when there is a problem creating a - * multi-user case. + * Constructs an exception to throw when there is a problem creating + * a multi-user case. * * @param message The exception message. - * @param cause The cause of the exception, if it was an exception. + * @param cause The cause of the exception, if it was an + * exception. */ private MultiUserCaseException(String message, Throwable cause) { super(message, cause); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseNodeData.java b/Core/src/org/sleuthkit/autopsy/coordinationservice/CaseNodeData.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/casemodule/CaseNodeData.java rename to Core/src/org/sleuthkit/autopsy/coordinationservice/CaseNodeData.java index 1eceb084e6..0b220e04b2 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseNodeData.java +++ b/Core/src/org/sleuthkit/autopsy/coordinationservice/CaseNodeData.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.casemodule; +package org.sleuthkit.autopsy.coordinationservice; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index 2ce6e2cba8..e6187877c3 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -64,7 +64,7 @@ import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.casemodule.CaseActionException; import org.sleuthkit.autopsy.casemodule.CaseDetails; import org.sleuthkit.autopsy.casemodule.CaseMetadata; -import org.sleuthkit.autopsy.casemodule.CaseNodeData; +import org.sleuthkit.autopsy.coordinationservice.CaseNodeData; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.Lock; @@ -867,9 +867,9 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen /** * Sets the coordination service manifest node. * - * Note that a new auto ingest job node data object will be created from - * the job passed in. Thus, if the data version of the node has changed, - * the node will be "upgraded" as well as updated. + * Note that a new auto ingest job node data object will be created from the + * job passed in. Thus, if the data version of the node has changed, the + * node will be "upgraded" as well as updated. * * @param job The auto ingest job. */ @@ -879,14 +879,19 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen byte[] rawData = nodeData.toArray(); coordinationService.setNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestNodePath, rawData); } - + /** - * Sets the coordination service case node. + * Sets the error flag for case node data given a case directory path. * - * @param caseNodeData The case node data. - * @param caseDirectoryPath The case directory. + * @param caseDirectoryPath The case directory path. + * + * @throws CoordinationService.CoordinationServiceException + * @throws InterruptedException + * @throws CaseNodeData.InvalidDataException */ - void updateCoordinationServiceCaseNode(CaseNodeData caseNodeData, Path caseDirectoryPath) throws CoordinationServiceException, InterruptedException { + private void setCaseNodeDataErrorsOccurred(Path caseDirectoryPath) throws CoordinationServiceException, InterruptedException, CaseNodeData.InvalidDataException { + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); byte[] rawData = caseNodeData.toArray(); coordinationService.setNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString(), rawData); } @@ -1052,8 +1057,8 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen if (null != manifest) { /* - * Update the mapping of case names to manifest paths that is - * used for case deletion. + * Update the mapping of case names to manifest paths that + * is used for case deletion. */ String caseName = manifest.getCaseName(); Path manifestPath = manifest.getFilePath(); @@ -1067,8 +1072,8 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen } /* - * Add a job to the pending jobs queue, the completed jobs list, - * or do crashed job recovery, as required. + * Add a job to the pending jobs queue, the completed jobs + * list, or do crashed job recovery, as required. */ try { byte[] rawData = coordinationService.getNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestPath.toString()); @@ -1088,7 +1093,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen break; case DELETED: /* - * Ignore jobs marked as "deleted." + * Ignore jobs marked as "deleted." */ break; default: @@ -1198,8 +1203,8 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen private void addNewPendingJob(Manifest manifest) throws InterruptedException, AutoIngestJobException { /* * Create the coordination service manifest node data for the job. - * Note that getting the lock will create the node for the job - * (with no data) if it does not already exist. + * Note that getting the lock will create the node for the job (with + * no data) if it does not already exist. * * An exclusive lock is obtained before creating the node data * because another host may have already found the job, obtained an @@ -1229,7 +1234,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen * the node that was processing the job crashed and the processing * status was not updated. * - * @param manifest The manifest for upgrading the node. + * @param manifest The manifest for upgrading the node. * @param jobNodeData The auto ingest job node data. * * @throws InterruptedException if the thread running the input @@ -1265,9 +1270,9 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen } /* - * Update the coordination service manifest node for - * the job. If this fails, leave the recovery to - * another host. + * Update the coordination service manifest node for the + * job. If this fails, leave the recovery to another + * host. */ try { updateCoordinationServiceManifestNode(job); @@ -1286,9 +1291,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen */ if (null != caseDirectoryPath) { try { - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); } catch (CaseNodeData.InvalidDataException ex) { SYS_LOGGER.log(Level.SEVERE, String.format("Error attempting to get case node data for %s", caseDirectoryPath), ex); } @@ -1367,11 +1370,10 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen /* * Try to upgrade/update the coordination service manifest - * node data for the job. It is possible that two hosts - * will both try to obtain the lock to do the upgrade - * operation at the same time. If this happens, the host - * that is holding the lock will complete the upgrade - * operation. + * node data for the job. It is possible that two hosts will + * both try to obtain the lock to do the upgrade operation + * at the same time. If this happens, the host that is + * holding the lock will complete the upgrade operation. */ try (Lock manifestLock = coordinationService.tryGetExclusiveLock(CoordinationService.CategoryNode.MANIFESTS, manifest.getFilePath().toString())) { if (null != manifestLock) { @@ -1953,9 +1955,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen if (currentJob.isCanceled()) { Path caseDirectoryPath = currentJob.getCaseDirectoryPath(); if (null != caseDirectoryPath) { - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); AutoIngestJobLogger jobLogger = new AutoIngestJobLogger(manifestPath, currentJob.getManifest().getDataSourceFileName(), caseDirectoryPath); jobLogger.logJobCancelled(); } @@ -2280,9 +2280,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen if (!dataSource.exists()) { SYS_LOGGER.log(Level.SEVERE, "Missing data source for {0}", manifestPath); currentJob.setErrorsOccurred(true); - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logMissingDataSource(); return null; } @@ -2330,9 +2328,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen // did we find a data source processor that can process the data source if (validDataSourceProcessorsMap.isEmpty()) { // This should never happen. We should add all unsupported data sources as logical files. - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); currentJob.setErrorsOccurred(true); jobLogger.logFailedToIdentifyDataSource(); SYS_LOGGER.log(Level.WARNING, "Unsupported data source {0} for {1}", new Object[]{dataSource.getPath(), manifestPath}); // NON-NLS @@ -2358,9 +2354,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen // Log that the current DSP failed and set the error flag. We consider it an error // if a DSP fails even if a later one succeeds since we expected to be able to process // the data source which each DSP on the list. - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); currentJob.setErrorsOccurred(true); jobLogger.logDataSourceProcessorError(selectedProcessor.getDataSourceType()); SYS_LOGGER.log(Level.SEVERE, "Exception while processing {0} with data source processor {1}", new Object[]{dataSource.getPath(), selectedProcessor.getDataSourceType()}); @@ -2404,9 +2398,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen jobLogger.logDataSourceAdded(); if (dataSource.getContent().isEmpty()) { currentJob.setErrorsOccurred(true); - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logNoDataSourceContent(); } break; @@ -2418,9 +2410,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen jobLogger.logDataSourceAdded(); if (dataSource.getContent().isEmpty()) { currentJob.setErrorsOccurred(true); - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logNoDataSourceContent(); } break; @@ -2430,9 +2420,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen SYS_LOGGER.log(Level.SEVERE, "Critical error running data source processor for {0}: {1}", new Object[]{manifestPath, errorMessage}); } currentJob.setErrorsOccurred(true); - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logFailedToAddDataSource(); break; } @@ -2446,9 +2434,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen */ SYS_LOGGER.log(Level.WARNING, "Cancellation while waiting for data source processor for {0}", manifestPath); currentJob.setErrorsOccurred(true); - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logDataSourceProcessorCancelled(); } } @@ -2502,9 +2488,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen if (!cancelledModules.isEmpty()) { SYS_LOGGER.log(Level.WARNING, String.format("Ingest module(s) cancelled for %s", manifestPath)); currentJob.setErrorsOccurred(true); - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); for (String module : snapshot.getCancelledDataSourceIngestModules()) { SYS_LOGGER.log(Level.WARNING, String.format("%s ingest module cancelled for %s", module, manifestPath)); jobLogger.logIngestModuleCancelled(module); @@ -2514,9 +2498,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen } else { currentJob.setProcessingStage(AutoIngestJob.Stage.CANCELLING, Date.from(Instant.now())); currentJob.setErrorsOccurred(true); - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logAnalysisCancelled(); CancellationReason cancellationReason = snapshot.getCancellationReason(); if (CancellationReason.NOT_CANCELLED != cancellationReason && CancellationReason.USER_CANCELLED != cancellationReason) { @@ -2529,17 +2511,13 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen SYS_LOGGER.log(Level.SEVERE, String.format("%s ingest module startup error for %s", error.getModuleDisplayName(), manifestPath), error.getThrowable()); } currentJob.setErrorsOccurred(true); - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logIngestModuleStartupErrors(); throw new AnalysisStartupException(String.format("Error(s) during ingest module startup for %s", manifestPath)); } else { SYS_LOGGER.log(Level.SEVERE, String.format("Ingest manager ingest job start error for %s", manifestPath), ingestJobStartResult.getStartupException()); currentJob.setErrorsOccurred(true); - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logAnalysisStartupError(); throw new AnalysisStartupException("Ingest manager error starting job", ingestJobStartResult.getStartupException()); } @@ -2548,9 +2526,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen SYS_LOGGER.log(Level.SEVERE, "Ingest job settings error for {0}: {1}", new Object[]{manifestPath, warning}); } currentJob.setErrorsOccurred(true); - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logIngestJobSettingsErrors(); throw new AnalysisStartupException("Error(s) in ingest job settings"); } @@ -2593,9 +2569,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen } catch (FileExportException ex) { SYS_LOGGER.log(Level.SEVERE, String.format("Error doing file export for %s", manifestPath), ex); currentJob.setErrorsOccurred(true); - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logFileExportError(); } } @@ -2938,6 +2912,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen PARTIALLY_DELETED, FULLY_DELETED } + static final class AutoIngestManagerException extends Exception { private static final long serialVersionUID = 1L; @@ -2952,4 +2927,4 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen } -} \ No newline at end of file +} From d09fce22f88ceab27a539a70a204b1b18e6b1b99 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Mon, 13 Nov 2017 07:58:52 -0500 Subject: [PATCH 088/115] x --- .../modules/hashdatabase/HashLookupSettingsPanel.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java index 7d2b782ec1..b6437e7fa5 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java @@ -259,13 +259,14 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan //Checking for for any unindexed databases List unindexed = new ArrayList<>(); for (HashDb hashSet : hashSetManager.getAllHashSets()) { - try { + unindexed.add(hashSet); + /*try { if (!hashSet.hasIndex()) { unindexed.add(hashSet); } } catch (TskCoreException ex) { Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting index info for hash database", ex); //NON-NLS - } + }*/ } //If unindexed ones are found, show a popup box that will either index them, or remove them. From 56c5cd92cb0484646e111f9c7d2f37954a6720ba Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Mon, 13 Nov 2017 08:47:01 -0500 Subject: [PATCH 089/115] Revert changes to the public api --- .../HashDbCreateDatabaseDialog.java | 2 +- .../HashDbImportDatabaseDialog.java | 2 +- .../modules/hashdatabase/HashDbManager.java | 62 ++++++------------- .../hashdatabase/HashLookupModuleFactory.java | 2 +- .../hashdatabase/HashLookupSettingsPanel.java | 18 +++--- .../configuration/SharedConfiguration.java | 4 +- 6 files changed, 31 insertions(+), 59 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java index ab3efb8afb..0bea515d14 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java @@ -338,7 +338,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { String errorMessage = NbBundle .getMessage(this.getClass(), "HashDbCreateDatabaseDialog.errMsg.hashDbCreationErr"); try { - newHashDb = HashDbManager.getInstance().addNewFileTypeHashDatabase(hashSetNameTextField.getText(), fileChooser.getSelectedFile().getCanonicalPath(), true, sendIngestMessagesCheckbox.isSelected(), type); + newHashDb = HashDbManager.getInstance().addNewHashDatabaseNoSave(hashSetNameTextField.getText(), fileChooser.getSelectedFile().getCanonicalPath(), true, sendIngestMessagesCheckbox.isSelected(), type); } catch (IOException ex) { Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.WARNING, errorMessage, ex); JOptionPane.showMessageDialog(this, diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java index 66037cccf9..012544bdab 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java @@ -514,7 +514,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { if(fileTypeRadioButton.isSelected()){ try { - selectedHashDb = HashDbManager.getInstance().addExistingFileTypeHashDatabase(hashSetNameTextField.getText(), selectedFilePath, true, sendIngestMessagesCheckbox.isSelected(), type); + selectedHashDb = HashDbManager.getInstance().addExistingHashDatabaseNoSave(hashSetNameTextField.getText(), selectedFilePath, true, sendIngestMessagesCheckbox.isSelected(), type); } catch (HashDbManagerException ex) { Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, errorMessage, ex); JOptionPane.showMessageDialog(this, diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java index ec28c31747..fb2edad967 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -147,7 +147,6 @@ public class HashDbManager implements PropertyChangeListener { * * @throws HashDbManagerException */ - @Deprecated public synchronized HashDb addExistingHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDbManagerException { HashDb hashDb = null; hashDb = this.addExistingHashDatabaseNoSave(hashSetName, path, searchDuringIngest, sendIngestMessages, knownFilesType); @@ -155,12 +154,7 @@ public class HashDbManager implements PropertyChangeListener { return hashDb; } - @Deprecated synchronized HashDb addExistingHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDbManagerException { - return (HashDb)addExistingFileTypeHashDatabase(hashSetName, path, searchDuringIngest, sendIngestMessages, knownFilesType); - } - - synchronized HashDatabase addExistingFileTypeHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDbManagerException { HashDb hashDb = null; try { if (!new File(path).exists()) { @@ -175,7 +169,7 @@ public class HashDbManager implements PropertyChangeListener { throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.duplicateHashSetNameExceptionMsg", hashSetName)); } - hashDb = addFileTypeHashDatabase(SleuthkitJNI.openHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); + hashDb = addFileHashDatabase(SleuthkitJNI.openHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); } catch (TskCoreException ex) { throw new HashDbManagerException(ex.getMessage()); } @@ -200,7 +194,6 @@ public class HashDbManager implements PropertyChangeListener { * * @throws HashDbManagerException */ - @Deprecated public synchronized HashDb addNewHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDbManagerException { @@ -212,14 +205,8 @@ public class HashDbManager implements PropertyChangeListener { return hashDb; } - @Deprecated public synchronized HashDb addNewHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDbManagerException { - return (HashDb)addNewFileTypeHashDatabase(hashSetName, path, searchDuringIngest, sendIngestMessages, knownFilesType); - } - - public synchronized HashDatabase addNewFileTypeHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, - HashDb.KnownFilesType knownFilesType) throws HashDbManagerException { HashDb hashDb = null; try { File file = new File(path); @@ -239,14 +226,14 @@ public class HashDbManager implements PropertyChangeListener { throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.duplicateHashSetNameExceptionMsg", hashSetName)); } - hashDb = addFileTypeHashDatabase(SleuthkitJNI.createHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); + hashDb = addFileHashDatabase(SleuthkitJNI.createHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); } catch (TskCoreException ex) { throw new HashDbManagerException(ex.getMessage()); } return hashDb; } - private HashDb addFileTypeHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws TskCoreException { + private HashDb addFileHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws TskCoreException { // Wrap an object around the handle. HashDb hashDb = new HashDb(handle, hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); @@ -281,7 +268,7 @@ public class HashDbManager implements PropertyChangeListener { return hashDb; } - public CentralRepoHashDb addExistingCentralRepoHashSet(String hashSetName, String version, int referenceSetID, + CentralRepoHashDb addExistingCentralRepoHashSet(String hashSetName, String version, int referenceSetID, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType, boolean readOnly) throws TskCoreException{ @@ -414,23 +401,22 @@ public class HashDbManager implements PropertyChangeListener { } /** - * Gets all of the hash databases used to classify files as known or known - * bad. + * Gets all of the HashDbs used to classify files as known or known + * bad. Will not return central repository databases. * * @return A list, possibly empty, of hash databases. */ - @Deprecated public synchronized List getAllHashSets() { - return getAllFileTypeHashSets(); + return getAllFileHashSets(); } /** - * Gets all of the file type hash databases used to classify files as known or known + * Gets all of the file hash databases used to classify files as known or known * bad. * * @return A list, possibly empty, of hash databases. */ - public synchronized List getAllFileTypeHashSets() { + synchronized List getAllFileHashSets() { List hashDbs = new ArrayList<>(); this.hashSets.stream().filter((thisSet) -> (thisSet instanceof HashDb)).forEach((thisSet) -> { hashDbs.add((HashDb)thisSet); @@ -440,28 +426,21 @@ public class HashDbManager implements PropertyChangeListener { /** * Gets all of the hash databases used to classify files as known or known - * bad. + * bad. Will add any new central repository databases to the list before + * returning it. * * @return A list, possibly empty, of hash databases. */ - public synchronized List getAllHashDatabases(){ - List hashDbs = new ArrayList<>(); - hashDbs.addAll(this.hashSets); - return hashDbs; - } - - /** - * Adds any new central repository databases to the list of hashes - * before returning a copy of the hash set list - * @return A list, possibly empty, of hash databases. - */ - public synchronized List refreshAndGetAllHashDatabases(){ + synchronized List getAllHashDatabases(){ try{ updateHashSetsFromCentralRepository(); } catch (TskCoreException ex){ Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS } - return getAllHashDatabases(); + + List hashDbs = new ArrayList<>(); + hashDbs.addAll(this.hashSets); + return hashDbs; } /** @@ -469,7 +448,6 @@ public class HashDbManager implements PropertyChangeListener { * * @return A list, possibly empty, of hash databases. */ - @Deprecated public synchronized List getKnownFileHashSets() { List hashDbs = new ArrayList<>(); this.hashSets.stream().filter((thisSet) -> ((thisSet instanceof HashDb) && (thisSet.getKnownFilesType() == HashDb.KnownFilesType.KNOWN))).forEach((thisSet) -> { @@ -483,7 +461,7 @@ public class HashDbManager implements PropertyChangeListener { * * @return A list, possibly empty, of hash databases. */ - public synchronized List getKnownFileHashDatabases() { + synchronized List getKnownFileHashDatabases() { List hashDbs = new ArrayList<>(); this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == HashDb.KnownFilesType.KNOWN)).forEach((db) -> { hashDbs.add(db); @@ -496,7 +474,6 @@ public class HashDbManager implements PropertyChangeListener { * * @return A list, possibly empty, of hash databases. */ - @Deprecated public synchronized List getKnownBadFileHashSets() { List hashDbs = new ArrayList<>(); this.hashSets.stream().filter((thisSet) -> ((thisSet instanceof HashDb) && (thisSet.getKnownFilesType() == HashDb.KnownFilesType.KNOWN_BAD))).forEach((thisSet) -> { @@ -510,7 +487,7 @@ public class HashDbManager implements PropertyChangeListener { * * @return A list, possibly empty, of hash databases. */ - public synchronized List getNotableFileHashDatabases() { + synchronized List getNotableFileHashDatabases() { List hashDbs = new ArrayList<>(); this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == HashDb.KnownFilesType.KNOWN_BAD)).forEach((db) -> { hashDbs.add(db); @@ -523,7 +500,6 @@ public class HashDbManager implements PropertyChangeListener { * * @return A list, possibly empty, of hash databases. */ - @Deprecated public synchronized List getUpdateableHashSets() { List updateableDbs = new ArrayList<>(); List updateableHashSets = getUpdateableHashSets(this.hashSets); @@ -625,7 +601,7 @@ public class HashDbManager implements PropertyChangeListener { if(hashDbInfo.isFileDatabaseType()){ String dbPath = this.getValidFilePath(hashDbInfo.getHashSetName(), hashDbInfo.getPath()); if (dbPath != null) { - addFileTypeHashDatabase(SleuthkitJNI.openHashDatabase(dbPath), hashDbInfo.getHashSetName(), hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(), hashDbInfo.getKnownFilesType()); + addFileHashDatabase(SleuthkitJNI.openHashDatabase(dbPath), hashDbInfo.getHashSetName(), hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(), hashDbInfo.getKnownFilesType()); } else { logger.log(Level.WARNING, Bundle.HashDbManager_noDbPath_message(hashDbInfo.getHashSetName())); allDatabasesLoadedCorrectly = false; diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java index 19a1d5ee21..52ae48c8cd 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java @@ -60,7 +60,7 @@ public class HashLookupModuleFactory extends IngestModuleFactoryAdapter { @Override public IngestModuleIngestJobSettings getDefaultIngestJobSettings() { // All available hash sets are enabled and always calculate hashes is true by default. - return new HashLookupModuleSettings(true, HashDbManager.getInstance().refreshAndGetAllHashDatabases()); + return new HashLookupModuleSettings(true, HashDbManager.getInstance().getAllHashDatabases()); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java index 27249e1e5a..46b636af82 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java @@ -27,7 +27,6 @@ import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import javax.swing.JComponent; -import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JTable; import javax.swing.ListSelectionModel; @@ -306,16 +305,13 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan public void saveSettings() { //Checking for for any unindexed databases List unindexed = new ArrayList<>(); - for (HashDatabase hashSet : hashSetManager.getAllHashDatabases()) { - if(hashSet instanceof HashDb){ - HashDb db = (HashDb)hashSet; - try { - if (!db.hasIndex()) { - unindexed.add(db); - } - } catch (TskCoreException ex) { - Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting index info for hash database", ex); //NON-NLS + for (HashDb db : hashSetManager.getAllFileHashSets()) { + try { + if (!db.hasIndex()) { + unindexed.add(db); } + } catch (TskCoreException ex) { + Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting index info for hash database", ex); //NON-NLS } } @@ -550,7 +546,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan } void refreshModel() { - hashSets = HashDbManager.getInstance().refreshAndGetAllHashDatabases(); + hashSets = HashDbManager.getInstance().getAllHashDatabases(); refreshDisplay(); } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/SharedConfiguration.java b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/SharedConfiguration.java index b715b7d309..ccb2e49e54 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/SharedConfiguration.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/SharedConfiguration.java @@ -1016,7 +1016,7 @@ public class SharedConfiguration { // If a copy of the database is loaded, close it before deleting and copying. if (localDb.exists()) { - List hashDbs = HashDbManager.getInstance().getAllFileTypeHashSets(); + List hashDbs = HashDbManager.getInstance().getAllHashSets(); HashDbManager.HashDb matchingDb = null; for (HashDbManager.HashDb db : hashDbs) { try { @@ -1122,7 +1122,7 @@ public class SharedConfiguration { try { HashDbManager hashDbManager = HashDbManager.getInstance(); hashDbManager.loadLastSavedConfiguration(); - for (HashDb hashDb : hashDbManager.getAllFileTypeHashSets()) { + for (HashDb hashDb : hashDbManager.getAllHashSets()) { if (hashDb.hasIndexOnly()) { results.add(hashDb.getIndexPath()); } else { From bf164a7a565279390e9219ed92fb9190c18d0043 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Mon, 13 Nov 2017 12:37:11 -0500 Subject: [PATCH 090/115] Put dialogs asking if unindexed hash sets should be indexed on the EDT --- .../hashdatabase/HashLookupSettingsPanel.java | 42 ++++++++++++------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java index b6437e7fa5..e4716d3fbb 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java @@ -259,28 +259,37 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan //Checking for for any unindexed databases List unindexed = new ArrayList<>(); for (HashDb hashSet : hashSetManager.getAllHashSets()) { - unindexed.add(hashSet); - /*try { + try { if (!hashSet.hasIndex()) { unindexed.add(hashSet); } } catch (TskCoreException ex) { Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting index info for hash database", ex); //NON-NLS - }*/ + } } - //If unindexed ones are found, show a popup box that will either index them, or remove them. - if (unindexed.size() == 1) { - showInvalidIndex(false, unindexed); - } else if (unindexed.size() > 1) { - showInvalidIndex(true, unindexed); - } - try { - hashSetManager.save(); - } catch (HashDbManager.HashDbManagerException ex) { - SwingUtilities.invokeLater(() -> { - JOptionPane.showMessageDialog(null, Bundle.HashLookupSettingsPanel_saveFail_message(), Bundle.HashLookupSettingsPanel_saveFail_title(), JOptionPane.ERROR_MESSAGE); + // If there are unindexed databases, give the user the option to index them now. This + // needs to be on the EDT, and will save the hash settings after completing + if(! unindexed.isEmpty()){ + SwingUtilities.invokeLater(new Runnable(){ + @Override + public void run(){ + //If unindexed ones are found, show a popup box that will either index them, or remove them. + if (unindexed.size() == 1) { + showInvalidIndex(false, unindexed); + } else if (unindexed.size() > 1) { + showInvalidIndex(true, unindexed); + } + } }); + } else { + try { + hashSetManager.save(); + } catch (HashDbManager.HashDbManagerException ex) { + SwingUtilities.invokeLater(() -> { + JOptionPane.showMessageDialog(null, Bundle.HashLookupSettingsPanel_saveFail_message(), Bundle.HashLookupSettingsPanel_saveFail_title(), JOptionPane.ERROR_MESSAGE); + }); + } } } @@ -353,6 +362,11 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan "HashDbConfigPanel.allUnindexedDbsRmFromListMsg")); removeThese(unindexed); } + try { + hashSetManager.save(); + } catch (HashDbManager.HashDbManagerException ex) { + JOptionPane.showMessageDialog(null, Bundle.HashLookupSettingsPanel_saveFail_message(), Bundle.HashLookupSettingsPanel_saveFail_title(), JOptionPane.ERROR_MESSAGE); + } } boolean valid() { From 5c2b89995e74c9ee7f52135aca1ae61aa23a68aa Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Mon, 13 Nov 2017 13:56:40 -0500 Subject: [PATCH 091/115] Switched around names of HashDb and HashDatabase --- .../datamodel/EamGlobalSet.java | 6 +- .../AddContentToHashDbAction.java | 10 +- .../AddHashValuesToDatabaseDialog.java | 6 +- ...AddHashValuesToDatabaseProgressDialog.java | 6 +- .../HashDbCreateDatabaseDialog.java | 6 +- .../HashDbImportDatabaseDialog.java | 7 +- .../hashdatabase/HashDbIngestModule.java | 22 +- .../modules/hashdatabase/HashDbManager.java | 243 ++++++++---------- .../hashdatabase/HashLookupModuleFactory.java | 2 +- .../HashLookupModuleSettings.java | 16 +- .../HashLookupModuleSettingsPanel.java | 36 +-- .../hashdatabase/HashLookupSettings.java | 28 +- .../hashdatabase/HashLookupSettingsPanel.java | 58 ++--- .../ImportCentralRepoDbProgressDialog.java | 14 +- .../modules/hashdatabase/ModalNoButtons.java | 16 +- .../taggedhashes/AddTaggedHashesToHashDb.java | 4 +- .../AddTaggedHashesToHashDbConfigPanel.form | 2 +- .../AddTaggedHashesToHashDbConfigPanel.java | 14 +- .../configuration/SharedConfiguration.java | 30 ++- 19 files changed, 246 insertions(+), 280 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java index e4292dc6ca..80e7d9cb8b 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java @@ -150,11 +150,11 @@ public class EamGlobalSet { * Return the FileKnown status as a KnownFilesType * @return KNOWN or KNOWN_BAD */ - public HashDbManager.HashDb.KnownFilesType getKnownStatus(){ + public HashDbManager.HashDatabase.KnownFilesType getKnownStatus(){ if(fileKnownStatus.equals(TskData.FileKnown.BAD)){ - return HashDbManager.HashDb.KnownFilesType.KNOWN_BAD; + return HashDbManager.HashDatabase.KnownFilesType.KNOWN_BAD; } - return HashDbManager.HashDb.KnownFilesType.KNOWN; + return HashDbManager.HashDatabase.KnownFilesType.KNOWN; } /** diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddContentToHashDbAction.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddContentToHashDbAction.java index 6c58402fd6..effa123af9 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddContentToHashDbAction.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddContentToHashDbAction.java @@ -35,7 +35,7 @@ import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.HashUtility; import org.sleuthkit.datamodel.TskCoreException; -import static org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; +import static org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * Instances of this Action allow users to content to a hash database. @@ -106,9 +106,9 @@ final class AddContentToHashDbAction extends AbstractAction implements Presenter // Get the current set of updateable hash databases and add each // one to the menu as a separate menu item. Selecting a hash database // adds the selected files to the selected database. - final List hashDatabases = HashDbManager.getInstance().getUpdateableHashDatabases(); + final List hashDatabases = HashDbManager.getInstance().getUpdateableHashSets(); if (!hashDatabases.isEmpty()) { - for (final HashDatabase database : hashDatabases) { + for (final HashDb database : hashDatabases) { JMenuItem databaseItem = add(database.getHashSetName()); databaseItem.addActionListener(new ActionListener() { @Override @@ -134,7 +134,7 @@ final class AddContentToHashDbAction extends AbstractAction implements Presenter newHashSetItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - HashDatabase hashDb = new HashDbCreateDatabaseDialog().getHashDatabase(); + HashDb hashDb = new HashDbCreateDatabaseDialog().getHashDatabase(); if (null != hashDb) { addFilesToHashSet(selectedFiles, hashDb); } @@ -143,7 +143,7 @@ final class AddContentToHashDbAction extends AbstractAction implements Presenter add(newHashSetItem); } - private void addFilesToHashSet(final Collection files, HashDatabase hashSet) { + private void addFilesToHashSet(final Collection files, HashDb hashSet) { for (AbstractFile file : files) { String md5Hash = file.getMd5Hash(); if (null != md5Hash) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java index debe46f47c..1fe05701ce 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java @@ -32,7 +32,7 @@ import javax.swing.SwingUtilities; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.datamodel.HashEntry; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * @@ -40,7 +40,7 @@ import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; */ public class AddHashValuesToDatabaseDialog extends javax.swing.JDialog { - HashDatabase hashDb; + HashDb hashDb; Pattern md5Pattern = Pattern.compile("^[a-fA-F0-9]{32}$"); List hashes = new ArrayList<>(); List invalidHashes = new ArrayList<>(); @@ -49,7 +49,7 @@ public class AddHashValuesToDatabaseDialog extends javax.swing.JDialog { * Displays a dialog that allows a user to add hash values to the selected * database. */ - AddHashValuesToDatabaseDialog(HashDatabase hashDb) { + AddHashValuesToDatabaseDialog(HashDb hashDb) { super((JFrame) WindowManager.getDefault().getMainWindow(), NbBundle.getMessage(AddHashValuesToDatabaseDialog.class, "AddHashValuesToDatabaseDialog.JDialog.Title", hashDb.getHashSetName()), true); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java index 77483e1d42..3f3671c44f 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java @@ -33,7 +33,7 @@ import javax.swing.SwingWorker; import org.openide.util.NbBundle; import org.sleuthkit.datamodel.HashEntry; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * @@ -43,7 +43,7 @@ public class AddHashValuesToDatabaseProgressDialog extends javax.swing.JDialog { private final AddHashValuesToDatabaseDialog parentRef; private boolean disposeParent = false; - private final HashDatabase hashDb; + private final HashDb hashDb; private final List hashes; private final List invalidHashes; private final Pattern md5Pattern; @@ -58,7 +58,7 @@ public class AddHashValuesToDatabaseProgressDialog extends javax.swing.JDialog { * @param hashDb * @param text */ - AddHashValuesToDatabaseProgressDialog(AddHashValuesToDatabaseDialog parent, HashDatabase hashDb, String text) { + AddHashValuesToDatabaseProgressDialog(AddHashValuesToDatabaseDialog parent, HashDb hashDb, String text) { super(parent); initComponents(); display(); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java index 0bea515d14..a794ada72d 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java @@ -35,7 +35,7 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.KnownFilesType; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDbManagerException; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * Instances of this class allow a user to create a new hash database and add it @@ -47,7 +47,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { private static final String DEFAULT_FILE_NAME = NbBundle .getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.defaultFileName"); private JFileChooser fileChooser = null; - private HashDatabase newHashDb = null; + private HashDb newHashDb = null; private final static String LAST_FILE_PATH_KEY = "HashDbCreate_Path"; /** @@ -67,7 +67,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { * * @return A HashDb object or null. */ - HashDatabase getHashDatabase() { + HashDb getHashDatabase() { return newHashDb; } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java index 012544bdab..c281e81db9 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java @@ -36,14 +36,13 @@ import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization; -import org.sleuthkit.autopsy.centralrepository.optionspanel.AddNewOrganizationDialog; import org.sleuthkit.autopsy.centralrepository.optionspanel.ManageOrganizationsDialog; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.KnownFilesType; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDbManagerException; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * Instances of this class allow a user to select an existing hash database and @@ -54,7 +53,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { private JFileChooser fileChooser = new JFileChooser(); private String selectedFilePath = ""; - private HashDatabase selectedHashDb = null; + private HashDb selectedHashDb = null; private final static String LAST_FILE_PATH_KEY = "HashDbImport_Path"; private EamOrganization selectedOrg = null; private List orgs = null; @@ -79,7 +78,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { * * @return A HashDb object or null. */ - HashDatabase getHashDatabase() { + HashDb getHashDatabase() { return selectedHashDb; } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java index 55d91b5fbd..75f477b585 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -36,7 +36,6 @@ import org.sleuthkit.autopsy.ingest.IngestMessage; import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter; import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; @@ -48,6 +47,7 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskException; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; @NbBundle.Messages({ "HashDbIngestModule.noKnownBadHashDbSetMsg=No notable hash database set.", @@ -63,8 +63,8 @@ public class HashDbIngestModule implements FileIngestModule { private final SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); private final HashDbManager hashDbManager = HashDbManager.getInstance(); private final HashLookupModuleSettings settings; - private List knownBadHashSets = new ArrayList<>(); - private List knownHashSets = new ArrayList<>(); + private List knownBadHashSets = new ArrayList<>(); + private List knownHashSets = new ArrayList<>(); private long jobId; private static final HashMap totalsForIngestJobs = new HashMap<>(); private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter(); @@ -96,8 +96,8 @@ public class HashDbIngestModule implements FileIngestModule { if (!hashDbManager.verifyAllDatabasesLoadedCorrectly()) { throw new IngestModuleException("Could not load all hash databases"); } - updateEnabledHashSets(hashDbManager.getNotableFileHashDatabases(), knownBadHashSets); - updateEnabledHashSets(hashDbManager.getKnownFileHashDatabases(), knownHashSets); + updateEnabledHashSets(hashDbManager.getKnownBadFileHashSets(), knownBadHashSets); + updateEnabledHashSets(hashDbManager.getKnownFileHashSets(), knownHashSets); if (refCounter.incrementAndGet(jobId) == 1) { // initialize job totals @@ -126,9 +126,9 @@ public class HashDbIngestModule implements FileIngestModule { * @param allHashSets List of all hashsets from DB manager * @param enabledHashSets List of enabled ones to return. */ - private void updateEnabledHashSets(List allHashSets, List enabledHashSets) { + private void updateEnabledHashSets(List allHashSets, List enabledHashSets) { enabledHashSets.clear(); - for (HashDatabase db : allHashSets) { + for (HashDb db : allHashSets) { if (settings.isHashSetEnabled(db)) { try { if (db.isValid()) { @@ -196,7 +196,7 @@ public class HashDbIngestModule implements FileIngestModule { // look up in notable first boolean foundBad = false; ProcessResult ret = ProcessResult.OK; - for (HashDatabase db : knownBadHashSets) { + for (HashDb db : knownBadHashSets) { try { long lookupstart = System.currentTimeMillis(); HashHitInfo hashInfo = db.lookupMD5(file); @@ -257,7 +257,7 @@ public class HashDbIngestModule implements FileIngestModule { // Any hit is sufficient to classify it as known, and there is no need to create // a hit artifact or send a message to the application inbox. if (!foundBad) { - for (HashDatabase db : knownHashSets) { + for (HashDb db : knownHashSets) { try { long lookupstart = System.currentTimeMillis(); if (db.lookupMD5Quick(file)) { @@ -359,7 +359,7 @@ public class HashDbIngestModule implements FileIngestModule { } private static synchronized void postSummary(long jobId, - List knownBadHashSets, List knownHashSets) { + List knownBadHashSets, List knownHashSets) { IngestJobTotals jobTotals = getTotalsForIngestJobs(jobId); totalsForIngestJobs.remove(jobId); @@ -384,7 +384,7 @@ public class HashDbIngestModule implements FileIngestModule { detailsSb.append("

") //NON-NLS .append(NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.databasesUsed")) .append("

\n
    "); //NON-NLS - for (HashDatabase db : knownBadHashSets) { + for (HashDb db : knownBadHashSets) { detailsSb.append("
  • ").append(db.getHashSetName()).append("
  • \n"); //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java index fb2edad967..59dcd998e0 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -61,7 +61,7 @@ public class HashDbManager implements PropertyChangeListener { private static final String HASH_DATABASE_FILE_EXTENSON = "kdb"; //NON-NLS private static HashDbManager instance = null; - private List hashSets = new ArrayList<>(); + private List hashSets = new ArrayList<>(); private Set hashSetNames = new HashSet<>(); private Set hashSetPaths = new HashSet<>(); PropertyChangeSupport changeSupport = new PropertyChangeSupport(HashDbManager.class); @@ -147,15 +147,15 @@ public class HashDbManager implements PropertyChangeListener { * * @throws HashDbManagerException */ - public synchronized HashDb addExistingHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDbManagerException { - HashDb hashDb = null; + public synchronized HashDatabase addExistingHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDatabase.KnownFilesType knownFilesType) throws HashDbManagerException { + HashDatabase hashDb = null; hashDb = this.addExistingHashDatabaseNoSave(hashSetName, path, searchDuringIngest, sendIngestMessages, knownFilesType); this.save(); return hashDb; } - synchronized HashDb addExistingHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDbManagerException { - HashDb hashDb = null; + synchronized HashDatabase addExistingHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDatabase.KnownFilesType knownFilesType) throws HashDbManagerException { + HashDatabase hashDb = null; try { if (!new File(path).exists()) { throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.hashDbDoesNotExistExceptionMsg", path)); @@ -194,10 +194,10 @@ public class HashDbManager implements PropertyChangeListener { * * @throws HashDbManagerException */ - public synchronized HashDb addNewHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, - HashDb.KnownFilesType knownFilesType) throws HashDbManagerException { + public synchronized HashDatabase addNewHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, + HashDatabase.KnownFilesType knownFilesType) throws HashDbManagerException { - HashDb hashDb = null; + HashDatabase hashDb = null; hashDb = this.addNewHashDatabaseNoSave(hashSetName, path, searchDuringIngest, sendIngestMessages, knownFilesType); this.save(); @@ -205,9 +205,9 @@ public class HashDbManager implements PropertyChangeListener { return hashDb; } - public synchronized HashDb addNewHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, - HashDb.KnownFilesType knownFilesType) throws HashDbManagerException { - HashDb hashDb = null; + public synchronized HashDatabase addNewHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, + HashDatabase.KnownFilesType knownFilesType) throws HashDbManagerException { + HashDatabase hashDb = null; try { File file = new File(path); if (file.exists()) { @@ -233,9 +233,9 @@ public class HashDbManager implements PropertyChangeListener { return hashDb; } - private HashDb addFileHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws TskCoreException { + private HashDatabase addFileHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDatabase.KnownFilesType knownFilesType) throws TskCoreException { // Wrap an object around the handle. - HashDb hashDb = new HashDb(handle, hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); + HashDatabase hashDb = new HashDatabase(handle, hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); // Get the indentity data before updating the collections since the // accessor methods may throw. @@ -300,7 +300,7 @@ public class HashDbManager implements PropertyChangeListener { } - synchronized void indexHashDatabase(HashDb hashDb) { + synchronized void indexHashDatabase(HashDatabase hashDb) { hashDb.addPropertyChangeListener(this); HashDbIndexer creator = new HashDbIndexer(hashDb); creator.execute(); @@ -308,8 +308,8 @@ public class HashDbManager implements PropertyChangeListener { @Override public void propertyChange(PropertyChangeEvent event) { - if (event.getPropertyName().equals(HashDb.Event.INDEXING_DONE.name())) { - HashDb hashDb = (HashDb) event.getNewValue(); + if (event.getPropertyName().equals(HashDatabase.Event.INDEXING_DONE.name())) { + HashDatabase hashDb = (HashDatabase) event.getNewValue(); if (null != hashDb) { try { String indexPath = hashDb.getIndexPath(); @@ -331,12 +331,12 @@ public class HashDbManager implements PropertyChangeListener { * * @throws HashDbManagerException */ - public synchronized void removeHashDatabase(HashDatabase hashDb) throws HashDbManagerException { + public synchronized void removeHashDatabase(HashDb hashDb) throws HashDbManagerException { this.removeHashDatabaseNoSave(hashDb); this.save(); } - public synchronized void removeHashDatabaseNoSave(HashDatabase hashDatabase) throws HashDbManagerException { + public synchronized void removeHashDatabaseNoSave(HashDb hashDb) throws HashDbManagerException { // Don't remove a database if ingest is running boolean ingestIsRunning = IngestManager.getInstance().isIngestRunning(); if (ingestIsRunning) { @@ -346,36 +346,36 @@ public class HashDbManager implements PropertyChangeListener { // and remove its hash set name from the hash set used to ensure unique // hash set names are used, before undertaking These operations will succeed and constitute // a mostly effective removal, even if the subsequent operations fail. - String hashSetName = hashDatabase.getHashSetName(); + String hashSetName = hashDb.getHashSetName(); hashSetNames.remove(hashSetName); - hashSets.remove(hashDatabase); + hashSets.remove(hashDb); // Now undertake the operations that could throw. // Indexing is only relevanet for file type hashsets - if(hashDatabase instanceof HashDb){ - HashDb hashDb = (HashDb)hashDatabase; + if(hashDb instanceof HashDatabase){ + HashDatabase hashDatabase = (HashDatabase)hashDb; try { - if(hashDb.hasIndex()){ - hashSetPaths.remove(hashDb.getIndexPath()); + if(hashDatabase.hasIndex()){ + hashSetPaths.remove(hashDatabase.getIndexPath()); } } catch (TskCoreException ex) { - Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting index path of " + hashDb.getHashSetName() + " hash database when removing the database", ex); //NON-NLS + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting index path of " + hashDatabase.getHashSetName() + " hash database when removing the database", ex); //NON-NLS } try { - if (!hashDb.hasIndexOnly()) { - hashSetPaths.remove(hashDb.getDatabasePath()); + if (!hashDatabase.hasIndexOnly()) { + hashSetPaths.remove(hashDatabase.getDatabasePath()); } } catch (TskCoreException ex) { - Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting database path of " + hashDb.getHashSetName() + " hash database when removing the database", ex); //NON-NLS + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting database path of " + hashDatabase.getHashSetName() + " hash database when removing the database", ex); //NON-NLS } } try { - hashDatabase.close(); + hashDb.close(); } catch (TskCoreException ex) { - Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + hashDatabase.getHashSetName() + " hash database when removing the database", ex); //NON-NLS + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + hashDb.getHashSetName() + " hash database when removing the database", ex); //NON-NLS } // Let any external listeners know that a set has been deleted @@ -399,16 +399,6 @@ public class HashDbManager implements PropertyChangeListener { throw new HashDbManagerException(NbBundle.getMessage(this.getClass(), "HashDbManager.saveErrorExceptionMsg")); } } - - /** - * Gets all of the HashDbs used to classify files as known or known - * bad. Will not return central repository databases. - * - * @return A list, possibly empty, of hash databases. - */ - public synchronized List getAllHashSets() { - return getAllFileHashSets(); - } /** * Gets all of the file hash databases used to classify files as known or known @@ -416,10 +406,10 @@ public class HashDbManager implements PropertyChangeListener { * * @return A list, possibly empty, of hash databases. */ - synchronized List getAllFileHashSets() { - List hashDbs = new ArrayList<>(); - this.hashSets.stream().filter((thisSet) -> (thisSet instanceof HashDb)).forEach((thisSet) -> { - hashDbs.add((HashDb)thisSet); + synchronized List getAllFileHashSets() { + List hashDbs = new ArrayList<>(); + this.hashSets.stream().filter((thisSet) -> (thisSet instanceof HashDatabase)).forEach((thisSet) -> { + hashDbs.add((HashDatabase)thisSet); }); return hashDbs; } @@ -431,14 +421,14 @@ public class HashDbManager implements PropertyChangeListener { * * @return A list, possibly empty, of hash databases. */ - synchronized List getAllHashDatabases(){ + public synchronized List getAllHashSets(){ try{ updateHashSetsFromCentralRepository(); } catch (TskCoreException ex){ Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS } - List hashDbs = new ArrayList<>(); + List hashDbs = new ArrayList<>(); hashDbs.addAll(this.hashSets); return hashDbs; } @@ -450,24 +440,11 @@ public class HashDbManager implements PropertyChangeListener { */ public synchronized List getKnownFileHashSets() { List hashDbs = new ArrayList<>(); - this.hashSets.stream().filter((thisSet) -> ((thisSet instanceof HashDb) && (thisSet.getKnownFilesType() == HashDb.KnownFilesType.KNOWN))).forEach((thisSet) -> { - hashDbs.add((HashDb)thisSet); - }); - return hashDbs; - } - - /** - * Gets all of the hash databases used to classify files as known. - * - * @return A list, possibly empty, of hash databases. - */ - synchronized List getKnownFileHashDatabases() { - List hashDbs = new ArrayList<>(); - this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == HashDb.KnownFilesType.KNOWN)).forEach((db) -> { + this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == HashDatabase.KnownFilesType.KNOWN)).forEach((db) -> { hashDbs.add(db); }); return hashDbs; - } + } /** * Gets all of the hash databases used to classify files as notable. @@ -476,20 +453,7 @@ public class HashDbManager implements PropertyChangeListener { */ public synchronized List getKnownBadFileHashSets() { List hashDbs = new ArrayList<>(); - this.hashSets.stream().filter((thisSet) -> ((thisSet instanceof HashDb) && (thisSet.getKnownFilesType() == HashDb.KnownFilesType.KNOWN_BAD))).forEach((thisSet) -> { - hashDbs.add((HashDb)thisSet); - }); - return hashDbs; - } - - /** - * Gets all of the hash databases used to classify files as notable. - * - * @return A list, possibly empty, of hash databases. - */ - synchronized List getNotableFileHashDatabases() { - List hashDbs = new ArrayList<>(); - this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == HashDb.KnownFilesType.KNOWN_BAD)).forEach((db) -> { + this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == HashDatabase.KnownFilesType.KNOWN_BAD)).forEach((db) -> { hashDbs.add(db); }); return hashDbs; @@ -501,26 +465,12 @@ public class HashDbManager implements PropertyChangeListener { * @return A list, possibly empty, of hash databases. */ public synchronized List getUpdateableHashSets() { - List updateableDbs = new ArrayList<>(); - List updateableHashSets = getUpdateableHashSets(this.hashSets); - updateableHashSets.stream().filter((db) -> (db instanceof HashDb)).forEach((db) -> { - updateableDbs.add((HashDb)db); - }); - return updateableDbs; - } - - /** - * Gets all of the hash databases that accept updates. - * - * @return A list, possibly empty, of hash databases. - */ - public synchronized List getUpdateableHashDatabases(){ return getUpdateableHashSets(this.hashSets); } - private List getUpdateableHashSets(List hashDbs) { - ArrayList updateableDbs = new ArrayList<>(); - for (HashDatabase db : hashDbs) { + private List getUpdateableHashSets(List hashDbs) { + ArrayList updateableDbs = new ArrayList<>(); + for (HashDb db : hashDbs) { try { if (db.isUpdateable()) { updateableDbs.add(db); @@ -542,7 +492,7 @@ public class HashDbManager implements PropertyChangeListener { // Defaults for fields not stored in the central repository: // searchDuringIngest: false // sendIngestMessages: true if the hash set is notable - boolean sendIngestMessages = globalSet.getKnownStatus().equals(HashDb.KnownFilesType.KNOWN_BAD); + boolean sendIngestMessages = globalSet.getKnownStatus().equals(HashDatabase.KnownFilesType.KNOWN_BAD); crHashSets.add(new HashDbInfo(globalSet.getSetName(), globalSet.getVersion(), globalSet.getGlobalSetID(), globalSet.getKnownStatus(), globalSet.isReadOnly(), false, sendIngestMessages)); } @@ -565,8 +515,8 @@ public class HashDbManager implements PropertyChangeListener { loadHashsetsConfiguration(); } - private void closeHashDatabases(List hashDatabases) { - for (HashDatabase database : hashDatabases) { + private void closeHashDatabases(List hashDatabases) { + for (HashDb database : hashDatabases) { try { database.close(); } catch (TskCoreException ex) { @@ -672,7 +622,7 @@ public class HashDbManager implements PropertyChangeListener { } private boolean hashDbInfoIsNew(HashDbInfo dbInfo){ - for(HashDatabase db:this.hashSets){ + for(HashDb db:this.hashSets){ if(dbInfo.matches(db)){ return false; } @@ -727,7 +677,35 @@ public class HashDbManager implements PropertyChangeListener { return filePath; } - public static interface HashDatabase { + public static interface HashDb { + + /** + * Indicates how files with hashes stored in a particular hash database + * object should be classified. + */ + public enum KnownFilesType { + + KNOWN(NbBundle.getMessage(HashDbManager.class, "HashDbManager.known.text")), + KNOWN_BAD(NbBundle.getMessage(HashDbManager.class, "HashDbManager.knownBad.text")); + private final String displayName; + + private KnownFilesType(String displayName) { + this.displayName = displayName; + } + + public String getDisplayName() { + return this.displayName; + } + } + + /** + * Property change events published by hash database objects. + */ + public enum Event { + + INDEXING_DONE + } + enum DatabaseType{ FILE, CENTRAL_REPOSITORY @@ -739,7 +717,7 @@ public class HashDbManager implements PropertyChangeListener { public String getDatabasePath() throws TskCoreException; - public HashDb.KnownFilesType getKnownFilesType(); + public HashDatabase.KnownFilesType getKnownFilesType(); public boolean getSearchDuringIngest(); @@ -788,6 +766,10 @@ public class HashDbManager implements PropertyChangeListener { public int getHandle(); + public String getIndexPath() throws TskCoreException; + + public boolean hasIndexOnly() throws TskCoreException; + public void firePropertyChange(String propertyName, Object oldValue, Object newValue); public void addPropertyChangeListener(PropertyChangeListener pcl); @@ -808,44 +790,18 @@ public class HashDbManager implements PropertyChangeListener { * Instances of this class represent hash databases used to classify files * as known or know bad. */ - public static class HashDb implements HashDatabase{ - - /** - * Indicates how files with hashes stored in a particular hash database - * object should be classified. - */ - public enum KnownFilesType { - - KNOWN(NbBundle.getMessage(HashDbManager.class, "HashDbManager.known.text")), - KNOWN_BAD(NbBundle.getMessage(HashDbManager.class, "HashDbManager.knownBad.text")); - private final String displayName; - - private KnownFilesType(String displayName) { - this.displayName = displayName; - } - - public String getDisplayName() { - return this.displayName; - } - } - - /** - * Property change events published by hash database objects. - */ - public enum Event { - - INDEXING_DONE - } + public static class HashDatabase implements HashDb{ + private static final long serialVersionUID = 1L; private final int handle; private final String hashSetName; private boolean searchDuringIngest; private boolean sendIngestMessages; - private final HashDb.KnownFilesType knownFilesType; + private final HashDatabase.KnownFilesType knownFilesType; private boolean indexing; private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); - private HashDb(int handle, String hashSetName, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType) { + private HashDatabase(int handle, String hashSetName, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType) { this.handle = handle; this.hashSetName = hashSetName; this.searchDuringIngest = useForIngest; @@ -1058,6 +1014,7 @@ public class HashDbManager implements PropertyChangeListener { return SleuthkitJNI.hashDatabaseHasLookupIndex(handle); } + @Override public boolean hasIndexOnly() throws TskCoreException { return SleuthkitJNI.hashDatabaseIsIndexOnly(handle); } @@ -1104,7 +1061,7 @@ public class HashDbManager implements PropertyChangeListener { if (getClass() != obj.getClass()) { return false; } - final HashDb other = (HashDb) obj; + final HashDatabase other = (HashDatabase) obj; if (!Objects.equals(this.hashSetName, other.hashSetName)) { return false; } @@ -1119,13 +1076,13 @@ public class HashDbManager implements PropertyChangeListener { * Instances of this class represent hash databases used to classify files * as known or know bad. */ - public static class CentralRepoHashDb implements HashDatabase{ + public static class CentralRepoHashDb implements HashDb{ private static final long serialVersionUID = 1L; private final String hashSetName; private boolean searchDuringIngest; private boolean sendIngestMessages; - private final HashDb.KnownFilesType knownFilesType; + private final HashDatabase.KnownFilesType knownFilesType; private final int referenceSetID; private final String version; private String orgName; @@ -1134,7 +1091,7 @@ public class HashDbManager implements PropertyChangeListener { @Messages({"HashDbManager.CentralRepoHashDb.orgError=Error loading organization"}) private CentralRepoHashDb(String hashSetName, String version, int referenceSetID, - boolean useForIngest, boolean sendHitMessages, HashDb.KnownFilesType knownFilesType, + boolean useForIngest, boolean sendHitMessages, HashDatabase.KnownFilesType knownFilesType, boolean readOnly) throws TskCoreException{ this.hashSetName = hashSetName; @@ -1148,7 +1105,7 @@ public class HashDbManager implements PropertyChangeListener { try{ orgName = EamDb.getInstance().getReferenceSetOrganization(referenceSetID).getName(); } catch (EamDbException ex){ - Logger.getLogger(HashDb.class.getName()).log(Level.SEVERE, "Error looking up central repository organization", ex); //NON-NLS + Logger.getLogger(HashDatabase.class.getName()).log(Level.SEVERE, "Error looking up central repository organization", ex); //NON-NLS orgName = Bundle.HashDbManager_CentralRepoHashDb_orgError(); } } @@ -1178,6 +1135,11 @@ public class HashDbManager implements PropertyChangeListener { public int getHandle(){ return 0; } + + @Override + public boolean hasIndexOnly() throws TskCoreException{ + return true; + } @Override public String getHashSetName() { @@ -1211,12 +1173,13 @@ public class HashDbManager implements PropertyChangeListener { return DatabaseType.CENTRAL_REPOSITORY; } + @Override public String getIndexPath() throws TskCoreException { return ""; } @Override - public HashDb.KnownFilesType getKnownFilesType() { + public HashDatabase.KnownFilesType getKnownFilesType() { return knownFilesType; } @@ -1319,7 +1282,7 @@ public class HashDbManager implements PropertyChangeListener { try{ return EamDb.getInstance().isHashInReferenceSet(file.getMd5Hash(), this.referenceSetID); } catch (EamDbException ex){ - Logger.getLogger(HashDb.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup", ex); //NON-NLS + Logger.getLogger(HashDatabase.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup", ex); //NON-NLS throw new TskCoreException("Error performing central reposiotry hash lookup", ex); } } @@ -1350,7 +1313,7 @@ public class HashDbManager implements PropertyChangeListener { result = new HashHitInfo(file.getMd5Hash(), "", ""); } } catch (EamDbException ex){ - Logger.getLogger(HashDb.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup", ex); //NON-NLS + Logger.getLogger(HashDatabase.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup", ex); //NON-NLS throw new TskCoreException("Error performing central reposiotry hash lookup", ex); } } @@ -1431,9 +1394,9 @@ public class HashDbManager implements PropertyChangeListener { private class HashDbIndexer extends SwingWorker { private ProgressHandle progress = null; - private HashDb hashDb = null; + private HashDatabase hashDb = null; - HashDbIndexer(HashDb hashDb) { + HashDbIndexer(HashDatabase hashDb) { this.hashDb = hashDb; } @@ -1447,7 +1410,7 @@ public class HashDbManager implements PropertyChangeListener { try { SleuthkitJNI.createLookupIndexForHashDatabase(hashDb.getHandle()); } catch (TskCoreException ex) { - Logger.getLogger(HashDb.class.getName()).log(Level.SEVERE, "Error indexing hash database", ex); //NON-NLS + Logger.getLogger(HashDatabase.class.getName()).log(Level.SEVERE, "Error indexing hash database", ex); //NON-NLS JOptionPane.showMessageDialog(null, NbBundle.getMessage(this.getClass(), "HashDbManager.dlgMsg.errorIndexingHashSet", @@ -1477,7 +1440,7 @@ public class HashDbManager implements PropertyChangeListener { } try { - hashDb.firePropertyChange(HashDb.Event.INDEXING_DONE.toString(), null, hashDb); + hashDb.firePropertyChange(HashDatabase.Event.INDEXING_DONE.toString(), null, hashDb); hashDb.firePropertyChange(HashDbManager.SetEvt.DB_INDEXED.toString(), null, hashDb.getHashSetName()); } catch (Exception e) { logger.log(Level.SEVERE, "HashDbManager listener threw exception", e); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java index 52ae48c8cd..2fb515832b 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java @@ -60,7 +60,7 @@ public class HashLookupModuleFactory extends IngestModuleFactoryAdapter { @Override public IngestModuleIngestJobSettings getDefaultIngestJobSettings() { // All available hash sets are enabled and always calculate hashes is true by default. - return new HashLookupModuleSettings(true, HashDbManager.getInstance().getAllHashDatabases()); + return new HashLookupModuleSettings(true, HashDbManager.getInstance().getAllHashSets()); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettings.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettings.java index 9923c7f21b..3e331cb1da 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettings.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettings.java @@ -26,8 +26,8 @@ import java.io.IOException; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupSettings.HashDbInfo; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * Ingest job settings for the hash lookup module. @@ -42,7 +42,7 @@ final class HashLookupModuleSettings implements IngestModuleIngestJobSettings { private boolean shouldCalculateHashes = true; private List databaseInfoList; - HashLookupModuleSettings(boolean shouldCalculateHashes, List hashDbList){ + HashLookupModuleSettings(boolean shouldCalculateHashes, List hashDbList){ this.shouldCalculateHashes = shouldCalculateHashes; try{ databaseInfoList = HashLookupSettings.convertHashSetList(hashDbList); @@ -76,12 +76,12 @@ final class HashLookupModuleSettings implements IngestModuleIngestJobSettings { * @param disabledHashSets A list of disabled hash sets. */ HashLookupModuleSettings(boolean shouldCalculateHashes, - List enabledHashSets, - List disabledHashSets) { + List enabledHashSets, + List disabledHashSets) { this.shouldCalculateHashes = shouldCalculateHashes; databaseInfoList = new ArrayList<>(); - for(HashDatabase db:enabledHashSets){ + for(HashDb db:enabledHashSets){ try{ HashDbInfo dbInfo = new HashDbInfo(db); dbInfo.setSearchDuringIngest(true); @@ -90,7 +90,7 @@ final class HashLookupModuleSettings implements IngestModuleIngestJobSettings { Logger.getLogger(HashLookupModuleSettings.class.getName()).log(Level.SEVERE, "Error creating hash database settings for " + db.getHashSetName(), ex); //NON-NLS } } - for(HashDatabase db:disabledHashSets){ + for(HashDb db:disabledHashSets){ try{ HashDbInfo dbInfo = new HashDbInfo(db); dbInfo.setSearchDuringIngest(false); @@ -128,7 +128,7 @@ final class HashLookupModuleSettings implements IngestModuleIngestJobSettings { * * @return True if the hash set is enabled, false otherwise. */ - boolean isHashSetEnabled(HashDatabase db) { + boolean isHashSetEnabled(HashDb db) { for(HashDbInfo dbInfo:databaseInfoList){ if(dbInfo.matches(db)){ return dbInfo.getSearchDuringIngest(); @@ -150,7 +150,7 @@ final class HashLookupModuleSettings implements IngestModuleIngestJobSettings { } try{ - databaseInfoList = HashLookupSettings.convertHashSetList(HashDbManager.getInstance().getAllHashDatabases()); + databaseInfoList = HashLookupSettings.convertHashSetList(HashDbManager.getInstance().getAllHashSets()); } catch (HashLookupSettings.HashLookupSettingsException ex){ Logger.getLogger(HashLookupModuleSettings.class.getName()).log(Level.SEVERE, "Error updating hash database settings.", ex); //NON-NLS return; diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java index 1e83fb77c6..c6d3e109fe 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java @@ -30,8 +30,8 @@ import javax.swing.table.TableColumn; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** @@ -58,13 +58,13 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe } catch (TskCoreException ex){ Logger.getLogger(HashLookupModuleSettingsPanel.class.getName()).log(Level.SEVERE, "Error updating central repository hash sets", ex); //NON-NLS } - initializeHashSetModels(settings, hashDbManager.getKnownFileHashDatabases(), knownHashSetModels); - initializeHashSetModels(settings, hashDbManager.getNotableFileHashDatabases(), knownBadHashSetModels); + initializeHashSetModels(settings, hashDbManager.getKnownFileHashSets(), knownHashSetModels); + initializeHashSetModels(settings, hashDbManager.getKnownBadFileHashSets(), knownBadHashSetModels); } - private void initializeHashSetModels(HashLookupModuleSettings settings, List hashDbs, List hashSetModels) { + private void initializeHashSetModels(HashLookupModuleSettings settings, List hashDbs, List hashSetModels) { hashSetModels.clear(); - for (HashDatabase db : hashDbs) { + for (HashDb db : hashDbs) { hashSetModels.add(new HashSetModel(db, settings.isHashSetEnabled(db), isHashDbValid(db))); } } @@ -105,15 +105,15 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe @Override public IngestModuleIngestJobSettings getSettings() { - List enabledHashSets = new ArrayList<>(); - List disabledHashSets = new ArrayList<>(); + List enabledHashSets = new ArrayList<>(); + List disabledHashSets = new ArrayList<>(); addHashSets(knownHashSetModels, enabledHashSets, disabledHashSets); addHashSets(knownBadHashSetModels, enabledHashSets, disabledHashSets); return new HashLookupModuleSettings(alwaysCalcHashesCheckbox.isSelected(), enabledHashSets, disabledHashSets); } - private void addHashSets(List hashSetModels, List enabledHashSets, List disabledHashSets) { + private void addHashSets(List hashSetModels, List enabledHashSets, List disabledHashSets) { for (HashSetModel model : hashSetModels) { if (model.isEnabled() && model.isValid()) { enabledHashSets.add(model.getDatabase()); @@ -130,19 +130,19 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe } private void updateHashSetModels() { - updateHashSetModels(hashDbManager.getKnownFileHashDatabases(), knownHashSetModels); - updateHashSetModels(hashDbManager.getNotableFileHashDatabases(), knownBadHashSetModels); + updateHashSetModels(hashDbManager.getKnownFileHashSets(), knownHashSetModels); + updateHashSetModels(hashDbManager.getKnownBadFileHashSets(), knownBadHashSetModels); } - void updateHashSetModels(List hashDbs, List hashSetModels) { + void updateHashSetModels(List hashDbs, List hashSetModels) { - List hashDatabases = new ArrayList<>(hashDbs); + List hashDatabases = new ArrayList<>(hashDbs); // Update the hash sets and detect deletions. List deletedHashSetModels = new ArrayList<>(); for (HashSetModel model : hashSetModels) { boolean foundDatabase = false; - for(HashDatabase db : hashDatabases){ + for(HashDb db : hashDatabases){ if(model.getDatabase().equals(db)){ model.setValid(isHashDbValid(db)); hashDatabases.remove(db); @@ -161,7 +161,7 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe } // Add any new hash sets. All new sets are enabled by default. - for (HashDatabase db : hashDatabases) { + for (HashDb db : hashDatabases) { hashSetModels.add(new HashSetModel(db, true, isHashDbValid(db))); } } @@ -173,7 +173,7 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe knownBadHashSetsTableModel.fireTableDataChanged(); } - private boolean isHashDbValid(HashDatabase hashDb) { + private boolean isHashDbValid(HashDb hashDb) { boolean isValid = false; try { isValid = hashDb.isValid(); @@ -185,17 +185,17 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe private static final class HashSetModel { - private final HashDatabase db; + private final HashDb db; private boolean valid; private boolean enabled; - HashSetModel(HashDatabase db, boolean enabled, boolean valid) { + HashSetModel(HashDb db, boolean enabled, boolean valid) { this.db = db; this.enabled = enabled; this.valid = valid; } - HashDatabase getDatabase(){ + HashDb getDatabase(){ return db; } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java index 89d807d507..5dda017e54 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java @@ -36,13 +36,13 @@ import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.XMLUtil; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase.DatabaseType; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.DatabaseType; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.CentralRepoHashDb; import org.sleuthkit.datamodel.TskCoreException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * Class to represent the settings to be serialized for hash lookup. @@ -74,9 +74,9 @@ final class HashLookupSettings implements Serializable { this.hashDbInfoList = hashDbInfoList; } - static List convertHashSetList(List hashSets) throws HashLookupSettingsException{ + static List convertHashSetList(List hashSets) throws HashLookupSettingsException{ List dbInfoList = new ArrayList<>(); - for(HashDbManager.HashDatabase db:hashSets){ + for(HashDbManager.HashDb db:hashSets){ try{ dbInfoList.add(new HashDbInfo(db)); } catch (TskCoreException ex){ @@ -202,7 +202,7 @@ final class HashLookupSettings implements Serializable { // Handle legacy known files types. if (knownFilesType.equals("NSRL")) { //NON-NLS - knownFilesType = HashDbManager.HashDb.KnownFilesType.KNOWN.toString(); + knownFilesType = HashDbManager.HashDatabase.KnownFilesType.KNOWN.toString(); updatedSchema = true; } @@ -236,7 +236,7 @@ final class HashLookupSettings implements Serializable { } else { throw new HashLookupSettingsException(String.format(elementErrorMessage, PATH_ELEMENT)); } - hashDbInfoList.add(new HashDbInfo(hashSetName, HashDbManager.HashDb.KnownFilesType.valueOf(knownFilesType), + hashDbInfoList.add(new HashDbInfo(hashSetName, HashDbManager.HashDatabase.KnownFilesType.valueOf(knownFilesType), searchDuringIngestFlag, sendIngestMessagesFlag, dbPath)); hashSetNames.add(hashSetName); } @@ -299,7 +299,7 @@ final class HashLookupSettings implements Serializable { private static final long serialVersionUID = 1L; private final String hashSetName; - private final HashDbManager.HashDb.KnownFilesType knownFilesType; + private final HashDbManager.HashDatabase.KnownFilesType knownFilesType; private boolean searchDuringIngest; private final boolean sendIngestMessages; private final String path; @@ -318,7 +318,7 @@ final class HashLookupSettings implements Serializable { * @param sendIngestMessages Whether or not ingest messages are sent * @param path The path to the db */ - HashDbInfo(String hashSetName, HashDbManager.HashDb.KnownFilesType knownFilesType, boolean searchDuringIngest, boolean sendIngestMessages, String path) { + HashDbInfo(String hashSetName, HashDbManager.HashDatabase.KnownFilesType knownFilesType, boolean searchDuringIngest, boolean sendIngestMessages, String path) { this.hashSetName = hashSetName; this.knownFilesType = knownFilesType; this.searchDuringIngest = searchDuringIngest; @@ -330,7 +330,7 @@ final class HashLookupSettings implements Serializable { this.dbType = DatabaseType.FILE; } - HashDbInfo(String hashSetName, String version, int referenceSetID, HashDbManager.HashDb.KnownFilesType knownFilesType, boolean readOnly, boolean searchDuringIngest, boolean sendIngestMessages){ + HashDbInfo(String hashSetName, String version, int referenceSetID, HashDbManager.HashDatabase.KnownFilesType knownFilesType, boolean readOnly, boolean searchDuringIngest, boolean sendIngestMessages){ this.hashSetName = hashSetName; this.version = version; this.referenceSetID = referenceSetID; @@ -342,9 +342,9 @@ final class HashLookupSettings implements Serializable { dbType = DatabaseType.CENTRAL_REPOSITORY; } - HashDbInfo(HashDbManager.HashDatabase db) throws TskCoreException{ - if(db instanceof HashDbManager.HashDb){ - HashDbManager.HashDb fileTypeDb = (HashDbManager.HashDb)db; + HashDbInfo(HashDbManager.HashDb db) throws TskCoreException{ + if(db instanceof HashDbManager.HashDatabase){ + HashDbManager.HashDatabase fileTypeDb = (HashDbManager.HashDatabase)db; this.hashSetName = fileTypeDb.getHashSetName(); this.knownFilesType = fileTypeDb.getKnownFilesType(); this.searchDuringIngest = fileTypeDb.getSearchDuringIngest(); @@ -402,7 +402,7 @@ final class HashLookupSettings implements Serializable { * * @return The known files type setting. */ - HashDbManager.HashDb.KnownFilesType getKnownFilesType() { + HashDbManager.HashDatabase.KnownFilesType getKnownFilesType() { return knownFilesType; } @@ -457,7 +457,7 @@ final class HashLookupSettings implements Serializable { return dbType == DatabaseType.CENTRAL_REPOSITORY; } - boolean matches(HashDatabase hashDb){ + boolean matches(HashDb hashDb){ if(hashDb == null){ return false; } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java index 46b636af82..ef8986af24 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java @@ -45,11 +45,11 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.CentralRepoHashDb; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.KnownFilesType; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * Instances of this class provide a comprehensive UI for managing the hash sets @@ -108,7 +108,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan } private void updateComponents() { - HashDatabase db = ((HashSetTable) hashSetTable).getSelection(); + HashDb db = ((HashSetTable) hashSetTable).getSelection(); if (db != null) { updateComponentsForSelection(db); } else { @@ -157,7 +157,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan "HashLookupSettingsPanel.notApplicable=N/A", "HashLookupSettingsPanel.centralRepo=Central Repository" }) - private void updateComponentsForSelection(HashDatabase db) { + private void updateComponentsForSelection(HashDb db) { boolean ingestIsRunning = IngestManager.getInstance().isIngestRunning(); // Update descriptive labels. @@ -180,8 +180,8 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan addHashesToDatabaseButton.setEnabled(false); } - if(db instanceof HashDb){ - HashDb hashDb = (HashDb)db; + if(db instanceof HashDatabase){ + HashDatabase hashDb = (HashDatabase)db; // Disable the central repo fields hashDbVersionLabel.setText(Bundle.HashLookupSettingsPanel_notApplicable()); @@ -304,8 +304,8 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan "HashLookupSettingsPanel.saveFail.title=Save Fail"}) public void saveSettings() { //Checking for for any unindexed databases - List unindexed = new ArrayList<>(); - for (HashDb db : hashSetManager.getAllFileHashSets()) { + List unindexed = new ArrayList<>(); + for (HashDatabase db : hashSetManager.getAllFileHashSets()) { try { if (!db.hasIndex()) { unindexed.add(db); @@ -370,8 +370,8 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan } @Messages({"# {0} - hash lookup name", "HashLookupSettingsPanel.removeDatabaseFailure.message=Failed to remove hash lookup: {0}"}) - void removeThese(List toRemove) { - for (HashDb hashDb : toRemove) { + void removeThese(List toRemove) { + for (HashDatabase hashDb : toRemove) { try { hashSetManager.removeHashDatabaseNoSave(hashDb); } catch (HashDbManager.HashDbManagerException ex) { @@ -389,10 +389,10 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan * @param plural Whether or not there are multiple unindexed databases * @param unindexed The list of unindexed databases. Can be of size 1. */ - private void showInvalidIndex(boolean plural, List unindexed) { + private void showInvalidIndex(boolean plural, List unindexed) { String total = ""; String message; - for (HashDatabase hdb : unindexed) { + for (HashDb hdb : unindexed) { total += "\n" + hdb.getHashSetName(); } if (plural) { @@ -445,7 +445,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan return cellRenderer; } - public HashDatabase getSelection() { + public HashDb getSelection() { return hashSetTableModel.getHashSetAt(getSelectionModel().getMinSelectionIndex()); } @@ -455,7 +455,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan } } - public void selectRowByDatabase(HashDatabase db){ + public void selectRowByDatabase(HashDb db){ setSelection(hashSetTableModel.getIndexByDatabase(db)); } @@ -471,7 +471,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan */ private class HashSetTableModel extends AbstractTableModel { - List hashSets = HashDbManager.getInstance().getAllHashDatabases(); + List hashSets = HashDbManager.getInstance().getAllHashSets(); @Override public int getColumnCount() { @@ -518,7 +518,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan return getValueAt(0, c).getClass(); } - HashDatabase getHashSetAt(int index) { + HashDb getHashSetAt(int index) { if (!hashSets.isEmpty() && index >= 0 && index < hashSets.size()) { return hashSets.get(index); } else { @@ -526,7 +526,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan } } - int getIndexByDatabase(HashDatabase db){ + int getIndexByDatabase(HashDb db){ for (int i = 0; i < hashSets.size(); ++i) { if (hashSets.get(i).equals(db)) { return i; @@ -546,7 +546,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan } void refreshModel() { - hashSets = HashDbManager.getInstance().getAllHashDatabases(); + hashSets = HashDbManager.getInstance().getAllHashSets(); refreshDisplay(); } @@ -910,12 +910,12 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan private void addHashesToDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addHashesToDatabaseButtonActionPerformed - HashDatabase hashDb = ((HashSetTable) hashSetTable).getSelection(); + HashDb hashDb = ((HashSetTable) hashSetTable).getSelection(); AddHashValuesToDatabaseDialog dialog = new AddHashValuesToDatabaseDialog(hashDb); }//GEN-LAST:event_addHashesToDatabaseButtonActionPerformed private void createDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createDatabaseButtonActionPerformed - HashDatabase hashDb = new HashDbCreateDatabaseDialog().getHashDatabase(); + HashDb hashDb = new HashDbCreateDatabaseDialog().getHashDatabase(); if (null != hashDb) { hashSetTableModel.refreshModel(); ((HashSetTable) hashSetTable).selectRowByDatabase(hashDb); @@ -924,7 +924,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan }//GEN-LAST:event_createDatabaseButtonActionPerformed private void sendIngestMessagesCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sendIngestMessagesCheckBoxActionPerformed - HashDatabase hashDb = ((HashSetTable) hashSetTable).getSelection(); + HashDb hashDb = ((HashSetTable) hashSetTable).getSelection(); if (hashDb != null) { hashDb.setSendIngestMessages(sendIngestMessagesCheckBox.isSelected()); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); @@ -932,18 +932,18 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan }//GEN-LAST:event_sendIngestMessagesCheckBoxActionPerformed private void indexButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_indexButtonActionPerformed - final HashDatabase hashDatabase = ((HashSetTable) hashSetTable).getSelection(); + final HashDb hashDatabase = ((HashSetTable) hashSetTable).getSelection(); assert hashDatabase != null; - assert hashDatabase instanceof HashDb; + assert hashDatabase instanceof HashDatabase; // Add a listener for the INDEXING_DONE event. This listener will update // the UI. - HashDb hashDb = (HashDb)hashDatabase; + HashDatabase hashDb = (HashDatabase)hashDatabase; hashDb.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(HashDb.Event.INDEXING_DONE.toString())) { - HashDatabase selectedHashDb = ((HashSetTable) hashSetTable).getSelection(); + if (evt.getPropertyName().equals(HashDatabase.Event.INDEXING_DONE.toString())) { + HashDb selectedHashDb = ((HashSetTable) hashSetTable).getSelection(); if (selectedHashDb != null && hashDb != null && hashDb.equals(selectedHashDb)) { updateComponents(); } @@ -964,7 +964,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan }//GEN-LAST:event_indexButtonActionPerformed private void importDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importDatabaseButtonActionPerformed - HashDatabase hashDb = new HashDbImportDatabaseDialog().getHashDatabase(); + HashDb hashDb = new HashDbImportDatabaseDialog().getHashDatabase(); if (null != hashDb) { if(hashDb instanceof CentralRepoHashDb){ int newReferenceSetID = ((CentralRepoHashDb)hashDb).getReferenceSetID(); @@ -985,7 +985,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.deleteDbActionMsg"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) { - HashDatabase hashDb = ((HashSetTable) hashSetTable).getSelection(); + HashDb hashDb = ((HashSetTable) hashSetTable).getSelection(); if (hashDb != null) { try { hashSetManager.removeHashDatabaseNoSave(hashDb); @@ -1000,7 +1000,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan private void hashSetTableKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_hashSetTableKeyPressed if (evt.getKeyCode() == KeyEvent.VK_DELETE) { - HashDatabase hashDb = ((HashSetTable) hashSetTable).getSelection(); + HashDb hashDb = ((HashSetTable) hashSetTable).getSelection(); if (hashDb != null) { try { hashSetManager.removeHashDatabaseNoSave(hashDb); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java index 397b4948cf..6f14459eb6 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java @@ -77,7 +77,7 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P } void importFile(String hashSetName, String version, int orgId, - boolean searchDuringIngest, boolean sendIngestMessages, HashDbManager.HashDb.KnownFilesType knownFilesType, + boolean searchDuringIngest, boolean sendIngestMessages, HashDbManager.HashDatabase.KnownFilesType knownFilesType, boolean readOnly, String importFileName){ setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); @@ -92,7 +92,7 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P this.setVisible(true); } - HashDbManager.HashDatabase getDatabase(){ + HashDbManager.HashDb getDatabase(){ if(worker != null){ return worker.getDatabase(); } @@ -128,7 +128,7 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P void addPropertyChangeListener(PropertyChangeListener dialog); int getProgressPercentage(); long getLinesProcessed(); - HashDbManager.HashDatabase getDatabase(); + HashDbManager.HashDb getDatabase(); } class ImportIDXWorker extends SwingWorker implements CentralRepoImportWorker{ @@ -139,7 +139,7 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P private final int orgId; private final boolean searchDuringIngest; private final boolean sendIngestMessages; - private final HashDbManager.HashDb.KnownFilesType knownFilesType; + private final HashDbManager.HashDatabase.KnownFilesType knownFilesType; private final boolean readOnly; private final File importFile; private final long totalLines; @@ -148,7 +148,7 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P private final AtomicLong numLines = new AtomicLong(); ImportIDXWorker(String hashSetName, String version, int orgId, - boolean searchDuringIngest, boolean sendIngestMessages, HashDbManager.HashDb.KnownFilesType knownFilesType, + boolean searchDuringIngest, boolean sendIngestMessages, HashDbManager.HashDatabase.KnownFilesType knownFilesType, boolean readOnly, File importFile){ this.hashSetName = hashSetName; @@ -176,7 +176,7 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P } @Override - public HashDbManager.HashDatabase getDatabase(){ + public HashDbManager.HashDb getDatabase(){ return newHashDb; } @@ -194,7 +194,7 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P protected Void doInBackground() throws Exception { TskData.FileKnown knownStatus; - if (knownFilesType.equals(HashDbManager.HashDb.KnownFilesType.KNOWN)) { + if (knownFilesType.equals(HashDbManager.HashDatabase.KnownFilesType.KNOWN)) { knownStatus = TskData.FileKnown.KNOWN; } else { knownStatus = TskData.FileKnown.BAD; diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ModalNoButtons.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ModalNoButtons.java index 33f65488d2..5795233479 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ModalNoButtons.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ModalNoButtons.java @@ -26,7 +26,7 @@ import java.util.List; import javax.swing.JOptionPane; import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; /** * This class exists as a stop-gap measure to force users to have an indexed @@ -43,8 +43,8 @@ import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; */ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListener { - List unindexed; - HashDb toIndex; + List unindexed; + HashDatabase toIndex; HashLookupSettingsPanel hdbmp; int length = 0; int currentcount = 1; @@ -58,7 +58,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen * @param parent Swing parent frame. * @param unindexed the list of unindexed databases to index. */ - ModalNoButtons(HashLookupSettingsPanel hdbmp, java.awt.Frame parent, List unindexed) { + ModalNoButtons(HashLookupSettingsPanel hdbmp, java.awt.Frame parent, List unindexed) { super(parent, NbBundle.getMessage(ModalNoButtons.class, "ModalNoButtons.indexingDbsTitle"), true); this.unindexed = unindexed; this.toIndex = null; @@ -75,7 +75,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen * @param parent Swing parent frame. * @param unindexed The unindexed database to index. */ - ModalNoButtons(HashLookupSettingsPanel hdbmp, java.awt.Frame parent, HashDb unindexed) { + ModalNoButtons(HashLookupSettingsPanel hdbmp, java.awt.Frame parent, HashDatabase unindexed) { super(parent, NbBundle.getMessage(ModalNoButtons.class, "ModalNoButtons.indexingDbTitle"), true); this.unindexed = null; this.toIndex = unindexed; @@ -183,7 +183,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen "ModalNoButtons.dlgTitle.unfinishedIndexing"), JOptionPane.YES_NO_OPTION); if (res == JOptionPane.YES_OPTION) { - List remove = new ArrayList<>(); + List remove = new ArrayList<>(); if (this.toIndex == null) { remove = this.unindexed; } else { @@ -230,7 +230,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen private void indexThese() { length = this.unindexed.size(); this.INDEXING_PROGBAR.setIndeterminate(true); - for (HashDb db : this.unindexed) { + for (HashDatabase db : this.unindexed) { currentDb = db.getHashSetName(); this.CURRENTDB_LABEL.setText("(" + currentDb + ")"); this.CURRENTLYON_LABEL.setText( @@ -255,7 +255,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen * this dialog if all indexing is complete. */ public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(HashDb.Event.INDEXING_DONE.name())) { + if (evt.getPropertyName().equals(HashDatabase.Event.INDEXING_DONE.name())) { if (currentcount >= length) { this.INDEXING_PROGBAR.setValue(100); this.setModal(false); diff --git a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java index 233aad0202..e2c90b005c 100755 --- a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java +++ b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java @@ -34,7 +34,7 @@ import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * Instances of this class plug in to the reporting infrastructure to provide a @@ -69,7 +69,7 @@ public class AddTaggedHashesToHashDb implements GeneralReportModule { progressPanel.start(); progressPanel.updateStatusLabel("Adding hashes..."); - HashDatabase hashSet = configPanel.getSelectedHashDatabase(); + HashDb hashSet = configPanel.getSelectedHashDatabase(); if (hashSet != null) { progressPanel.updateStatusLabel("Adding hashes to " + hashSet.getHashSetName() + " hash set..."); diff --git a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.form b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.form index 20cec74d82..dfe9ba921e 100755 --- a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.form +++ b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.form @@ -124,7 +124,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java index 9c1875eeb2..0c20eee562 100644 --- a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java @@ -39,7 +39,7 @@ import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupSettingsPanel; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * Instances of this class are used to configure the report module plug in that @@ -52,7 +52,7 @@ class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { private final Map tagNameSelections = new LinkedHashMap<>(); private final TagNamesListModel tagsNamesListModel = new TagNamesListModel(); private final TagsNamesListCellRenderer tagsNamesRenderer = new TagsNamesListCellRenderer(); - private HashDatabase selectedHashSet = null; + private HashDb selectedHashSet = null; AddTaggedHashesToHashDbConfigPanel() { initComponents(); @@ -107,9 +107,9 @@ class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { // Get the updateable hash databases and add their hash set names to the // JComboBox component. - List updateableHashSets = HashDbManager.getInstance().getUpdateableHashDatabases(); + List updateableHashSets = HashDbManager.getInstance().getUpdateableHashSets(); if (!updateableHashSets.isEmpty()) { - for (HashDatabase hashDb : updateableHashSets) { + for (HashDb hashDb : updateableHashSets) { hashSetsComboBox.addItem(hashDb); } hashSetsComboBox.setEnabled(true); @@ -138,7 +138,7 @@ class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { * * @return A HashDb object representing the database or null. */ - HashDatabase getSelectedHashDatabase() { + HashDb getSelectedHashDatabase() { return selectedHashSet; } @@ -286,7 +286,7 @@ class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { }//GEN-LAST:event_selectAllButtonActionPerformed private void hashSetsComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_hashSetsComboBoxActionPerformed - selectedHashSet = (HashDatabase)hashSetsComboBox.getSelectedItem(); + selectedHashSet = (HashDb)hashSetsComboBox.getSelectedItem(); }//GEN-LAST:event_hashSetsComboBoxActionPerformed private void deselectAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deselectAllButtonActionPerformed @@ -311,7 +311,7 @@ class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton configureHashDatabasesButton; private javax.swing.JButton deselectAllButton; - private javax.swing.JComboBox hashSetsComboBox; + private javax.swing.JComboBox hashSetsComboBox; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JScrollPane jScrollPane1; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/SharedConfiguration.java b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/SharedConfiguration.java index ccb2e49e54..e3f6a23bf5 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/SharedConfiguration.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/SharedConfiguration.java @@ -47,7 +47,7 @@ import org.sleuthkit.autopsy.keywordsearch.KeywordListsManager; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.core.ServicesMonitor; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; import org.sleuthkit.autopsy.experimental.configuration.AutoIngestSettingsPanel.UpdateConfigSwingWorker; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CategoryNode; @@ -1017,15 +1017,17 @@ public class SharedConfiguration { // If a copy of the database is loaded, close it before deleting and copying. if (localDb.exists()) { List hashDbs = HashDbManager.getInstance().getAllHashSets(); - HashDbManager.HashDb matchingDb = null; + HashDbManager.HashDatabase matchingDb = null; for (HashDbManager.HashDb db : hashDbs) { - try { - if (localDb.getAbsolutePath().equals(db.getDatabasePath()) || localDb.getAbsolutePath().equals(db.getIndexPath())) { - matchingDb = db; - break; + if(db instanceof HashDbManager.HashDatabase){ + try { + if (localDb.getAbsolutePath().equals(db.getDatabasePath()) || localDb.getAbsolutePath().equals(db.getIndexPath())) { + matchingDb = (HashDbManager.HashDatabase)db; + break; + } + } catch (TskCoreException ex) { + throw new SharedConfigurationException(String.format("Error getting hash database path info for %s", localDb.getParentFile().getAbsolutePath()), ex); } - } catch (TskCoreException ex) { - throw new SharedConfigurationException(String.format("Error getting hash database path info for %s", localDb.getParentFile().getAbsolutePath()), ex); } } @@ -1122,11 +1124,13 @@ public class SharedConfiguration { try { HashDbManager hashDbManager = HashDbManager.getInstance(); hashDbManager.loadLastSavedConfiguration(); - for (HashDb hashDb : hashDbManager.getAllHashSets()) { - if (hashDb.hasIndexOnly()) { - results.add(hashDb.getIndexPath()); - } else { - results.add(hashDb.getDatabasePath()); + for (HashDbManager.HashDb hashDb : hashDbManager.getAllHashSets()) { + if(hashDb instanceof HashDatabase){ + if (hashDb.hasIndexOnly()) { + results.add(hashDb.getIndexPath()); + } else { + results.add(hashDb.getDatabasePath()); + } } } } catch (TskCoreException ex) { From f00ceeea273df66fce95d66bd61e00a118d8577e Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Mon, 13 Nov 2017 14:03:29 -0500 Subject: [PATCH 092/115] Cleanup --- .../autopsy/modules/hashdatabase/AddContentToHashDbAction.java | 2 +- .../modules/hashdatabase/AddHashValuesToDatabaseDialog.java | 2 +- .../hashdatabase/AddHashValuesToDatabaseProgressDialog.java | 2 +- .../modules/hashdatabase/HashDbCreateDatabaseDialog.java | 2 +- .../autopsy/modules/hashdatabase/HashDbIngestModule.java | 2 +- .../autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java | 2 +- .../report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddContentToHashDbAction.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddContentToHashDbAction.java index effa123af9..5ec70ce3b9 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddContentToHashDbAction.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddContentToHashDbAction.java @@ -32,10 +32,10 @@ import org.openide.util.Utilities; import org.openide.util.actions.Presenter; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; +import static org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.HashUtility; import org.sleuthkit.datamodel.TskCoreException; -import static org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * Instances of this Action allow users to content to a hash database. diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java index 1fe05701ce..40db15718f 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java @@ -31,8 +31,8 @@ import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; -import org.sleuthkit.datamodel.HashEntry; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; +import org.sleuthkit.datamodel.HashEntry; /** * diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java index 3f3671c44f..f712a965fd 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java @@ -31,9 +31,9 @@ import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.SwingWorker; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.datamodel.HashEntry; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java index a794ada72d..d07f5a034c 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java @@ -33,9 +33,9 @@ import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.KnownFilesType; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDbManagerException; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * Instances of this class allow a user to create a new hash database and add it diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java index 75f477b585..40cd2230b3 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -36,6 +36,7 @@ import org.sleuthkit.autopsy.ingest.IngestMessage; import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter; import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; @@ -47,7 +48,6 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskException; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; @NbBundle.Messages({ "HashDbIngestModule.noKnownBadHashDbSetMsg=No notable hash database set.", diff --git a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java index e2c90b005c..1de1db7eaa 100755 --- a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java +++ b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java @@ -27,6 +27,7 @@ import javax.swing.JPanel; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.TagsManager; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.autopsy.report.GeneralReportModule; import org.sleuthkit.autopsy.report.ReportProgressPanel; import org.sleuthkit.datamodel.AbstractFile; @@ -34,7 +35,6 @@ import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * Instances of this class plug in to the reporting infrastructure to provide a diff --git a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java index 0c20eee562..4dd665b890 100644 --- a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java @@ -35,11 +35,11 @@ import javax.swing.ListModel; import javax.swing.event.ListDataListener; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupSettingsPanel; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * Instances of this class are used to configure the report module plug in that From 0ea88c0f68213b8ff96544cf764b974e5fec9fc2 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Mon, 13 Nov 2017 14:24:50 -0500 Subject: [PATCH 093/115] Cleanup --- .../modules/hashdatabase/HashDbManager.java | 42 +++++++------------ .../hashdatabase/HashLookupSettingsPanel.java | 15 ++++--- 2 files changed, 23 insertions(+), 34 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java index 59dcd998e0..a764065b6b 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -147,15 +147,15 @@ public class HashDbManager implements PropertyChangeListener { * * @throws HashDbManagerException */ - public synchronized HashDatabase addExistingHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDatabase.KnownFilesType knownFilesType) throws HashDbManagerException { - HashDatabase hashDb = null; + public synchronized HashDb addExistingHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDatabase.KnownFilesType knownFilesType) throws HashDbManagerException { + HashDb hashDb = null; hashDb = this.addExistingHashDatabaseNoSave(hashSetName, path, searchDuringIngest, sendIngestMessages, knownFilesType); this.save(); return hashDb; } - synchronized HashDatabase addExistingHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDatabase.KnownFilesType knownFilesType) throws HashDbManagerException { - HashDatabase hashDb = null; + synchronized HashDb addExistingHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDatabase.KnownFilesType knownFilesType) throws HashDbManagerException { + HashDb hashDb = null; try { if (!new File(path).exists()) { throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.hashDbDoesNotExistExceptionMsg", path)); @@ -169,7 +169,7 @@ public class HashDbManager implements PropertyChangeListener { throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.duplicateHashSetNameExceptionMsg", hashSetName)); } - hashDb = addFileHashDatabase(SleuthkitJNI.openHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); + hashDb = addHashDatabase(SleuthkitJNI.openHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); } catch (TskCoreException ex) { throw new HashDbManagerException(ex.getMessage()); } @@ -194,10 +194,10 @@ public class HashDbManager implements PropertyChangeListener { * * @throws HashDbManagerException */ - public synchronized HashDatabase addNewHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, - HashDatabase.KnownFilesType knownFilesType) throws HashDbManagerException { + public synchronized HashDb addNewHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, + HashDb.KnownFilesType knownFilesType) throws HashDbManagerException { - HashDatabase hashDb = null; + HashDb hashDb = null; hashDb = this.addNewHashDatabaseNoSave(hashSetName, path, searchDuringIngest, sendIngestMessages, knownFilesType); this.save(); @@ -205,9 +205,9 @@ public class HashDbManager implements PropertyChangeListener { return hashDb; } - public synchronized HashDatabase addNewHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, - HashDatabase.KnownFilesType knownFilesType) throws HashDbManagerException { - HashDatabase hashDb = null; + public synchronized HashDb addNewHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, + HashDb.KnownFilesType knownFilesType) throws HashDbManagerException { + HashDb hashDb = null; try { File file = new File(path); if (file.exists()) { @@ -226,14 +226,14 @@ public class HashDbManager implements PropertyChangeListener { throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.duplicateHashSetNameExceptionMsg", hashSetName)); } - hashDb = addFileHashDatabase(SleuthkitJNI.createHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); + hashDb = addHashDatabase(SleuthkitJNI.createHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); } catch (TskCoreException ex) { throw new HashDbManagerException(ex.getMessage()); } return hashDb; } - private HashDatabase addFileHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDatabase.KnownFilesType knownFilesType) throws TskCoreException { + private HashDatabase addHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDatabase.KnownFilesType knownFilesType) throws TskCoreException { // Wrap an object around the handle. HashDatabase hashDb = new HashDatabase(handle, hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); @@ -400,20 +400,6 @@ public class HashDbManager implements PropertyChangeListener { } } - /** - * Gets all of the file hash databases used to classify files as known or known - * bad. - * - * @return A list, possibly empty, of hash databases. - */ - synchronized List getAllFileHashSets() { - List hashDbs = new ArrayList<>(); - this.hashSets.stream().filter((thisSet) -> (thisSet instanceof HashDatabase)).forEach((thisSet) -> { - hashDbs.add((HashDatabase)thisSet); - }); - return hashDbs; - } - /** * Gets all of the hash databases used to classify files as known or known * bad. Will add any new central repository databases to the list before @@ -551,7 +537,7 @@ public class HashDbManager implements PropertyChangeListener { if(hashDbInfo.isFileDatabaseType()){ String dbPath = this.getValidFilePath(hashDbInfo.getHashSetName(), hashDbInfo.getPath()); if (dbPath != null) { - addFileHashDatabase(SleuthkitJNI.openHashDatabase(dbPath), hashDbInfo.getHashSetName(), hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(), hashDbInfo.getKnownFilesType()); + addHashDatabase(SleuthkitJNI.openHashDatabase(dbPath), hashDbInfo.getHashSetName(), hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(), hashDbInfo.getKnownFilesType()); } else { logger.log(Level.WARNING, Bundle.HashDbManager_noDbPath_message(hashDbInfo.getHashSetName())); allDatabasesLoadedCorrectly = false; diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java index ef8986af24..f765fcbd4b 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java @@ -305,13 +305,16 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan public void saveSettings() { //Checking for for any unindexed databases List unindexed = new ArrayList<>(); - for (HashDatabase db : hashSetManager.getAllFileHashSets()) { - try { - if (!db.hasIndex()) { - unindexed.add(db); + for (HashDb db : hashSetManager.getAllHashSets()) { + if(db instanceof HashDatabase){ + try { + HashDatabase hashDatabase = (HashDatabase)db; + if (!hashDatabase.hasIndex()) { + unindexed.add(hashDatabase); + } + } catch (TskCoreException ex) { + Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting index info for hash database", ex); //NON-NLS } - } catch (TskCoreException ex) { - Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting index info for hash database", ex); //NON-NLS } } From fed52680a97ec4e4b9a43bf93e7e3f5808344b91 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Mon, 13 Nov 2017 14:28:04 -0500 Subject: [PATCH 094/115] Cleanup --- .../autopsy/modules/hashdatabase/HashDbManager.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java index a764065b6b..412fb6410e 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -147,14 +147,14 @@ public class HashDbManager implements PropertyChangeListener { * * @throws HashDbManagerException */ - public synchronized HashDb addExistingHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDatabase.KnownFilesType knownFilesType) throws HashDbManagerException { + public synchronized HashDb addExistingHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDbManagerException { HashDb hashDb = null; hashDb = this.addExistingHashDatabaseNoSave(hashSetName, path, searchDuringIngest, sendIngestMessages, knownFilesType); this.save(); return hashDb; } - synchronized HashDb addExistingHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDatabase.KnownFilesType knownFilesType) throws HashDbManagerException { + synchronized HashDb addExistingHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDbManagerException { HashDb hashDb = null; try { if (!new File(path).exists()) { @@ -407,7 +407,7 @@ public class HashDbManager implements PropertyChangeListener { * * @return A list, possibly empty, of hash databases. */ - public synchronized List getAllHashSets(){ + public synchronized List getAllHashSets() { try{ updateHashSetsFromCentralRepository(); } catch (TskCoreException ex){ From 5edea4c5955879c5e2fbc280219c21746de16b6c Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Mon, 13 Nov 2017 16:26:14 -0500 Subject: [PATCH 095/115] API added for getting data source content size. --- .../autopsy/casemodule/CaseNodeData.java | 141 +++++++++++ .../autoingest/AutoIngestControlPanel.form | 238 ++++++++++++++---- .../autoingest/AutoIngestControlPanel.java | 188 +++++++++----- .../autoingest/AutoIngestDashboard.java | 6 +- .../autoingest/AutoIngestManager.java | 197 ++++++++------- .../AutoIngestMetricsCollector.java | 160 ++++++++++++ .../autoingest/AutoIngestMetricsDialog.java | 50 +++- .../autoingest/AutoIngestMonitor.java | 95 +------ 8 files changed, 769 insertions(+), 306 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/CaseNodeData.java create mode 100755 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsCollector.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseNodeData.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseNodeData.java new file mode 100755 index 0000000000..f4308e8954 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseNodeData.java @@ -0,0 +1,141 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.casemodule; + +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; + +/** + * An object that converts case data for a case directory coordination service + * node to and from byte arrays. + */ +public final class CaseNodeData { + + private static final int CURRENT_VERSION = 0; + + private int version; + private boolean errorsOccurred; + + /** + * Gets the current version of the case directory coordination service node + * data. + * + * @return The version number. + */ + public static int getCurrentVersion() { + return CaseNodeData.CURRENT_VERSION; + } + + /** + * Uses coordination service node data to construct an object that converts + * case data for a case directory coordination service node to and from byte + * arrays. + * + * @param nodeData The raw bytes received from the coordination service. + * + * @throws InvalidDataException If the node data buffer is smaller than + * expected. + */ + public CaseNodeData(byte[] nodeData) throws InvalidDataException { + if(nodeData == null || nodeData.length == 0) { + this.version = CURRENT_VERSION; + this.errorsOccurred = false; + } else { + /* + * Get fields from node data. + */ + ByteBuffer buffer = ByteBuffer.wrap(nodeData); + try { + if (buffer.hasRemaining()) { + this.version = buffer.getInt(); + + /* + * Flags bit format: 76543210 + * 0-6 --> reserved for future use + * 7 --> errorsOccurred + */ + byte flags = buffer.get(); + this.errorsOccurred = (flags < 0); + } + } catch (BufferUnderflowException ex) { + throw new InvalidDataException("Node data is incomplete", ex); + } + } + } + + /** + * Gets whether or not any errors occurred during the processing of the job. + * + * @return True or false. + */ + public boolean getErrorsOccurred() { + return this.errorsOccurred; + } + + /** + * Sets whether or not any errors occurred during the processing of job. + * + * @param errorsOccurred True or false. + */ + public void setErrorsOccurred(boolean errorsOccurred) { + this.errorsOccurred = errorsOccurred; + } + + /** + * Gets the node data version number. + * + * @return The version number. + */ + public int getVersion() { + return this.version; + } + + /** + * Gets the node data as a byte array that can be sent to the coordination + * service. + * + * @return The node data as a byte array. + */ + public byte[] toArray() { + ByteBuffer buffer = ByteBuffer.allocate(5); + + buffer.putInt(this.version); + buffer.put((byte)(this.errorsOccurred ? 0x80 : 0)); + + // Prepare the array + byte[] array = new byte[buffer.position()]; + buffer.rewind(); + buffer.get(array, 0, array.length); + + return array; + } + + public final static class InvalidDataException extends Exception { + + private static final long serialVersionUID = 1L; + + private InvalidDataException(String message) { + super(message); + } + + private InvalidDataException(String message, Throwable cause) { + super(message, cause); + } + } +} \ No newline at end of file diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.form index cec9d21492..f00e28374c 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.form @@ -17,46 +17,22 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - + + + + + + + + + @@ -73,8 +49,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - @@ -99,9 +103,9 @@ - + - + @@ -135,16 +139,13 @@ - - - - - - - - - - + + + + + + + @@ -169,6 +170,7 @@ + @@ -192,6 +194,7 @@ + @@ -215,6 +218,7 @@ + @@ -231,6 +235,15 @@ + + + + + + + + + @@ -244,6 +257,15 @@ + + + + + + + + + @@ -287,6 +309,15 @@ + + + + + + + + + @@ -300,6 +331,15 @@ + + + + + + + + + @@ -313,6 +353,15 @@ + + + + + + + + + @@ -327,6 +376,15 @@ + + + + + + + + + @@ -340,6 +398,15 @@ + + + + + + + + + @@ -353,6 +420,15 @@ + + + + + + + + + @@ -366,6 +442,15 @@ + + + + + + + + + @@ -379,6 +464,15 @@ + + + + + + + + + @@ -419,6 +513,15 @@ + + + + + + + + + @@ -453,20 +556,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + \ No newline at end of file diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java index 7b893ae0b9..8024fbf93a 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java @@ -73,6 +73,7 @@ import org.sleuthkit.autopsy.ingest.IngestProgressSnapshotDialog; * one such panel per node. */ @Messages({ + "AutoIngestControlPanel.bnClusterMetrics.text=Cluster Metrics", "AutoIngestControlPanel.bnPause.text=Pause", "AutoIngestControlPanel.bnPause.paused=Paused", "AutoIngestControlPanel.bnPause.running=Running", @@ -116,7 +117,7 @@ import org.sleuthkit.autopsy.ingest.IngestProgressSnapshotDialog; "AutoIngestControlPanel.bnPrioritizeJob.actionCommand=", "AutoIngestControlPanel.lbServicesStatus.text=Services Status:", "AutoIngestControlPanel.tbServicesStatusMessage.text=", - "AutoIngestControlPanel.bnOpenLogDir.text=Open System Logs Directory", + "AutoIngestControlPanel.bnOpenLogDir.text=Open System Logs Folder", "AutoIngestControlPanel.bnReprocessJob.text=Reprocess Job", "AutoIngestControlPanel.bnPrioritizeFolder.label=", "AutoIngestControlPanel.Cancelling=Cancelling...", @@ -1198,10 +1199,12 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { lbServicesStatus = new javax.swing.JLabel(); tbServicesStatusMessage = new javax.swing.JTextField(); bnOpenLogDir = new javax.swing.JButton(); + bnClusterMetrics = new javax.swing.JButton(); bnReprocessJob = new javax.swing.JButton(); pendingTable.setModel(pendingTableModel); pendingTable.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.pendingTable.toolTipText")); // NOI18N + pendingTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS); pendingTable.setRowHeight(20); pendingTable.setSelectionModel(new DefaultListSelectionModel() { private static final long serialVersionUID = 1L; @@ -1219,6 +1222,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { runningTable.setModel(runningTableModel); runningTable.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.runningTable.toolTipText")); // NOI18N + runningTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS); runningTable.setRowHeight(20); runningTable.setSelectionModel(new DefaultListSelectionModel() { private static final long serialVersionUID = 1L; @@ -1236,6 +1240,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { completedTable.setModel(completedTableModel); completedTable.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.completedTable.toolTipText")); // NOI18N + completedTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS); completedTable.setRowHeight(20); completedTable.setSelectionModel(new DefaultListSelectionModel() { private static final long serialVersionUID = 1L; @@ -1253,6 +1258,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnCancelJob, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnCancelJob.text")); // NOI18N bnCancelJob.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnCancelJob.toolTipText")); // NOI18N + bnCancelJob.setMaximumSize(new java.awt.Dimension(162, 23)); + bnCancelJob.setMinimumSize(new java.awt.Dimension(162, 23)); + bnCancelJob.setPreferredSize(new java.awt.Dimension(162, 23)); bnCancelJob.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnCancelJobActionPerformed(evt); @@ -1261,6 +1269,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnDeleteCase, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnDeleteCase.text")); // NOI18N bnDeleteCase.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnDeleteCase.toolTipText")); // NOI18N + bnDeleteCase.setMaximumSize(new java.awt.Dimension(162, 23)); + bnDeleteCase.setMinimumSize(new java.awt.Dimension(162, 23)); + bnDeleteCase.setPreferredSize(new java.awt.Dimension(162, 23)); bnDeleteCase.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnDeleteCaseActionPerformed(evt); @@ -1278,6 +1289,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnRefresh, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnRefresh.text")); // NOI18N bnRefresh.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnRefresh.toolTipText")); // NOI18N + bnRefresh.setMaximumSize(new java.awt.Dimension(162, 23)); + bnRefresh.setMinimumSize(new java.awt.Dimension(162, 23)); + bnRefresh.setPreferredSize(new java.awt.Dimension(162, 23)); bnRefresh.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnRefreshActionPerformed(evt); @@ -1286,6 +1300,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnCancelModule, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnCancelModule.text")); // NOI18N bnCancelModule.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnCancelModule.toolTipText")); // NOI18N + bnCancelModule.setMaximumSize(new java.awt.Dimension(162, 23)); + bnCancelModule.setMinimumSize(new java.awt.Dimension(162, 23)); + bnCancelModule.setPreferredSize(new java.awt.Dimension(162, 23)); bnCancelModule.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnCancelModuleActionPerformed(evt); @@ -1294,6 +1311,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnExit, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnExit.text")); // NOI18N bnExit.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnExit.toolTipText")); // NOI18N + bnExit.setMaximumSize(new java.awt.Dimension(162, 23)); + bnExit.setMinimumSize(new java.awt.Dimension(162, 23)); + bnExit.setPreferredSize(new java.awt.Dimension(162, 23)); bnExit.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnExitActionPerformed(evt); @@ -1303,6 +1323,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnOptions, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnOptions.text")); // NOI18N bnOptions.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnOptions.toolTipText")); // NOI18N bnOptions.setEnabled(false); + bnOptions.setMaximumSize(new java.awt.Dimension(162, 23)); + bnOptions.setMinimumSize(new java.awt.Dimension(162, 23)); + bnOptions.setPreferredSize(new java.awt.Dimension(162, 23)); bnOptions.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnOptionsActionPerformed(evt); @@ -1311,6 +1334,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnShowProgress, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnShowProgress.text")); // NOI18N bnShowProgress.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnShowProgress.toolTipText")); // NOI18N + bnShowProgress.setMaximumSize(new java.awt.Dimension(162, 23)); + bnShowProgress.setMinimumSize(new java.awt.Dimension(162, 23)); + bnShowProgress.setPreferredSize(new java.awt.Dimension(162, 23)); bnShowProgress.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnShowProgressActionPerformed(evt); @@ -1319,6 +1345,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnPause, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPause.text")); // NOI18N bnPause.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPause.toolTipText")); // NOI18N + bnPause.setMaximumSize(new java.awt.Dimension(162, 23)); + bnPause.setMinimumSize(new java.awt.Dimension(162, 23)); + bnPause.setPreferredSize(new java.awt.Dimension(162, 23)); bnPause.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnPauseActionPerformed(evt); @@ -1327,6 +1356,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnPrioritizeCase, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPrioritizeCase.text")); // NOI18N bnPrioritizeCase.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPrioritizeCase.toolTipText")); // NOI18N + bnPrioritizeCase.setMaximumSize(new java.awt.Dimension(162, 23)); + bnPrioritizeCase.setMinimumSize(new java.awt.Dimension(162, 23)); + bnPrioritizeCase.setPreferredSize(new java.awt.Dimension(162, 23)); bnPrioritizeCase.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnPrioritizeCaseActionPerformed(evt); @@ -1335,6 +1367,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnShowCaseLog, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnShowCaseLog.text")); // NOI18N bnShowCaseLog.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnShowCaseLog.toolTipText")); // NOI18N + bnShowCaseLog.setMaximumSize(new java.awt.Dimension(162, 23)); + bnShowCaseLog.setMinimumSize(new java.awt.Dimension(162, 23)); + bnShowCaseLog.setPreferredSize(new java.awt.Dimension(162, 23)); bnShowCaseLog.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnShowCaseLogActionPerformed(evt); @@ -1352,6 +1387,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnPrioritizeJob, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPrioritizeJob.text")); // NOI18N bnPrioritizeJob.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPrioritizeJob.toolTipText")); // NOI18N bnPrioritizeJob.setActionCommand(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPrioritizeJob.actionCommand")); // NOI18N + bnPrioritizeJob.setMaximumSize(new java.awt.Dimension(162, 23)); + bnPrioritizeJob.setMinimumSize(new java.awt.Dimension(162, 23)); + bnPrioritizeJob.setPreferredSize(new java.awt.Dimension(162, 23)); bnPrioritizeJob.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnPrioritizeJobActionPerformed(evt); @@ -1367,13 +1405,29 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { tbServicesStatusMessage.setBorder(null); org.openide.awt.Mnemonics.setLocalizedText(bnOpenLogDir, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnOpenLogDir.text")); // NOI18N + bnOpenLogDir.setMaximumSize(new java.awt.Dimension(162, 23)); + bnOpenLogDir.setMinimumSize(new java.awt.Dimension(162, 23)); + bnOpenLogDir.setPreferredSize(new java.awt.Dimension(162, 23)); bnOpenLogDir.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnOpenLogDirActionPerformed(evt); } }); + org.openide.awt.Mnemonics.setLocalizedText(bnClusterMetrics, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnClusterMetrics.text")); // NOI18N + bnClusterMetrics.setMaximumSize(new java.awt.Dimension(162, 23)); + bnClusterMetrics.setMinimumSize(new java.awt.Dimension(162, 23)); + bnClusterMetrics.setPreferredSize(new java.awt.Dimension(162, 23)); + bnClusterMetrics.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnClusterMetricsActionPerformed(evt); + } + }); + org.openide.awt.Mnemonics.setLocalizedText(bnReprocessJob, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnReprocessJob.text")); // NOI18N + bnReprocessJob.setMaximumSize(new java.awt.Dimension(162, 23)); + bnReprocessJob.setMinimumSize(new java.awt.Dimension(162, 23)); + bnReprocessJob.setPreferredSize(new java.awt.Dimension(162, 23)); bnReprocessJob.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnReprocessJobActionPerformed(evt); @@ -1387,38 +1441,20 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(lbPending, javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(pendingScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 920, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(bnPrioritizeCase, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(bnPrioritizeJob, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(bnPause) - .addGap(18, 18, 18) - .addComponent(bnRefresh, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addComponent(bnOptions) - .addGap(18, 18, 18) - .addComponent(bnOpenLogDir) - .addGap(18, 18, 18) - .addComponent(bnExit, javax.swing.GroupLayout.PREFERRED_SIZE, 94, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(runningScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 920, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(completedScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 920, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(bnPause, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(bnCancelJob, javax.swing.GroupLayout.PREFERRED_SIZE, 117, Short.MAX_VALUE) - .addComponent(bnShowProgress, javax.swing.GroupLayout.PREFERRED_SIZE, 116, Short.MAX_VALUE) - .addComponent(bnCancelModule, javax.swing.GroupLayout.PREFERRED_SIZE, 117, Short.MAX_VALUE) - .addComponent(bnDeleteCase, javax.swing.GroupLayout.PREFERRED_SIZE, 117, Short.MAX_VALUE) - .addComponent(bnShowCaseLog, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(bnReprocessJob, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addComponent(bnRefresh, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(bnOptions, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(bnOpenLogDir, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(bnClusterMetrics, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(bnExit, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(layout.createSequentialGroup() .addComponent(lbStatus) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) @@ -1429,11 +1465,32 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { .addComponent(lbServicesStatus) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(tbServicesStatusMessage, javax.swing.GroupLayout.PREFERRED_SIZE, 861, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGap(0, 0, Short.MAX_VALUE))) - .addContainerGap()) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lbPending) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(runningScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 1021, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(completedScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 1021, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(bnCancelJob, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(bnShowProgress, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(bnCancelModule, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(bnDeleteCase, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(bnShowCaseLog, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(bnReprocessJob, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addGroup(layout.createSequentialGroup() + .addComponent(pendingScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 1021, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(bnPrioritizeCase, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(bnPrioritizeJob, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) ); - layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {bnCancelJob, bnCancelModule, bnDeleteCase, bnExit, bnOpenLogDir, bnOptions, bnPause, bnRefresh, bnShowProgress}); + layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {bnCancelJob, bnCancelModule, bnDeleteCase, bnShowProgress}); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -1453,48 +1510,47 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { .addComponent(pendingScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(layout.createSequentialGroup() .addGap(82, 82, 82) - .addComponent(bnPrioritizeCase) + .addComponent(bnPrioritizeCase, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnPrioritizeJob))) + .addComponent(bnPrioritizeJob, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(lbRunning) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(34, 34, 34) - .addComponent(bnShowProgress) + .addComponent(bnShowProgress, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnCancelJob) + .addComponent(bnCancelJob, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnCancelModule)) + .addComponent(bnCancelModule, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(layout.createSequentialGroup() .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(runningScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE))) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(68, 68, 68) - .addComponent(bnReprocessJob) + .addComponent(bnReprocessJob, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnDeleteCase) + .addComponent(bnDeleteCase, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnShowCaseLog)) + .addComponent(bnShowCaseLog, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(layout.createSequentialGroup() .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(lbCompleted) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(completedScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 179, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(bnExit) - .addComponent(bnOpenLogDir)) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(bnPause) - .addComponent(bnRefresh) - .addComponent(bnOptions))))) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(bnPause, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(bnRefresh, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(bnOptions, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(bnOpenLogDir, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(bnClusterMetrics, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(bnExit, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))) .addContainerGap()) ); - layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {bnCancelJob, bnCancelModule, bnDeleteCase, bnExit, bnOpenLogDir, bnOptions, bnRefresh, bnShowProgress}); + layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {bnCancelJob, bnCancelModule, bnClusterMetrics, bnDeleteCase, bnExit, bnOpenLogDir, bnOptions, bnPrioritizeCase, bnPrioritizeJob, bnRefresh, bnShowProgress}); }// //GEN-END:initComponents @@ -1523,11 +1579,11 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { "AutoIngestControlPanel.DeletionFailed=Deletion failed for job" }) private void bnDeleteCaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnDeleteCaseActionPerformed - if (completedTable.getModel().getRowCount() < 0 || completedTable.getSelectedRow() < 0) { + if (completedTableModel.getRowCount() < 0 || completedTable.getSelectedRow() < 0) { return; } - String caseName = (String) completedTable.getModel().getValueAt(completedTable.convertRowIndexToModel(completedTable.getSelectedRow()), JobsTableModelColumns.CASE.ordinal()); + String caseName = (String) completedTable.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal()); Object[] options = { org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "ConfirmationDialog.Delete"), org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "ConfirmationDialog.DoNotDelete") @@ -1544,8 +1600,8 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { if (reply == JOptionPane.YES_OPTION) { bnDeleteCase.setEnabled(false); bnShowCaseLog.setEnabled(false); - if (completedTable.getModel().getRowCount() > 0 && completedTable.getSelectedRow() >= 0) { - Path caseDirectoryPath = (Path) completedTable.getModel().getValueAt(completedTable.convertRowIndexToModel(completedTable.getSelectedRow()), JobsTableModelColumns.CASE_DIRECTORY_PATH.ordinal()); + if (completedTableModel.getRowCount() > 0 && completedTable.getSelectedRow() >= 0) { + Path caseDirectoryPath = (Path) completedTableModel.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.CASE_DIRECTORY_PATH.ordinal()); completedTable.clearSelection(); this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); CaseDeletionResult result = manager.deleteCase(caseName, caseDirectoryPath); @@ -1691,10 +1747,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { */ @Messages({"AutoIngestControlPanel.casePrioritization.errorMessage=An error occurred when prioritizing the case. Some or all jobs may not have been prioritized."}) private void bnPrioritizeCaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPrioritizeCaseActionPerformed - if (pendingTable.getModel().getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { + if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - - String caseName = (pendingTable.getModel().getValueAt(pendingTable.convertRowIndexToModel(pendingTable.getSelectedRow()), JobsTableModelColumns.CASE.ordinal())).toString(); + String caseName = (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal())).toString(); try { manager.prioritizeCase(caseName); } catch (AutoIngestManager.AutoIngestManagerException ex) { @@ -1720,9 +1775,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { }) private void bnShowCaseLogActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnShowCaseLogActionPerformed try { - int selectedRow = completedTable.convertRowIndexToModel(completedTable.getSelectedRow()); + int selectedRow = completedTable.getSelectedRow(); if (selectedRow != -1) { - Path caseDirectoryPath = (Path) completedTable.getModel().getValueAt(selectedRow, JobsTableModelColumns.CASE_DIRECTORY_PATH.ordinal()); + Path caseDirectoryPath = (Path) completedTableModel.getValueAt(selectedRow, JobsTableModelColumns.CASE_DIRECTORY_PATH.ordinal()); if (null != caseDirectoryPath) { Path pathToLog = AutoIngestJobLogger.getLogPath(caseDirectoryPath); if (pathToLog.toFile().exists()) { @@ -1751,9 +1806,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { @Messages({"AutoIngestControlPanel.jobPrioritization.errorMessage=An error occurred when prioritizing the job."}) private void bnPrioritizeJobActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPrioritizeJobActionPerformed - if (pendingTable.getModel().getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { + if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - Path manifestFilePath = (Path) (pendingTable.getModel().getValueAt(pendingTable.convertRowIndexToModel(pendingTable.getSelectedRow()), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal())); + Path manifestFilePath = (Path) (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal())); try { manager.prioritizeJob(manifestFilePath); } catch (AutoIngestManager.AutoIngestManagerException ex) { @@ -1780,19 +1835,28 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { }//GEN-LAST:event_bnOpenLogDirActionPerformed private void bnReprocessJobActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnReprocessJobActionPerformed - if (completedTable.getModel().getRowCount() < 0 || completedTable.getSelectedRow() < 0) { + if (completedTableModel.getRowCount() < 0 || completedTable.getSelectedRow() < 0) { return; } this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - Path manifestPath = (Path) completedTable.getModel().getValueAt(completedTable.convertRowIndexToModel(completedTable.getSelectedRow()), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal()); + Path manifestPath = (Path) completedTableModel.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal()); manager.reprocessJob(manifestPath); refreshTables(); AutoIngestControlPanel.this.setCursor(Cursor.getDefaultCursor()); }//GEN-LAST:event_bnReprocessJobActionPerformed + private void bnClusterMetricsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnClusterMetricsActionPerformed + try { + new AutoIngestMetricsDialog(this.getTopLevelAncestor()); + } catch (AutoIngestMetricsDialog.AutoIngestMetricsDialogException ex) { + MessageNotifyUtil.Message.error(ex.getMessage()); + } + }//GEN-LAST:event_bnClusterMetricsActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton bnCancelJob; private javax.swing.JButton bnCancelModule; + private javax.swing.JButton bnClusterMetrics; private javax.swing.JButton bnDeleteCase; private javax.swing.JButton bnExit; private javax.swing.JButton bnOpenLogDir; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java index d53503a72f..421b1f92f0 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java @@ -873,7 +873,11 @@ final class AutoIngestDashboard extends JPanel implements Observer { }//GEN-LAST:event_prioritizeCaseButtonActionPerformed private void clusterMetricsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clusterMetricsButtonActionPerformed - new AutoIngestMetricsDialog(this.getTopLevelAncestor(), autoIngestMonitor); + try { + new AutoIngestMetricsDialog(this.getTopLevelAncestor()); + } catch (AutoIngestMetricsDialog.AutoIngestMetricsDialogException ex) { + MessageNotifyUtil.Message.error(ex.getMessage()); + } }//GEN-LAST:event_clusterMetricsButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index 1cbe9af5a6..2ce6e2cba8 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -64,7 +64,7 @@ import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.casemodule.CaseActionException; import org.sleuthkit.autopsy.casemodule.CaseDetails; import org.sleuthkit.autopsy.casemodule.CaseMetadata; -import org.sleuthkit.autopsy.coordinationservice.CaseNodeData; +import org.sleuthkit.autopsy.casemodule.CaseNodeData; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.Lock; @@ -498,7 +498,6 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen } SYS_LOGGER.log(Level.INFO, "Starting input scan of {0}", rootInputDirectory); InputDirScanner scanner = new InputDirScanner(); - scanner.scan(); SYS_LOGGER.log(Level.INFO, "Completed input scan of {0}", rootInputDirectory); } @@ -554,12 +553,10 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen if (!prioritizedJobs.isEmpty()) { ++maxPriority; for (AutoIngestJob job : prioritizedJobs) { - int oldPriority = job.getPriority(); - job.setPriority(maxPriority); try { this.updateCoordinationServiceManifestNode(job); + job.setPriority(maxPriority); } catch (CoordinationServiceException | InterruptedException ex) { - job.setPriority(oldPriority); throw new AutoIngestManagerException("Error updating case priority", ex); } } @@ -610,14 +607,12 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen */ if (null != prioritizedJob) { ++maxPriority; - int oldPriority = prioritizedJob.getPriority(); - prioritizedJob.setPriority(maxPriority); try { this.updateCoordinationServiceManifestNode(prioritizedJob); } catch (CoordinationServiceException | InterruptedException ex) { - prioritizedJob.setPriority(oldPriority); throw new AutoIngestManagerException("Error updating job priority", ex); } + prioritizedJob.setPriority(maxPriority); } Collections.sort(pendingJobs, new AutoIngestJob.PriorityComparator()); @@ -872,9 +867,9 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen /** * Sets the coordination service manifest node. * - * Note that a new auto ingest job node data object will be created from the - * job passed in. Thus, if the data version of the node has changed, the - * node will be "upgraded" as well as updated. + * Note that a new auto ingest job node data object will be created from + * the job passed in. Thus, if the data version of the node has changed, + * the node will be "upgraded" as well as updated. * * @param job The auto ingest job. */ @@ -884,19 +879,14 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen byte[] rawData = nodeData.toArray(); coordinationService.setNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestNodePath, rawData); } - + /** - * Sets the error flag for case node data given a case directory path. + * Sets the coordination service case node. * - * @param caseDirectoryPath The case directory path. - * - * @throws CoordinationService.CoordinationServiceException - * @throws InterruptedException - * @throws CaseNodeData.InvalidDataException + * @param caseNodeData The case node data. + * @param caseDirectoryPath The case directory. */ - private void setCaseNodeDataErrorsOccurred(Path caseDirectoryPath) throws CoordinationServiceException, InterruptedException, CaseNodeData.InvalidDataException { - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); + void updateCoordinationServiceCaseNode(CaseNodeData caseNodeData, Path caseDirectoryPath) throws CoordinationServiceException, InterruptedException { byte[] rawData = caseNodeData.toArray(); coordinationService.setNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString(), rawData); } @@ -1062,8 +1052,8 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen if (null != manifest) { /* - * Update the mapping of case names to manifest paths that - * is used for case deletion. + * Update the mapping of case names to manifest paths that is + * used for case deletion. */ String caseName = manifest.getCaseName(); Path manifestPath = manifest.getFilePath(); @@ -1077,8 +1067,8 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen } /* - * Add a job to the pending jobs queue, the completed jobs - * list, or do crashed job recovery, as required. + * Add a job to the pending jobs queue, the completed jobs list, + * or do crashed job recovery, as required. */ try { byte[] rawData = coordinationService.getNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestPath.toString()); @@ -1098,7 +1088,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen break; case DELETED: /* - * Ignore jobs marked as "deleted." + * Ignore jobs marked as "deleted." */ break; default: @@ -1208,8 +1198,8 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen private void addNewPendingJob(Manifest manifest) throws InterruptedException, AutoIngestJobException { /* * Create the coordination service manifest node data for the job. - * Note that getting the lock will create the node for the job (with - * no data) if it does not already exist. + * Note that getting the lock will create the node for the job + * (with no data) if it does not already exist. * * An exclusive lock is obtained before creating the node data * because another host may have already found the job, obtained an @@ -1239,15 +1229,13 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen * the node that was processing the job crashed and the processing * status was not updated. * - * @param manifest The manifest for upgrading the node. + * @param manifest The manifest for upgrading the node. * @param jobNodeData The auto ingest job node data. * - * @throws InterruptedException if the thread running the input - * directory scan task is interrupted - * while blocked, i.e., if auto ingest is - * shutting down. - * @throws AutoIngestJobException if there is an issue creating a new - * AutoIngestJob object. + * @throws InterruptedException if the thread running the input + * directory scan task is interrupted while + * blocked, i.e., if auto ingest is + * shutting down. */ private void doRecoveryIfCrashed(Manifest manifest, AutoIngestJobNodeData jobNodeData) throws InterruptedException, AutoIngestJobException { /* @@ -1260,35 +1248,51 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen if (null != manifestLock) { SYS_LOGGER.log(Level.SEVERE, "Attempting crash recovery for {0}", manifestPath); try { - Path caseDirectoryPath = PathUtils.findCaseDirectory(rootOutputDirectory, manifest.getCaseName()); - /* * Create the recovery job. */ AutoIngestJob job = new AutoIngestJob(jobNodeData); int numberOfCrashes = job.getNumberOfCrashes(); - if (numberOfCrashes <= AutoIngestUserPreferences.getMaxNumTimesToProcessImage()) { - ++numberOfCrashes; - job.setNumberOfCrashes(numberOfCrashes); - if (numberOfCrashes <= AutoIngestUserPreferences.getMaxNumTimesToProcessImage()) { - job.setCompletedDate(new Date(0)); - } else { - job.setCompletedDate(Date.from(Instant.now())); - } - } - + ++numberOfCrashes; + job.setNumberOfCrashes(numberOfCrashes); + job.setCompletedDate(new Date(0)); + Path caseDirectoryPath = PathUtils.findCaseDirectory(rootOutputDirectory, manifest.getCaseName()); if (null != caseDirectoryPath) { job.setCaseDirectoryPath(caseDirectoryPath); job.setErrorsOccurred(true); - try { - setCaseNodeDataErrorsOccurred(caseDirectoryPath); - } catch (CaseNodeData.InvalidDataException ex) { - SYS_LOGGER.log(Level.SEVERE, String.format("Error attempting to get case node data for %s", caseDirectoryPath), ex); - } } else { job.setErrorsOccurred(false); } + /* + * Update the coordination service manifest node for + * the job. If this fails, leave the recovery to + * another host. + */ + try { + updateCoordinationServiceManifestNode(job); + if (numberOfCrashes <= AutoIngestUserPreferences.getMaxNumTimesToProcessImage()) { + newPendingJobsList.add(job); + } else { + newCompletedJobsList.add(new AutoIngestJob(jobNodeData)); + } + } catch (CoordinationServiceException ex) { + SYS_LOGGER.log(Level.SEVERE, String.format("Error attempting to set node data for %s", manifestPath), ex); + return; + } + + /* + * Update the case node data and do the logging. + */ + if (null != caseDirectoryPath) { + try { + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + } catch (CaseNodeData.InvalidDataException ex) { + SYS_LOGGER.log(Level.SEVERE, String.format("Error attempting to get case node data for %s", caseDirectoryPath), ex); + } + } if (numberOfCrashes <= AutoIngestUserPreferences.getMaxNumTimesToProcessImage()) { job.setProcessingStatus(AutoIngestJob.ProcessingStatus.PENDING); if (null != caseDirectoryPath) { @@ -1302,32 +1306,13 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen job.setProcessingStatus(AutoIngestJob.ProcessingStatus.COMPLETED); if (null != caseDirectoryPath) { try { - new AutoIngestJobLogger(manifest.getFilePath(), manifest.getDataSourceFileName(), caseDirectoryPath).logCrashRecoveryNoRetry(); + new AutoIngestJobLogger(manifest.getFilePath(), manifest.getDataSourceFileName(), jobNodeData.getCaseDirectoryPath()).logCrashRecoveryNoRetry(); } catch (AutoIngestJobLoggerException ex) { SYS_LOGGER.log(Level.SEVERE, String.format("Error creating case auto ingest log entry for crashed job for %s", manifestPath), ex); } } } - /* - * Update the coordination service node for the job. If - * this fails, leave the recovery to another host. - */ - try { - updateCoordinationServiceManifestNode(job); - } catch (CoordinationServiceException ex) { - SYS_LOGGER.log(Level.SEVERE, String.format("Error attempting to set node data for %s", manifestPath), ex); - return; - } - - jobNodeData = new AutoIngestJobNodeData(job); - - if (numberOfCrashes <= AutoIngestUserPreferences.getMaxNumTimesToProcessImage()) { - newPendingJobsList.add(job); - } else { - newCompletedJobsList.add(new AutoIngestJob(jobNodeData)); - } - } finally { try { manifestLock.release(); @@ -1382,10 +1367,11 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen /* * Try to upgrade/update the coordination service manifest - * node data for the job. It is possible that two hosts will - * both try to obtain the lock to do the upgrade operation - * at the same time. If this happens, the host that is - * holding the lock will complete the upgrade operation. + * node data for the job. It is possible that two hosts + * will both try to obtain the lock to do the upgrade + * operation at the same time. If this happens, the host + * that is holding the lock will complete the upgrade + * operation. */ try (Lock manifestLock = coordinationService.tryGetExclusiveLock(CoordinationService.CategoryNode.MANIFESTS, manifest.getFilePath().toString())) { if (null != manifestLock) { @@ -1967,7 +1953,9 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen if (currentJob.isCanceled()) { Path caseDirectoryPath = currentJob.getCaseDirectoryPath(); if (null != caseDirectoryPath) { - setCaseNodeDataErrorsOccurred(caseDirectoryPath); + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); AutoIngestJobLogger jobLogger = new AutoIngestJobLogger(manifestPath, currentJob.getManifest().getDataSourceFileName(), caseDirectoryPath); jobLogger.logJobCancelled(); } @@ -2292,7 +2280,9 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen if (!dataSource.exists()) { SYS_LOGGER.log(Level.SEVERE, "Missing data source for {0}", manifestPath); currentJob.setErrorsOccurred(true); - setCaseNodeDataErrorsOccurred(caseDirectoryPath); + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); jobLogger.logMissingDataSource(); return null; } @@ -2340,7 +2330,9 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen // did we find a data source processor that can process the data source if (validDataSourceProcessorsMap.isEmpty()) { // This should never happen. We should add all unsupported data sources as logical files. - setCaseNodeDataErrorsOccurred(caseDirectoryPath); + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); currentJob.setErrorsOccurred(true); jobLogger.logFailedToIdentifyDataSource(); SYS_LOGGER.log(Level.WARNING, "Unsupported data source {0} for {1}", new Object[]{dataSource.getPath(), manifestPath}); // NON-NLS @@ -2366,7 +2358,9 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen // Log that the current DSP failed and set the error flag. We consider it an error // if a DSP fails even if a later one succeeds since we expected to be able to process // the data source which each DSP on the list. - setCaseNodeDataErrorsOccurred(caseDirectoryPath); + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); currentJob.setErrorsOccurred(true); jobLogger.logDataSourceProcessorError(selectedProcessor.getDataSourceType()); SYS_LOGGER.log(Level.SEVERE, "Exception while processing {0} with data source processor {1}", new Object[]{dataSource.getPath(), selectedProcessor.getDataSourceType()}); @@ -2410,7 +2404,9 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen jobLogger.logDataSourceAdded(); if (dataSource.getContent().isEmpty()) { currentJob.setErrorsOccurred(true); - setCaseNodeDataErrorsOccurred(caseDirectoryPath); + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); jobLogger.logNoDataSourceContent(); } break; @@ -2422,7 +2418,9 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen jobLogger.logDataSourceAdded(); if (dataSource.getContent().isEmpty()) { currentJob.setErrorsOccurred(true); - setCaseNodeDataErrorsOccurred(caseDirectoryPath); + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); jobLogger.logNoDataSourceContent(); } break; @@ -2432,7 +2430,9 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen SYS_LOGGER.log(Level.SEVERE, "Critical error running data source processor for {0}: {1}", new Object[]{manifestPath, errorMessage}); } currentJob.setErrorsOccurred(true); - setCaseNodeDataErrorsOccurred(caseDirectoryPath); + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); jobLogger.logFailedToAddDataSource(); break; } @@ -2446,7 +2446,9 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen */ SYS_LOGGER.log(Level.WARNING, "Cancellation while waiting for data source processor for {0}", manifestPath); currentJob.setErrorsOccurred(true); - setCaseNodeDataErrorsOccurred(caseDirectoryPath); + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); jobLogger.logDataSourceProcessorCancelled(); } } @@ -2500,7 +2502,9 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen if (!cancelledModules.isEmpty()) { SYS_LOGGER.log(Level.WARNING, String.format("Ingest module(s) cancelled for %s", manifestPath)); currentJob.setErrorsOccurred(true); - setCaseNodeDataErrorsOccurred(caseDirectoryPath); + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); for (String module : snapshot.getCancelledDataSourceIngestModules()) { SYS_LOGGER.log(Level.WARNING, String.format("%s ingest module cancelled for %s", module, manifestPath)); jobLogger.logIngestModuleCancelled(module); @@ -2510,7 +2514,9 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen } else { currentJob.setProcessingStage(AutoIngestJob.Stage.CANCELLING, Date.from(Instant.now())); currentJob.setErrorsOccurred(true); - setCaseNodeDataErrorsOccurred(caseDirectoryPath); + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); jobLogger.logAnalysisCancelled(); CancellationReason cancellationReason = snapshot.getCancellationReason(); if (CancellationReason.NOT_CANCELLED != cancellationReason && CancellationReason.USER_CANCELLED != cancellationReason) { @@ -2523,13 +2529,17 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen SYS_LOGGER.log(Level.SEVERE, String.format("%s ingest module startup error for %s", error.getModuleDisplayName(), manifestPath), error.getThrowable()); } currentJob.setErrorsOccurred(true); - setCaseNodeDataErrorsOccurred(caseDirectoryPath); + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); jobLogger.logIngestModuleStartupErrors(); throw new AnalysisStartupException(String.format("Error(s) during ingest module startup for %s", manifestPath)); } else { SYS_LOGGER.log(Level.SEVERE, String.format("Ingest manager ingest job start error for %s", manifestPath), ingestJobStartResult.getStartupException()); currentJob.setErrorsOccurred(true); - setCaseNodeDataErrorsOccurred(caseDirectoryPath); + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); jobLogger.logAnalysisStartupError(); throw new AnalysisStartupException("Ingest manager error starting job", ingestJobStartResult.getStartupException()); } @@ -2538,7 +2548,9 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen SYS_LOGGER.log(Level.SEVERE, "Ingest job settings error for {0}: {1}", new Object[]{manifestPath, warning}); } currentJob.setErrorsOccurred(true); - setCaseNodeDataErrorsOccurred(caseDirectoryPath); + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); jobLogger.logIngestJobSettingsErrors(); throw new AnalysisStartupException("Error(s) in ingest job settings"); } @@ -2581,7 +2593,9 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen } catch (FileExportException ex) { SYS_LOGGER.log(Level.SEVERE, String.format("Error doing file export for %s", manifestPath), ex); currentJob.setErrorsOccurred(true); - setCaseNodeDataErrorsOccurred(caseDirectoryPath); + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); jobLogger.logFileExportError(); } } @@ -2924,7 +2938,6 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen PARTIALLY_DELETED, FULLY_DELETED } - static final class AutoIngestManagerException extends Exception { private static final long serialVersionUID = 1L; @@ -2939,4 +2952,4 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen } -} +} \ No newline at end of file diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsCollector.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsCollector.java new file mode 100755 index 0000000000..9567b70470 --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsCollector.java @@ -0,0 +1,160 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.experimental.autoingest; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import org.sleuthkit.autopsy.coordinationservice.CoordinationService; +import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; +import org.sleuthkit.autopsy.coreutils.Logger; + +/** + * Collects metrics for an auto ingest cluster. + */ +final class AutoIngestMetricsCollector { + + private static final Logger LOGGER = Logger.getLogger(AutoIngestMetricsCollector.class.getName()); + private CoordinationService coordinationService; + + /** + * Creates an instance of the AutoIngestMetricsCollector. + * + * @throws AutoIngestMetricsCollector.AutoIngestMetricsCollectorException + */ + AutoIngestMetricsCollector() throws AutoIngestMetricsCollectorException { + try { + coordinationService = CoordinationService.getInstance(); + } catch (CoordinationServiceException ex) { + throw new AutoIngestMetricsCollectorException("Failed to get coordination service", ex); //NON-NLS + } + } + + /** + * Gets a new metrics snapshot from the coordination service for an auto + * ingest cluster. + * + * @return The metrics snapshot. + */ + MetricsSnapshot queryCoordinationServiceForMetrics() { + try { + MetricsSnapshot newMetricsSnapshot = new MetricsSnapshot(); + List nodeList = coordinationService.getNodeList(CoordinationService.CategoryNode.MANIFESTS); + for (String node : nodeList) { + try { + AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.MANIFESTS, node)); + if (nodeData.getVersion() < 1) { + /* + * Ignore version '0' nodes that have not been + * "upgraded" since they don't carry enough data. + */ + continue; + } + AutoIngestJob job = new AutoIngestJob(nodeData); + AutoIngestJob.ProcessingStatus processingStatus = nodeData.getProcessingStatus(); + switch (processingStatus) { + case PENDING: + case PROCESSING: + case DELETED: + /* + * These are not jobs we care about for metrics, so + * we will ignore them. + */ + break; + case COMPLETED: + newMetricsSnapshot.addCompletedJobDate(job.getCompletedDate()); + break; + default: + LOGGER.log(Level.SEVERE, "Unknown AutoIngestJobData.ProcessingStatus"); + break; + } + } catch (InterruptedException ex) { + LOGGER.log(Level.SEVERE, String.format("Unexpected interrupt while retrieving coordination service node data for '%s'", node), ex); + } catch (AutoIngestJobNodeData.InvalidDataException ex) { + LOGGER.log(Level.SEVERE, String.format("Unable to use node data for '%s'", node), ex); + } catch (AutoIngestJob.AutoIngestJobException ex) { + LOGGER.log(Level.SEVERE, String.format("Failed to create a job for '%s'", node), ex); + } + } + + return newMetricsSnapshot; + + } catch (CoordinationService.CoordinationServiceException ex) { + LOGGER.log(Level.SEVERE, "Failed to get node list from coordination service", ex); + return new MetricsSnapshot(); + } + } + + /** + * A snapshot of metrics for an auto ingest cluster. + */ + static final class MetricsSnapshot { + + private final List completedJobDates = new ArrayList<>(); + + /** + * Gets a list of completed job dates, formatted in milliseconds. + * + * @return The completed job dates, formatted in milliseconds. + */ + List getCompletedJobDates() { + return new ArrayList<>(completedJobDates); + } + + /** + * Adds a new date to the list of completed job dates. + * + * @param date The date to be added. + */ + void addCompletedJobDate(java.util.Date date) { + completedJobDates.add(date.getTime()); + } + } + + /** + * Exception type thrown when there is an error completing an auto ingest + * metrics collector operation. + */ + static final class AutoIngestMetricsCollectorException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructs an instance of the exception type thrown when there is an + * error completing an auto ingest metrics collector operation. + * + * @param message The exception message. + */ + private AutoIngestMetricsCollectorException(String message) { + super(message); + } + + /** + * Constructs an instance of the exception type thrown when there is an + * error completing an auto ingest metrics collector operation. + * + * @param message The exception message. + * @param cause A Throwable cause for the error. + */ + private AutoIngestMetricsCollectorException(String message, Throwable cause) { + super(message, cause); + } + + } +} \ No newline at end of file diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java index 66c6d28581..80bcb6958b 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java @@ -29,27 +29,30 @@ import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; /** - * Display basic metrics for a cluster. + * Displays auto ingest metrics for a cluster. */ final class AutoIngestMetricsDialog extends javax.swing.JDialog { - private final AutoIngestMonitor autoIngestMonitor; + private final AutoIngestMetricsCollector autoIngestMetricsCollector; /** - * Creates new form AutoIngestMetricsDialog + * Creates an instance of AutoIngestMetricsDialog * * @param parent The parent container. - * @param autoIngestMonitor The auto ingest monitor. */ @Messages({ "AutoIngestMetricsDialog.title.text=Auto Ingest Cluster Metrics", "AutoIngestMetricsDialog.initReportText=Select a date below and click the 'Get Metrics Since...' button to generate\na metrics report." }) - AutoIngestMetricsDialog(Container parent, AutoIngestMonitor autoIngestMonitor) { + AutoIngestMetricsDialog(Container parent) throws AutoIngestMetricsDialogException { super((Window) parent, NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.title.text"), ModalityType.MODELESS); + try { + autoIngestMetricsCollector = new AutoIngestMetricsCollector(); + } catch (AutoIngestMetricsCollector.AutoIngestMetricsCollectorException ex) { + throw new AutoIngestMetricsDialogException("Error starting up the auto ingest metrics dialog.", ex); + } initComponents(); reportTextArea.setText(NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.initReportText")); - this.autoIngestMonitor = autoIngestMonitor; setModal(true); setSize(getPreferredSize()); setLocationRelativeTo(parent); @@ -64,7 +67,7 @@ final class AutoIngestMetricsDialog extends javax.swing.JDialog { return; } - AutoIngestMonitor.MetricsSnapshot metricsSnapshot = autoIngestMonitor.getMetricsSnapshot(); + AutoIngestMetricsCollector.MetricsSnapshot metricsSnapshot = autoIngestMetricsCollector.queryCoordinationServiceForMetrics(); Object[] completedJobDates = metricsSnapshot.getCompletedJobDates().toArray(); int count = 0; long pickedDate = datePicker.getDate().atStartOfDay().toEpochSecond(ZoneOffset.UTC) * 1000; @@ -82,6 +85,37 @@ final class AutoIngestMetricsDialog extends javax.swing.JDialog { count )); } + + /** + * Exception type thrown when there is an error completing an auto ingest + * metrics dialog operation. + */ + static final class AutoIngestMetricsDialogException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructs an instance of the exception type thrown when there is an + * error completing an auto ingest metrics dialog operation. + * + * @param message The exception message. + */ + private AutoIngestMetricsDialogException(String message) { + super(message); + } + + /** + * Constructs an instance of the exception type thrown when there is an + * error completing an auto ingest metrics dialog operation. + * + * @param message The exception message. + * @param cause A Throwable cause for the error. + */ + private AutoIngestMetricsDialogException(String message, Throwable cause) { + super(message, cause); + } + + } /** * This method is called from within the constructor to initialize the form. @@ -175,4 +209,4 @@ final class AutoIngestMetricsDialog extends javax.swing.JDialog { private javax.swing.JButton metricsButton; private javax.swing.JTextArea reportTextArea; // End of variables declaration//GEN-END:variables -} +} \ No newline at end of file diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java index 37c635b9f0..e46a5e43c0 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java @@ -23,12 +23,10 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Arrays; -import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Observable; import java.util.Set; -import java.util.TreeSet; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.logging.Level; @@ -282,71 +280,6 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen } } - /** - * Gets a new metrics snapshot from the coordination service for an auto - * ingest cluster. - * - * @return The metrics snapshot. - */ - private MetricsSnapshot queryCoordinationServiceForMetrics() { - try { - MetricsSnapshot newMetricsSnapshot = new MetricsSnapshot(); - List nodeList = coordinationService.getNodeList(CoordinationService.CategoryNode.MANIFESTS); - for (String node : nodeList) { - try { - AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.MANIFESTS, node)); - if (nodeData.getVersion() < 1) { - /* - * Ignore version '0' nodes that have not been - * "upgraded" since they don't carry enough data. - */ - continue; - } - AutoIngestJob job = new AutoIngestJob(nodeData); - ProcessingStatus processingStatus = nodeData.getProcessingStatus(); - switch (processingStatus) { - case PENDING: - case PROCESSING: - case DELETED: - /* - * These are not jobs we care about for metrics, so - * we will ignore them. - */ - break; - case COMPLETED: - newMetricsSnapshot.addCompletedJobDate(job.getCompletedDate()); - break; - default: - LOGGER.log(Level.SEVERE, "Unknown AutoIngestJobData.ProcessingStatus"); - break; - } - } catch (InterruptedException ex) { - LOGGER.log(Level.SEVERE, String.format("Unexpected interrupt while retrieving coordination service node data for '%s'", node), ex); - } catch (AutoIngestJobNodeData.InvalidDataException ex) { - LOGGER.log(Level.SEVERE, String.format("Unable to use node data for '%s'", node), ex); - } catch (AutoIngestJob.AutoIngestJobException ex) { - LOGGER.log(Level.SEVERE, String.format("Failed to create a job for '%s'", node), ex); - } - } - - return newMetricsSnapshot; - - } catch (CoordinationServiceException ex) { - LOGGER.log(Level.SEVERE, "Failed to get node list from coordination service", ex); - return new MetricsSnapshot(); - } - } - - /** - * Gets a new metrics snapshot. The jobs snapshot will also be updated in - * effect. - * - * @return The metrics snapshot. - */ - public MetricsSnapshot getMetricsSnapshot() { - return queryCoordinationServiceForMetrics(); - } - /** * Bumps the priority of all pending ingest jobs for a specified case. * @@ -593,32 +526,6 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen } - /** - * A snapshot of metrics for an auto ingest cluster. - */ - public static final class MetricsSnapshot { - - private final List completedJobDates = new ArrayList<>(); - - /** - * Gets a list of completed job dates, formatted in milliseconds. - * - * @return The completed job dates, formatted in milliseconds. - */ - List getCompletedJobDates() { - return new ArrayList<>(completedJobDates); - } - - /** - * Adds a new date to the list of completed job dates. - * - * @param date The date to be added. - */ - void addCompletedJobDate(Date date) { - completedJobDates.add(date.getTime()); - } - } - /** * Exception type thrown when there is an error completing an auto ingest * monitor operation. @@ -649,4 +556,4 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen } } -} +} \ No newline at end of file From e63c7d8723ee7188d64ab78da75084bb2ced55e8 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Mon, 13 Nov 2017 16:28:55 -0500 Subject: [PATCH 096/115] Cleanup. --- .../autopsy/experimental/autoingest/AutoIngestManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index 2ce6e2cba8..cf5e30ffed 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -2807,7 +2807,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen } } - } catch (Exception ex) { + } catch (CoordinationServiceException | InterruptedException ex) { SYS_LOGGER.log(Level.SEVERE, "Unexpected exception in PeriodicJobStatusEventTask", ex); //NON-NLS } } From 556810da0ebc3ca64b77a9746b527025590d8eb8 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Mon, 13 Nov 2017 16:52:19 -0500 Subject: [PATCH 097/115] Fixed merge conflict. --- .../autoingest/AutoIngestControlPanel.java | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java index 8024fbf93a..be8abbd1ee 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java @@ -1579,11 +1579,11 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { "AutoIngestControlPanel.DeletionFailed=Deletion failed for job" }) private void bnDeleteCaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnDeleteCaseActionPerformed - if (completedTableModel.getRowCount() < 0 || completedTable.getSelectedRow() < 0) { + if (completedTable.getModel().getRowCount() < 0 || completedTable.getSelectedRow() < 0) { return; } - String caseName = (String) completedTable.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal()); + String caseName = (String) completedTable.getModel().getValueAt(completedTable.convertRowIndexToModel(completedTable.getSelectedRow()), JobsTableModelColumns.CASE.ordinal()); Object[] options = { org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "ConfirmationDialog.Delete"), org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "ConfirmationDialog.DoNotDelete") @@ -1600,8 +1600,8 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { if (reply == JOptionPane.YES_OPTION) { bnDeleteCase.setEnabled(false); bnShowCaseLog.setEnabled(false); - if (completedTableModel.getRowCount() > 0 && completedTable.getSelectedRow() >= 0) { - Path caseDirectoryPath = (Path) completedTableModel.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.CASE_DIRECTORY_PATH.ordinal()); + if (completedTable.getModel().getRowCount() > 0 && completedTable.getSelectedRow() >= 0) { + Path caseDirectoryPath = (Path) completedTable.getModel().getValueAt(completedTable.convertRowIndexToModel(completedTable.getSelectedRow()), JobsTableModelColumns.CASE_DIRECTORY_PATH.ordinal()); completedTable.clearSelection(); this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); CaseDeletionResult result = manager.deleteCase(caseName, caseDirectoryPath); @@ -1747,9 +1747,10 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { */ @Messages({"AutoIngestControlPanel.casePrioritization.errorMessage=An error occurred when prioritizing the case. Some or all jobs may not have been prioritized."}) private void bnPrioritizeCaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPrioritizeCaseActionPerformed - if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { + if (pendingTable.getModel().getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - String caseName = (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal())).toString(); + + String caseName = (pendingTable.getModel().getValueAt(pendingTable.convertRowIndexToModel(pendingTable.getSelectedRow()), JobsTableModelColumns.CASE.ordinal())).toString(); try { manager.prioritizeCase(caseName); } catch (AutoIngestManager.AutoIngestManagerException ex) { @@ -1775,9 +1776,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { }) private void bnShowCaseLogActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnShowCaseLogActionPerformed try { - int selectedRow = completedTable.getSelectedRow(); + int selectedRow = completedTable.convertRowIndexToModel(completedTable.getSelectedRow()); if (selectedRow != -1) { - Path caseDirectoryPath = (Path) completedTableModel.getValueAt(selectedRow, JobsTableModelColumns.CASE_DIRECTORY_PATH.ordinal()); + Path caseDirectoryPath = (Path) completedTable.getModel().getValueAt(selectedRow, JobsTableModelColumns.CASE_DIRECTORY_PATH.ordinal()); if (null != caseDirectoryPath) { Path pathToLog = AutoIngestJobLogger.getLogPath(caseDirectoryPath); if (pathToLog.toFile().exists()) { @@ -1806,9 +1807,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { @Messages({"AutoIngestControlPanel.jobPrioritization.errorMessage=An error occurred when prioritizing the job."}) private void bnPrioritizeJobActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPrioritizeJobActionPerformed - if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { + if (pendingTable.getModel().getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - Path manifestFilePath = (Path) (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal())); + Path manifestFilePath = (Path) (pendingTable.getModel().getValueAt(pendingTable.convertRowIndexToModel(pendingTable.getSelectedRow()), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal())); try { manager.prioritizeJob(manifestFilePath); } catch (AutoIngestManager.AutoIngestManagerException ex) { @@ -1835,11 +1836,11 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { }//GEN-LAST:event_bnOpenLogDirActionPerformed private void bnReprocessJobActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnReprocessJobActionPerformed - if (completedTableModel.getRowCount() < 0 || completedTable.getSelectedRow() < 0) { + if (completedTable.getModel().getRowCount() < 0 || completedTable.getSelectedRow() < 0) { return; } this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - Path manifestPath = (Path) completedTableModel.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal()); + Path manifestPath = (Path) completedTable.getModel().getValueAt(completedTable.convertRowIndexToModel(completedTable.getSelectedRow()), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal()); manager.reprocessJob(manifestPath); refreshTables(); AutoIngestControlPanel.this.setCursor(Cursor.getDefaultCursor()); From 22f023002c7d8396eab0366a60134850d72d506e Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 14 Nov 2017 02:24:24 -0500 Subject: [PATCH 098/115] Fixed merge issue. --- .../autoingest/AutoIngestManager.java | 197 ++++++++---------- 1 file changed, 92 insertions(+), 105 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index cf5e30ffed..338544d9a8 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -64,7 +64,7 @@ import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.casemodule.CaseActionException; import org.sleuthkit.autopsy.casemodule.CaseDetails; import org.sleuthkit.autopsy.casemodule.CaseMetadata; -import org.sleuthkit.autopsy.casemodule.CaseNodeData; +import org.sleuthkit.autopsy.coordinationservice.CaseNodeData; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.Lock; @@ -498,6 +498,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen } SYS_LOGGER.log(Level.INFO, "Starting input scan of {0}", rootInputDirectory); InputDirScanner scanner = new InputDirScanner(); + scanner.scan(); SYS_LOGGER.log(Level.INFO, "Completed input scan of {0}", rootInputDirectory); } @@ -553,10 +554,12 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen if (!prioritizedJobs.isEmpty()) { ++maxPriority; for (AutoIngestJob job : prioritizedJobs) { + int oldPriority = job.getPriority(); + job.setPriority(maxPriority); try { this.updateCoordinationServiceManifestNode(job); - job.setPriority(maxPriority); } catch (CoordinationServiceException | InterruptedException ex) { + job.setPriority(oldPriority); throw new AutoIngestManagerException("Error updating case priority", ex); } } @@ -607,12 +610,14 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen */ if (null != prioritizedJob) { ++maxPriority; + int oldPriority = prioritizedJob.getPriority(); + prioritizedJob.setPriority(maxPriority); try { this.updateCoordinationServiceManifestNode(prioritizedJob); } catch (CoordinationServiceException | InterruptedException ex) { + prioritizedJob.setPriority(oldPriority); throw new AutoIngestManagerException("Error updating job priority", ex); } - prioritizedJob.setPriority(maxPriority); } Collections.sort(pendingJobs, new AutoIngestJob.PriorityComparator()); @@ -867,9 +872,9 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen /** * Sets the coordination service manifest node. * - * Note that a new auto ingest job node data object will be created from - * the job passed in. Thus, if the data version of the node has changed, - * the node will be "upgraded" as well as updated. + * Note that a new auto ingest job node data object will be created from the + * job passed in. Thus, if the data version of the node has changed, the + * node will be "upgraded" as well as updated. * * @param job The auto ingest job. */ @@ -879,14 +884,19 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen byte[] rawData = nodeData.toArray(); coordinationService.setNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestNodePath, rawData); } - + /** - * Sets the coordination service case node. + * Sets the error flag for case node data given a case directory path. * - * @param caseNodeData The case node data. - * @param caseDirectoryPath The case directory. + * @param caseDirectoryPath The case directory path. + * + * @throws CoordinationService.CoordinationServiceException + * @throws InterruptedException + * @throws CaseNodeData.InvalidDataException */ - void updateCoordinationServiceCaseNode(CaseNodeData caseNodeData, Path caseDirectoryPath) throws CoordinationServiceException, InterruptedException { + private void setCaseNodeDataErrorsOccurred(Path caseDirectoryPath) throws CoordinationServiceException, InterruptedException, CaseNodeData.InvalidDataException { + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); byte[] rawData = caseNodeData.toArray(); coordinationService.setNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString(), rawData); } @@ -1052,8 +1062,8 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen if (null != manifest) { /* - * Update the mapping of case names to manifest paths that is - * used for case deletion. + * Update the mapping of case names to manifest paths that + * is used for case deletion. */ String caseName = manifest.getCaseName(); Path manifestPath = manifest.getFilePath(); @@ -1067,8 +1077,8 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen } /* - * Add a job to the pending jobs queue, the completed jobs list, - * or do crashed job recovery, as required. + * Add a job to the pending jobs queue, the completed jobs + * list, or do crashed job recovery, as required. */ try { byte[] rawData = coordinationService.getNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestPath.toString()); @@ -1088,7 +1098,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen break; case DELETED: /* - * Ignore jobs marked as "deleted." + * Ignore jobs marked as "deleted." */ break; default: @@ -1198,8 +1208,8 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen private void addNewPendingJob(Manifest manifest) throws InterruptedException, AutoIngestJobException { /* * Create the coordination service manifest node data for the job. - * Note that getting the lock will create the node for the job - * (with no data) if it does not already exist. + * Note that getting the lock will create the node for the job (with + * no data) if it does not already exist. * * An exclusive lock is obtained before creating the node data * because another host may have already found the job, obtained an @@ -1229,13 +1239,15 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen * the node that was processing the job crashed and the processing * status was not updated. * - * @param manifest The manifest for upgrading the node. + * @param manifest The manifest for upgrading the node. * @param jobNodeData The auto ingest job node data. * - * @throws InterruptedException if the thread running the input - * directory scan task is interrupted while - * blocked, i.e., if auto ingest is - * shutting down. + * @throws InterruptedException if the thread running the input + * directory scan task is interrupted + * while blocked, i.e., if auto ingest is + * shutting down. + * @throws AutoIngestJobException if there is an issue creating a new + * AutoIngestJob object. */ private void doRecoveryIfCrashed(Manifest manifest, AutoIngestJobNodeData jobNodeData) throws InterruptedException, AutoIngestJobException { /* @@ -1248,51 +1260,35 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen if (null != manifestLock) { SYS_LOGGER.log(Level.SEVERE, "Attempting crash recovery for {0}", manifestPath); try { + Path caseDirectoryPath = PathUtils.findCaseDirectory(rootOutputDirectory, manifest.getCaseName()); + /* * Create the recovery job. */ AutoIngestJob job = new AutoIngestJob(jobNodeData); int numberOfCrashes = job.getNumberOfCrashes(); - ++numberOfCrashes; - job.setNumberOfCrashes(numberOfCrashes); - job.setCompletedDate(new Date(0)); - Path caseDirectoryPath = PathUtils.findCaseDirectory(rootOutputDirectory, manifest.getCaseName()); + if (numberOfCrashes <= AutoIngestUserPreferences.getMaxNumTimesToProcessImage()) { + ++numberOfCrashes; + job.setNumberOfCrashes(numberOfCrashes); + if (numberOfCrashes <= AutoIngestUserPreferences.getMaxNumTimesToProcessImage()) { + job.setCompletedDate(new Date(0)); + } else { + job.setCompletedDate(Date.from(Instant.now())); + } + } + if (null != caseDirectoryPath) { job.setCaseDirectoryPath(caseDirectoryPath); job.setErrorsOccurred(true); + try { + setCaseNodeDataErrorsOccurred(caseDirectoryPath); + } catch (CaseNodeData.InvalidDataException ex) { + SYS_LOGGER.log(Level.SEVERE, String.format("Error attempting to get case node data for %s", caseDirectoryPath), ex); + } } else { job.setErrorsOccurred(false); } - /* - * Update the coordination service manifest node for - * the job. If this fails, leave the recovery to - * another host. - */ - try { - updateCoordinationServiceManifestNode(job); - if (numberOfCrashes <= AutoIngestUserPreferences.getMaxNumTimesToProcessImage()) { - newPendingJobsList.add(job); - } else { - newCompletedJobsList.add(new AutoIngestJob(jobNodeData)); - } - } catch (CoordinationServiceException ex) { - SYS_LOGGER.log(Level.SEVERE, String.format("Error attempting to set node data for %s", manifestPath), ex); - return; - } - - /* - * Update the case node data and do the logging. - */ - if (null != caseDirectoryPath) { - try { - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); - } catch (CaseNodeData.InvalidDataException ex) { - SYS_LOGGER.log(Level.SEVERE, String.format("Error attempting to get case node data for %s", caseDirectoryPath), ex); - } - } if (numberOfCrashes <= AutoIngestUserPreferences.getMaxNumTimesToProcessImage()) { job.setProcessingStatus(AutoIngestJob.ProcessingStatus.PENDING); if (null != caseDirectoryPath) { @@ -1306,13 +1302,32 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen job.setProcessingStatus(AutoIngestJob.ProcessingStatus.COMPLETED); if (null != caseDirectoryPath) { try { - new AutoIngestJobLogger(manifest.getFilePath(), manifest.getDataSourceFileName(), jobNodeData.getCaseDirectoryPath()).logCrashRecoveryNoRetry(); + new AutoIngestJobLogger(manifest.getFilePath(), manifest.getDataSourceFileName(), caseDirectoryPath).logCrashRecoveryNoRetry(); } catch (AutoIngestJobLoggerException ex) { SYS_LOGGER.log(Level.SEVERE, String.format("Error creating case auto ingest log entry for crashed job for %s", manifestPath), ex); } } } + /* + * Update the coordination service node for the job. If + * this fails, leave the recovery to another host. + */ + try { + updateCoordinationServiceManifestNode(job); + } catch (CoordinationServiceException ex) { + SYS_LOGGER.log(Level.SEVERE, String.format("Error attempting to set node data for %s", manifestPath), ex); + return; + } + + jobNodeData = new AutoIngestJobNodeData(job); + + if (numberOfCrashes <= AutoIngestUserPreferences.getMaxNumTimesToProcessImage()) { + newPendingJobsList.add(job); + } else { + newCompletedJobsList.add(new AutoIngestJob(jobNodeData)); + } + } finally { try { manifestLock.release(); @@ -1367,11 +1382,10 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen /* * Try to upgrade/update the coordination service manifest - * node data for the job. It is possible that two hosts - * will both try to obtain the lock to do the upgrade - * operation at the same time. If this happens, the host - * that is holding the lock will complete the upgrade - * operation. + * node data for the job. It is possible that two hosts will + * both try to obtain the lock to do the upgrade operation + * at the same time. If this happens, the host that is + * holding the lock will complete the upgrade operation. */ try (Lock manifestLock = coordinationService.tryGetExclusiveLock(CoordinationService.CategoryNode.MANIFESTS, manifest.getFilePath().toString())) { if (null != manifestLock) { @@ -1953,9 +1967,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen if (currentJob.isCanceled()) { Path caseDirectoryPath = currentJob.getCaseDirectoryPath(); if (null != caseDirectoryPath) { - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); AutoIngestJobLogger jobLogger = new AutoIngestJobLogger(manifestPath, currentJob.getManifest().getDataSourceFileName(), caseDirectoryPath); jobLogger.logJobCancelled(); } @@ -2280,9 +2292,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen if (!dataSource.exists()) { SYS_LOGGER.log(Level.SEVERE, "Missing data source for {0}", manifestPath); currentJob.setErrorsOccurred(true); - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logMissingDataSource(); return null; } @@ -2330,9 +2340,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen // did we find a data source processor that can process the data source if (validDataSourceProcessorsMap.isEmpty()) { // This should never happen. We should add all unsupported data sources as logical files. - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); currentJob.setErrorsOccurred(true); jobLogger.logFailedToIdentifyDataSource(); SYS_LOGGER.log(Level.WARNING, "Unsupported data source {0} for {1}", new Object[]{dataSource.getPath(), manifestPath}); // NON-NLS @@ -2358,9 +2366,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen // Log that the current DSP failed and set the error flag. We consider it an error // if a DSP fails even if a later one succeeds since we expected to be able to process // the data source which each DSP on the list. - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); currentJob.setErrorsOccurred(true); jobLogger.logDataSourceProcessorError(selectedProcessor.getDataSourceType()); SYS_LOGGER.log(Level.SEVERE, "Exception while processing {0} with data source processor {1}", new Object[]{dataSource.getPath(), selectedProcessor.getDataSourceType()}); @@ -2404,9 +2410,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen jobLogger.logDataSourceAdded(); if (dataSource.getContent().isEmpty()) { currentJob.setErrorsOccurred(true); - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logNoDataSourceContent(); } break; @@ -2418,9 +2422,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen jobLogger.logDataSourceAdded(); if (dataSource.getContent().isEmpty()) { currentJob.setErrorsOccurred(true); - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logNoDataSourceContent(); } break; @@ -2430,9 +2432,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen SYS_LOGGER.log(Level.SEVERE, "Critical error running data source processor for {0}: {1}", new Object[]{manifestPath, errorMessage}); } currentJob.setErrorsOccurred(true); - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logFailedToAddDataSource(); break; } @@ -2446,9 +2446,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen */ SYS_LOGGER.log(Level.WARNING, "Cancellation while waiting for data source processor for {0}", manifestPath); currentJob.setErrorsOccurred(true); - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logDataSourceProcessorCancelled(); } } @@ -2502,9 +2500,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen if (!cancelledModules.isEmpty()) { SYS_LOGGER.log(Level.WARNING, String.format("Ingest module(s) cancelled for %s", manifestPath)); currentJob.setErrorsOccurred(true); - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); for (String module : snapshot.getCancelledDataSourceIngestModules()) { SYS_LOGGER.log(Level.WARNING, String.format("%s ingest module cancelled for %s", module, manifestPath)); jobLogger.logIngestModuleCancelled(module); @@ -2514,9 +2510,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen } else { currentJob.setProcessingStage(AutoIngestJob.Stage.CANCELLING, Date.from(Instant.now())); currentJob.setErrorsOccurred(true); - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logAnalysisCancelled(); CancellationReason cancellationReason = snapshot.getCancellationReason(); if (CancellationReason.NOT_CANCELLED != cancellationReason && CancellationReason.USER_CANCELLED != cancellationReason) { @@ -2529,17 +2523,13 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen SYS_LOGGER.log(Level.SEVERE, String.format("%s ingest module startup error for %s", error.getModuleDisplayName(), manifestPath), error.getThrowable()); } currentJob.setErrorsOccurred(true); - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logIngestModuleStartupErrors(); throw new AnalysisStartupException(String.format("Error(s) during ingest module startup for %s", manifestPath)); } else { SYS_LOGGER.log(Level.SEVERE, String.format("Ingest manager ingest job start error for %s", manifestPath), ingestJobStartResult.getStartupException()); currentJob.setErrorsOccurred(true); - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logAnalysisStartupError(); throw new AnalysisStartupException("Ingest manager error starting job", ingestJobStartResult.getStartupException()); } @@ -2548,9 +2538,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen SYS_LOGGER.log(Level.SEVERE, "Ingest job settings error for {0}: {1}", new Object[]{manifestPath, warning}); } currentJob.setErrorsOccurred(true); - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logIngestJobSettingsErrors(); throw new AnalysisStartupException("Error(s) in ingest job settings"); } @@ -2593,9 +2581,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen } catch (FileExportException ex) { SYS_LOGGER.log(Level.SEVERE, String.format("Error doing file export for %s", manifestPath), ex); currentJob.setErrorsOccurred(true); - CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); - caseNodeData.setErrorsOccurred(true); - updateCoordinationServiceCaseNode(caseNodeData, caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logFileExportError(); } } @@ -2807,7 +2793,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen } } - } catch (CoordinationServiceException | InterruptedException ex) { + } catch (Exception ex) { SYS_LOGGER.log(Level.SEVERE, "Unexpected exception in PeriodicJobStatusEventTask", ex); //NON-NLS } } @@ -2938,6 +2924,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen PARTIALLY_DELETED, FULLY_DELETED } + static final class AutoIngestManagerException extends Exception { private static final long serialVersionUID = 1L; From e64e30181ead01685d1c48302c5e8f1fdeba7934 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 14 Nov 2017 02:26:38 -0500 Subject: [PATCH 099/115] Typo --- .../autopsy/experimental/autoingest/AutoIngestManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index 338544d9a8..1cbe9af5a6 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -2939,4 +2939,4 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen } -} \ No newline at end of file +} From e78980cb6e7cc3d2a87638f6f6195766b4b3168e Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 14 Nov 2017 02:45:19 -0500 Subject: [PATCH 100/115] Merge --- .../autopsy/casemodule/CaseNodeData.java | 141 ------------------ 1 file changed, 141 deletions(-) delete mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/CaseNodeData.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseNodeData.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseNodeData.java deleted file mode 100755 index f4308e8954..0000000000 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseNodeData.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2017 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.casemodule; - -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; - -/** - * An object that converts case data for a case directory coordination service - * node to and from byte arrays. - */ -public final class CaseNodeData { - - private static final int CURRENT_VERSION = 0; - - private int version; - private boolean errorsOccurred; - - /** - * Gets the current version of the case directory coordination service node - * data. - * - * @return The version number. - */ - public static int getCurrentVersion() { - return CaseNodeData.CURRENT_VERSION; - } - - /** - * Uses coordination service node data to construct an object that converts - * case data for a case directory coordination service node to and from byte - * arrays. - * - * @param nodeData The raw bytes received from the coordination service. - * - * @throws InvalidDataException If the node data buffer is smaller than - * expected. - */ - public CaseNodeData(byte[] nodeData) throws InvalidDataException { - if(nodeData == null || nodeData.length == 0) { - this.version = CURRENT_VERSION; - this.errorsOccurred = false; - } else { - /* - * Get fields from node data. - */ - ByteBuffer buffer = ByteBuffer.wrap(nodeData); - try { - if (buffer.hasRemaining()) { - this.version = buffer.getInt(); - - /* - * Flags bit format: 76543210 - * 0-6 --> reserved for future use - * 7 --> errorsOccurred - */ - byte flags = buffer.get(); - this.errorsOccurred = (flags < 0); - } - } catch (BufferUnderflowException ex) { - throw new InvalidDataException("Node data is incomplete", ex); - } - } - } - - /** - * Gets whether or not any errors occurred during the processing of the job. - * - * @return True or false. - */ - public boolean getErrorsOccurred() { - return this.errorsOccurred; - } - - /** - * Sets whether or not any errors occurred during the processing of job. - * - * @param errorsOccurred True or false. - */ - public void setErrorsOccurred(boolean errorsOccurred) { - this.errorsOccurred = errorsOccurred; - } - - /** - * Gets the node data version number. - * - * @return The version number. - */ - public int getVersion() { - return this.version; - } - - /** - * Gets the node data as a byte array that can be sent to the coordination - * service. - * - * @return The node data as a byte array. - */ - public byte[] toArray() { - ByteBuffer buffer = ByteBuffer.allocate(5); - - buffer.putInt(this.version); - buffer.put((byte)(this.errorsOccurred ? 0x80 : 0)); - - // Prepare the array - byte[] array = new byte[buffer.position()]; - buffer.rewind(); - buffer.get(array, 0, array.length); - - return array; - } - - public final static class InvalidDataException extends Exception { - - private static final long serialVersionUID = 1L; - - private InvalidDataException(String message) { - super(message); - } - - private InvalidDataException(String message, Throwable cause) { - super(message, cause); - } - } -} \ No newline at end of file From 1b272cf18c14fad285e53fb1bb9519c3fdb4837d Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Tue, 14 Nov 2017 09:26:10 -0500 Subject: [PATCH 101/115] Only display valid hash sets in the ingest module settings --- .../HashLookupModuleSettingsPanel.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java index c6d3e109fe..d3bfb915d4 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java @@ -58,8 +58,8 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe } catch (TskCoreException ex){ Logger.getLogger(HashLookupModuleSettingsPanel.class.getName()).log(Level.SEVERE, "Error updating central repository hash sets", ex); //NON-NLS } - initializeHashSetModels(settings, hashDbManager.getKnownFileHashSets(), knownHashSetModels); - initializeHashSetModels(settings, hashDbManager.getKnownBadFileHashSets(), knownBadHashSetModels); + initializeHashSetModels(settings, validSetsOnly(hashDbManager.getKnownFileHashSets()), knownHashSetModels); + initializeHashSetModels(settings, validSetsOnly(hashDbManager.getKnownBadFileHashSets()), knownBadHashSetModels); } private void initializeHashSetModels(HashLookupModuleSettings settings, List hashDbs, List hashSetModels) { @@ -130,8 +130,22 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe } private void updateHashSetModels() { - updateHashSetModels(hashDbManager.getKnownFileHashSets(), knownHashSetModels); - updateHashSetModels(hashDbManager.getKnownBadFileHashSets(), knownBadHashSetModels); + updateHashSetModels(validSetsOnly(hashDbManager.getKnownFileHashSets()), knownHashSetModels); + updateHashSetModels(validSetsOnly(hashDbManager.getKnownBadFileHashSets()), knownBadHashSetModels); + } + + private List validSetsOnly(List hashDbs){ + List validDbs = new ArrayList<>(); + for(HashDb db:hashDbs){ + try{ + if(db.isValid()){ + validDbs.add(db); + } + } catch (TskCoreException ex){ + Logger.getLogger(HashLookupModuleSettingsPanel.class.getName()).log(Level.SEVERE, "Error checking validity for hash set (name = " + db.getHashSetName() + ")", ex); //NON-NLS + } + } + return validDbs; } void updateHashSetModels(List hashDbs, List hashSetModels) { From 2bb24e3d4de52068525f1a544fe070dabd82044e Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Tue, 14 Nov 2017 11:32:19 -0500 Subject: [PATCH 102/115] Remove/change some public methods. --- .../datamodel/EamGlobalSet.java | 6 +-- .../modules/hashdatabase/HashDbManager.java | 48 +++++-------------- .../hashdatabase/HashLookupSettings.java | 32 +++++++------ 3 files changed, 31 insertions(+), 55 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java index 80e7d9cb8b..e4292dc6ca 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java @@ -150,11 +150,11 @@ public class EamGlobalSet { * Return the FileKnown status as a KnownFilesType * @return KNOWN or KNOWN_BAD */ - public HashDbManager.HashDatabase.KnownFilesType getKnownStatus(){ + public HashDbManager.HashDb.KnownFilesType getKnownStatus(){ if(fileKnownStatus.equals(TskData.FileKnown.BAD)){ - return HashDbManager.HashDatabase.KnownFilesType.KNOWN_BAD; + return HashDbManager.HashDb.KnownFilesType.KNOWN_BAD; } - return HashDbManager.HashDatabase.KnownFilesType.KNOWN; + return HashDbManager.HashDb.KnownFilesType.KNOWN; } /** diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java index 412fb6410e..e656606c52 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -692,11 +692,6 @@ public class HashDbManager implements PropertyChangeListener { INDEXING_DONE } - enum DatabaseType{ - FILE, - CENTRAL_REPOSITORY - }; - public String getHashSetName(); public String getDisplayName(); @@ -709,11 +704,11 @@ public class HashDbManager implements PropertyChangeListener { public boolean getDefaultSearchDuringIngest(); - void setSearchDuringIngest(boolean useForIngest); + public void setSearchDuringIngest(boolean useForIngest); public boolean getSendIngestMessages(); - void setSendIngestMessages(boolean showInboxMessages); + public void setSendIngestMessages(boolean showInboxMessages); /** * Indicates whether the hash database accepts updates. @@ -750,8 +745,6 @@ public class HashDbManager implements PropertyChangeListener { */ public boolean isValid() throws TskCoreException; - public int getHandle(); - public String getIndexPath() throws TskCoreException; public boolean hasIndexOnly() throws TskCoreException; @@ -762,14 +755,11 @@ public class HashDbManager implements PropertyChangeListener { public void removePropertyChangeListener(PropertyChangeListener pcl); - void close() throws TskCoreException; + public void close() throws TskCoreException; @Override public String toString(); - DatabaseType getDatabaseType(); - - } /** @@ -817,8 +807,7 @@ public class HashDbManager implements PropertyChangeListener { propertyChangeSupport.removePropertyChangeListener(pcl); } - @Override - public int getHandle(){ + int getHandle(){ return handle; } @@ -840,12 +829,8 @@ public class HashDbManager implements PropertyChangeListener { public void setIndexing(boolean indexing){ this.indexing = indexing; } - - @Override - public DatabaseType getDatabaseType(){ - return DatabaseType.FILE; - } + @Override public String getIndexPath() throws TskCoreException { return SleuthkitJNI.getHashDatabaseIndexPath(handle); } @@ -996,7 +981,7 @@ public class HashDbManager implements PropertyChangeListener { return hasIndex(); } - public boolean hasIndex() throws TskCoreException { + boolean hasIndex() throws TskCoreException { return SleuthkitJNI.hashDatabaseHasLookupIndex(handle); } @@ -1005,11 +990,11 @@ public class HashDbManager implements PropertyChangeListener { return SleuthkitJNI.hashDatabaseIsIndexOnly(handle); } - public boolean canBeReIndexed() throws TskCoreException { + boolean canBeReIndexed() throws TskCoreException { return SleuthkitJNI.hashDatabaseCanBeReindexed(handle); } - public boolean isIndexing() { + boolean isIndexing() { return indexing; } @@ -1117,11 +1102,6 @@ public class HashDbManager implements PropertyChangeListener { propertyChangeSupport.removePropertyChangeListener(pcl); } - @Override - public int getHandle(){ - return 0; - } - @Override public boolean hasIndexOnly() throws TskCoreException{ return true; @@ -1137,15 +1117,15 @@ public class HashDbManager implements PropertyChangeListener { return getHashSetName() + " " + getVersion(); } - public String getVersion(){ + String getVersion(){ return version; } - public String getOrgName(){ + String getOrgName(){ return orgName; } - public int getReferenceSetID(){ + int getReferenceSetID(){ return referenceSetID; } @@ -1153,11 +1133,6 @@ public class HashDbManager implements PropertyChangeListener { public String getDatabasePath() throws TskCoreException { return ""; } - - @Override - public DatabaseType getDatabaseType(){ - return DatabaseType.CENTRAL_REPOSITORY; - } @Override public String getIndexPath() throws TskCoreException { @@ -1311,7 +1286,6 @@ public class HashDbManager implements PropertyChangeListener { * Returns whether this database can be enabled. * * @return true if is valid, false otherwise - * @throws TskCoreException */ @Override public boolean isValid() { diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java index 5dda017e54..fecc5ad192 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java @@ -36,8 +36,8 @@ import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.XMLUtil; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.DatabaseType; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.CentralRepoHashDb; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; import org.sleuthkit.datamodel.TskCoreException; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -297,6 +297,11 @@ final class HashLookupSettings implements Serializable { */ static final class HashDbInfo implements Serializable { + enum DatabaseType{ + FILE, + CENTRAL_REPOSITORY + }; + private static final long serialVersionUID = 1L; private final String hashSetName; private final HashDbManager.HashDatabase.KnownFilesType knownFilesType; @@ -466,7 +471,8 @@ final class HashLookupSettings implements Serializable { return false; } - if( ! this.dbType.equals(hashDb.getDatabaseType())){ + if((this.dbType == DatabaseType.CENTRAL_REPOSITORY) && (! (hashDb instanceof CentralRepoHashDb)) + || (this.dbType == DatabaseType.FILE) && (! (hashDb instanceof HashDatabase))){ return false; } @@ -474,19 +480,15 @@ final class HashLookupSettings implements Serializable { return false; } - if(this.dbType.equals(DatabaseType.FILE)){ - // FILE types will always have unique names, so no more testing required - return true; - } - - // Central repo tests - CentralRepoHashDb crDb = (CentralRepoHashDb) hashDb; - if(this.referenceSetID != crDb.getReferenceSetID()){ - return false; - } - - if(! version.equals(crDb.getVersion())){ - return false; + if(hashDb instanceof CentralRepoHashDb){ + CentralRepoHashDb crDb = (CentralRepoHashDb) hashDb; + if(this.referenceSetID != crDb.getReferenceSetID()){ + return false; + } + + if(! version.equals(crDb.getVersion())){ + return false; + } } return true; From 8a63c5aa154b947d400e84b6ccd8792b0b13141b Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Tue, 14 Nov 2017 15:04:30 -0500 Subject: [PATCH 103/115] Change HashDb interface to an abstract class. Rename SleuthkitHashSet and CentralRepoHashSet --- .../modules/hashdatabase/HashDbManager.java | 158 +++++++++--------- .../hashdatabase/HashLookupSettings.java | 30 ++-- .../hashdatabase/HashLookupSettingsPanel.java | 32 ++-- .../ImportCentralRepoDbProgressDialog.java | 10 +- .../modules/hashdatabase/ModalNoButtons.java | 16 +- .../configuration/SharedConfiguration.java | 28 ++-- 6 files changed, 132 insertions(+), 142 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java index e656606c52..4f68120f6a 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -233,9 +233,9 @@ public class HashDbManager implements PropertyChangeListener { return hashDb; } - private HashDatabase addHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDatabase.KnownFilesType knownFilesType) throws TskCoreException { + private SleuthkitHashSet addHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, SleuthkitHashSet.KnownFilesType knownFilesType) throws TskCoreException { // Wrap an object around the handle. - HashDatabase hashDb = new HashDatabase(handle, hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); + SleuthkitHashSet hashDb = new SleuthkitHashSet(handle, hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); // Get the indentity data before updating the collections since the // accessor methods may throw. @@ -268,7 +268,7 @@ public class HashDbManager implements PropertyChangeListener { return hashDb; } - CentralRepoHashDb addExistingCentralRepoHashSet(String hashSetName, String version, int referenceSetID, + CentralRepoHashSet addExistingCentralRepoHashSet(String hashSetName, String version, int referenceSetID, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType, boolean readOnly) throws TskCoreException{ @@ -276,7 +276,7 @@ public class HashDbManager implements PropertyChangeListener { throw new TskCoreException("Could not load central repository database " + hashSetName + " - central repository is not enabled"); } - CentralRepoHashDb db = new CentralRepoHashDb(hashSetName, version, referenceSetID, searchDuringIngest, + CentralRepoHashSet db = new CentralRepoHashSet(hashSetName, version, referenceSetID, searchDuringIngest, sendIngestMessages, knownFilesType, readOnly); if(! db.isValid()){ @@ -300,7 +300,7 @@ public class HashDbManager implements PropertyChangeListener { } - synchronized void indexHashDatabase(HashDatabase hashDb) { + synchronized void indexHashDatabase(SleuthkitHashSet hashDb) { hashDb.addPropertyChangeListener(this); HashDbIndexer creator = new HashDbIndexer(hashDb); creator.execute(); @@ -308,8 +308,8 @@ public class HashDbManager implements PropertyChangeListener { @Override public void propertyChange(PropertyChangeEvent event) { - if (event.getPropertyName().equals(HashDatabase.Event.INDEXING_DONE.name())) { - HashDatabase hashDb = (HashDatabase) event.getNewValue(); + if (event.getPropertyName().equals(SleuthkitHashSet.Event.INDEXING_DONE.name())) { + SleuthkitHashSet hashDb = (SleuthkitHashSet) event.getNewValue(); if (null != hashDb) { try { String indexPath = hashDb.getIndexPath(); @@ -352,9 +352,9 @@ public class HashDbManager implements PropertyChangeListener { // Now undertake the operations that could throw. - // Indexing is only relevanet for file type hashsets - if(hashDb instanceof HashDatabase){ - HashDatabase hashDatabase = (HashDatabase)hashDb; + // Indexing is only relevanet for sleuthkit hashsets + if(hashDb instanceof SleuthkitHashSet){ + SleuthkitHashSet hashDatabase = (SleuthkitHashSet)hashDb; try { if(hashDatabase.hasIndex()){ hashSetPaths.remove(hashDatabase.getIndexPath()); @@ -370,12 +370,12 @@ public class HashDbManager implements PropertyChangeListener { } catch (TskCoreException ex) { Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting database path of " + hashDatabase.getHashSetName() + " hash database when removing the database", ex); //NON-NLS } - } - try { - hashDb.close(); - } catch (TskCoreException ex) { - Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + hashDb.getHashSetName() + " hash database when removing the database", ex); //NON-NLS + try { + hashDatabase.close(); + } catch (TskCoreException ex) { + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + hashDb.getHashSetName() + " hash database when removing the database", ex); //NON-NLS + } } // Let any external listeners know that a set has been deleted @@ -426,7 +426,7 @@ public class HashDbManager implements PropertyChangeListener { */ public synchronized List getKnownFileHashSets() { List hashDbs = new ArrayList<>(); - this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == HashDatabase.KnownFilesType.KNOWN)).forEach((db) -> { + this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == SleuthkitHashSet.KnownFilesType.KNOWN)).forEach((db) -> { hashDbs.add(db); }); return hashDbs; @@ -439,7 +439,7 @@ public class HashDbManager implements PropertyChangeListener { */ public synchronized List getKnownBadFileHashSets() { List hashDbs = new ArrayList<>(); - this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == HashDatabase.KnownFilesType.KNOWN_BAD)).forEach((db) -> { + this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == SleuthkitHashSet.KnownFilesType.KNOWN_BAD)).forEach((db) -> { hashDbs.add(db); }); return hashDbs; @@ -478,7 +478,7 @@ public class HashDbManager implements PropertyChangeListener { // Defaults for fields not stored in the central repository: // searchDuringIngest: false // sendIngestMessages: true if the hash set is notable - boolean sendIngestMessages = globalSet.getKnownStatus().equals(HashDatabase.KnownFilesType.KNOWN_BAD); + boolean sendIngestMessages = globalSet.getKnownStatus().equals(SleuthkitHashSet.KnownFilesType.KNOWN_BAD); crHashSets.add(new HashDbInfo(globalSet.getSetName(), globalSet.getVersion(), globalSet.getGlobalSetID(), globalSet.getKnownStatus(), globalSet.isReadOnly(), false, sendIngestMessages)); } @@ -503,10 +503,12 @@ public class HashDbManager implements PropertyChangeListener { private void closeHashDatabases(List hashDatabases) { for (HashDb database : hashDatabases) { - try { - database.close(); - } catch (TskCoreException ex) { - Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + database.getHashSetName() + " hash database", ex); //NON-NLS + if(database instanceof SleuthkitHashSet){ + try { + ((SleuthkitHashSet)database).close(); + } catch (TskCoreException ex) { + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + database.getHashSetName() + " hash database", ex); //NON-NLS + } } } hashDatabases.clear(); @@ -663,7 +665,7 @@ public class HashDbManager implements PropertyChangeListener { return filePath; } - public static interface HashDb { + public static abstract class HashDb { /** * Indicates how files with hashes stored in a particular hash database @@ -692,23 +694,23 @@ public class HashDbManager implements PropertyChangeListener { INDEXING_DONE } - public String getHashSetName(); + public abstract String getHashSetName(); - public String getDisplayName(); + abstract String getDisplayName(); - public String getDatabasePath() throws TskCoreException; + public abstract String getDatabasePath() throws TskCoreException; - public HashDatabase.KnownFilesType getKnownFilesType(); + public abstract SleuthkitHashSet.KnownFilesType getKnownFilesType(); - public boolean getSearchDuringIngest(); + public abstract boolean getSearchDuringIngest(); - public boolean getDefaultSearchDuringIngest(); + abstract boolean getDefaultSearchDuringIngest(); - public void setSearchDuringIngest(boolean useForIngest); + abstract void setSearchDuringIngest(boolean useForIngest); - public boolean getSendIngestMessages(); + public abstract boolean getSendIngestMessages(); - public void setSendIngestMessages(boolean showInboxMessages); + abstract void setSendIngestMessages(boolean showInboxMessages); /** * Indicates whether the hash database accepts updates. @@ -717,7 +719,7 @@ public class HashDbManager implements PropertyChangeListener { * * @throws org.sleuthkit.datamodel.TskCoreException */ - public boolean isUpdateable() throws TskCoreException; + public abstract boolean isUpdateable() throws TskCoreException; /** * Adds hashes of content (if calculated) to the hash database. @@ -727,15 +729,15 @@ public class HashDbManager implements PropertyChangeListener { * * @throws TskCoreException */ - public void addHashes(Content content) throws TskCoreException; + public abstract void addHashes(Content content) throws TskCoreException; - public void addHashes(Content content, String comment) throws TskCoreException; + public abstract void addHashes(Content content, String comment) throws TskCoreException; - public void addHashes(List hashes) throws TskCoreException; + public abstract void addHashes(List hashes) throws TskCoreException; - public boolean lookupMD5Quick(Content content) throws TskCoreException; + public abstract boolean lookupMD5Quick(Content content) throws TskCoreException; - public HashHitInfo lookupMD5(Content content) throws TskCoreException; + public abstract HashHitInfo lookupMD5(Content content) throws TskCoreException; /** * Returns whether this database can be enabled. @@ -743,22 +745,20 @@ public class HashDbManager implements PropertyChangeListener { * @return true if is valid, false otherwise * @throws TskCoreException */ - public boolean isValid() throws TskCoreException; + abstract boolean isValid() throws TskCoreException; - public String getIndexPath() throws TskCoreException; + public abstract String getIndexPath() throws TskCoreException; - public boolean hasIndexOnly() throws TskCoreException; + public abstract boolean hasIndexOnly() throws TskCoreException; - public void firePropertyChange(String propertyName, Object oldValue, Object newValue); + public abstract void firePropertyChange(String propertyName, Object oldValue, Object newValue); - public void addPropertyChangeListener(PropertyChangeListener pcl); + public abstract void addPropertyChangeListener(PropertyChangeListener pcl); - public void removePropertyChangeListener(PropertyChangeListener pcl); - - public void close() throws TskCoreException; + public abstract void removePropertyChangeListener(PropertyChangeListener pcl); @Override - public String toString(); + public abstract String toString(); } @@ -766,18 +766,18 @@ public class HashDbManager implements PropertyChangeListener { * Instances of this class represent hash databases used to classify files * as known or know bad. */ - public static class HashDatabase implements HashDb{ + class SleuthkitHashSet extends HashDb{ private static final long serialVersionUID = 1L; private final int handle; private final String hashSetName; private boolean searchDuringIngest; private boolean sendIngestMessages; - private final HashDatabase.KnownFilesType knownFilesType; + private final SleuthkitHashSet.KnownFilesType knownFilesType; private boolean indexing; private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); - private HashDatabase(int handle, String hashSetName, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType) { + private SleuthkitHashSet(int handle, String hashSetName, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType) { this.handle = handle; this.hashSetName = hashSetName; this.searchDuringIngest = useForIngest; @@ -817,7 +817,7 @@ public class HashDbManager implements PropertyChangeListener { } @Override - public String getDisplayName(){ + String getDisplayName(){ return getHashSetName(); } @@ -846,13 +846,13 @@ public class HashDbManager implements PropertyChangeListener { } @Override - public boolean getDefaultSearchDuringIngest(){ + boolean getDefaultSearchDuringIngest(){ // File type hash sets are on by default return true; } @Override - public void setSearchDuringIngest(boolean useForIngest) { + void setSearchDuringIngest(boolean useForIngest) { this.searchDuringIngest = useForIngest; } @@ -862,7 +862,7 @@ public class HashDbManager implements PropertyChangeListener { } @Override - public void setSendIngestMessages(boolean showInboxMessages) { + void setSendIngestMessages(boolean showInboxMessages) { this.sendIngestMessages = showInboxMessages; } @@ -977,7 +977,7 @@ public class HashDbManager implements PropertyChangeListener { * @throws TskCoreException */ @Override - public boolean isValid() throws TskCoreException { + boolean isValid() throws TskCoreException { return hasIndex(); } @@ -1003,8 +1003,7 @@ public class HashDbManager implements PropertyChangeListener { this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue); } - @Override - public void close() throws TskCoreException { + private void close() throws TskCoreException { SleuthkitJNI.closeHashDatabase(handle); } @@ -1032,7 +1031,7 @@ public class HashDbManager implements PropertyChangeListener { if (getClass() != obj.getClass()) { return false; } - final HashDatabase other = (HashDatabase) obj; + final SleuthkitHashSet other = (SleuthkitHashSet) obj; if (!Objects.equals(this.hashSetName, other.hashSetName)) { return false; } @@ -1047,13 +1046,13 @@ public class HashDbManager implements PropertyChangeListener { * Instances of this class represent hash databases used to classify files * as known or know bad. */ - public static class CentralRepoHashDb implements HashDb{ + class CentralRepoHashSet extends HashDb{ private static final long serialVersionUID = 1L; private final String hashSetName; private boolean searchDuringIngest; private boolean sendIngestMessages; - private final HashDatabase.KnownFilesType knownFilesType; + private final SleuthkitHashSet.KnownFilesType knownFilesType; private final int referenceSetID; private final String version; private String orgName; @@ -1061,8 +1060,8 @@ public class HashDbManager implements PropertyChangeListener { private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); @Messages({"HashDbManager.CentralRepoHashDb.orgError=Error loading organization"}) - private CentralRepoHashDb(String hashSetName, String version, int referenceSetID, - boolean useForIngest, boolean sendHitMessages, HashDatabase.KnownFilesType knownFilesType, + private CentralRepoHashSet(String hashSetName, String version, int referenceSetID, + boolean useForIngest, boolean sendHitMessages, SleuthkitHashSet.KnownFilesType knownFilesType, boolean readOnly) throws TskCoreException{ this.hashSetName = hashSetName; @@ -1076,7 +1075,7 @@ public class HashDbManager implements PropertyChangeListener { try{ orgName = EamDb.getInstance().getReferenceSetOrganization(referenceSetID).getName(); } catch (EamDbException ex){ - Logger.getLogger(HashDatabase.class.getName()).log(Level.SEVERE, "Error looking up central repository organization", ex); //NON-NLS + Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error looking up central repository organization", ex); //NON-NLS orgName = Bundle.HashDbManager_CentralRepoHashDb_orgError(); } } @@ -1113,7 +1112,7 @@ public class HashDbManager implements PropertyChangeListener { } @Override - public String getDisplayName(){ + String getDisplayName(){ return getHashSetName() + " " + getVersion(); } @@ -1140,7 +1139,7 @@ public class HashDbManager implements PropertyChangeListener { } @Override - public HashDatabase.KnownFilesType getKnownFilesType() { + public SleuthkitHashSet.KnownFilesType getKnownFilesType() { return knownFilesType; } @@ -1150,13 +1149,13 @@ public class HashDbManager implements PropertyChangeListener { } @Override - public boolean getDefaultSearchDuringIngest(){ + boolean getDefaultSearchDuringIngest(){ // Central repo hash sets are off by default return false; } @Override - public void setSearchDuringIngest(boolean useForIngest) { + void setSearchDuringIngest(boolean useForIngest) { this.searchDuringIngest = useForIngest; } @@ -1166,7 +1165,7 @@ public class HashDbManager implements PropertyChangeListener { } @Override - public void setSendIngestMessages(boolean showInboxMessages) { + void setSendIngestMessages(boolean showInboxMessages) { this.sendIngestMessages = showInboxMessages; } @@ -1243,7 +1242,7 @@ public class HashDbManager implements PropertyChangeListener { try{ return EamDb.getInstance().isHashInReferenceSet(file.getMd5Hash(), this.referenceSetID); } catch (EamDbException ex){ - Logger.getLogger(HashDatabase.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup", ex); //NON-NLS + Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup", ex); //NON-NLS throw new TskCoreException("Error performing central reposiotry hash lookup", ex); } } @@ -1274,7 +1273,7 @@ public class HashDbManager implements PropertyChangeListener { result = new HashHitInfo(file.getMd5Hash(), "", ""); } } catch (EamDbException ex){ - Logger.getLogger(HashDatabase.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup", ex); //NON-NLS + Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup", ex); //NON-NLS throw new TskCoreException("Error performing central reposiotry hash lookup", ex); } } @@ -1288,14 +1287,14 @@ public class HashDbManager implements PropertyChangeListener { * @return true if is valid, false otherwise */ @Override - public boolean isValid() { + boolean isValid() { if(! EamDb.isEnabled()) { return false; } try{ return EamDb.getInstance().referenceSetIsValid(this.referenceSetID, this.hashSetName, this.version); } catch (EamDbException ex){ - Logger.getLogger(CentralRepoHashDb.class.getName()).log(Level.SEVERE, "Error validating hash database " + hashSetName, ex); //NON-NLS + Logger.getLogger(CentralRepoHashSet.class.getName()).log(Level.SEVERE, "Error validating hash database " + hashSetName, ex); //NON-NLS return false; } } @@ -1304,11 +1303,6 @@ public class HashDbManager implements PropertyChangeListener { public void firePropertyChange(String propertyName, Object oldValue, Object newValue){ this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue); } - - @Override - public void close() throws TskCoreException { - - } @Override public String toString(){ @@ -1334,7 +1328,7 @@ public class HashDbManager implements PropertyChangeListener { if (getClass() != obj.getClass()) { return false; } - final CentralRepoHashDb other = (CentralRepoHashDb) obj; + final CentralRepoHashSet other = (CentralRepoHashSet) obj; if (!Objects.equals(this.hashSetName, other.hashSetName)) { return false; } @@ -1354,9 +1348,9 @@ public class HashDbManager implements PropertyChangeListener { private class HashDbIndexer extends SwingWorker { private ProgressHandle progress = null; - private HashDatabase hashDb = null; + private SleuthkitHashSet hashDb = null; - HashDbIndexer(HashDatabase hashDb) { + HashDbIndexer(SleuthkitHashSet hashDb) { this.hashDb = hashDb; } @@ -1370,7 +1364,7 @@ public class HashDbManager implements PropertyChangeListener { try { SleuthkitJNI.createLookupIndexForHashDatabase(hashDb.getHandle()); } catch (TskCoreException ex) { - Logger.getLogger(HashDatabase.class.getName()).log(Level.SEVERE, "Error indexing hash database", ex); //NON-NLS + Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error indexing hash database", ex); //NON-NLS JOptionPane.showMessageDialog(null, NbBundle.getMessage(this.getClass(), "HashDbManager.dlgMsg.errorIndexingHashSet", @@ -1400,7 +1394,7 @@ public class HashDbManager implements PropertyChangeListener { } try { - hashDb.firePropertyChange(HashDatabase.Event.INDEXING_DONE.toString(), null, hashDb); + hashDb.firePropertyChange(SleuthkitHashSet.Event.INDEXING_DONE.toString(), null, hashDb); hashDb.firePropertyChange(HashDbManager.SetEvt.DB_INDEXED.toString(), null, hashDb.getHashSetName()); } catch (Exception e) { logger.log(Level.SEVERE, "HashDbManager listener threw exception", e); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java index fecc5ad192..8630b516c4 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java @@ -36,8 +36,8 @@ import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.XMLUtil; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.CentralRepoHashDb; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.CentralRepoHashSet; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.SleuthkitHashSet; import org.sleuthkit.datamodel.TskCoreException; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -202,7 +202,7 @@ final class HashLookupSettings implements Serializable { // Handle legacy known files types. if (knownFilesType.equals("NSRL")) { //NON-NLS - knownFilesType = HashDbManager.HashDatabase.KnownFilesType.KNOWN.toString(); + knownFilesType = HashDbManager.SleuthkitHashSet.KnownFilesType.KNOWN.toString(); updatedSchema = true; } @@ -236,7 +236,7 @@ final class HashLookupSettings implements Serializable { } else { throw new HashLookupSettingsException(String.format(elementErrorMessage, PATH_ELEMENT)); } - hashDbInfoList.add(new HashDbInfo(hashSetName, HashDbManager.HashDatabase.KnownFilesType.valueOf(knownFilesType), + hashDbInfoList.add(new HashDbInfo(hashSetName, HashDbManager.SleuthkitHashSet.KnownFilesType.valueOf(knownFilesType), searchDuringIngestFlag, sendIngestMessagesFlag, dbPath)); hashSetNames.add(hashSetName); } @@ -304,7 +304,7 @@ final class HashLookupSettings implements Serializable { private static final long serialVersionUID = 1L; private final String hashSetName; - private final HashDbManager.HashDatabase.KnownFilesType knownFilesType; + private final HashDbManager.SleuthkitHashSet.KnownFilesType knownFilesType; private boolean searchDuringIngest; private final boolean sendIngestMessages; private final String path; @@ -323,7 +323,7 @@ final class HashLookupSettings implements Serializable { * @param sendIngestMessages Whether or not ingest messages are sent * @param path The path to the db */ - HashDbInfo(String hashSetName, HashDbManager.HashDatabase.KnownFilesType knownFilesType, boolean searchDuringIngest, boolean sendIngestMessages, String path) { + HashDbInfo(String hashSetName, HashDbManager.SleuthkitHashSet.KnownFilesType knownFilesType, boolean searchDuringIngest, boolean sendIngestMessages, String path) { this.hashSetName = hashSetName; this.knownFilesType = knownFilesType; this.searchDuringIngest = searchDuringIngest; @@ -335,7 +335,7 @@ final class HashLookupSettings implements Serializable { this.dbType = DatabaseType.FILE; } - HashDbInfo(String hashSetName, String version, int referenceSetID, HashDbManager.HashDatabase.KnownFilesType knownFilesType, boolean readOnly, boolean searchDuringIngest, boolean sendIngestMessages){ + HashDbInfo(String hashSetName, String version, int referenceSetID, HashDbManager.SleuthkitHashSet.KnownFilesType knownFilesType, boolean readOnly, boolean searchDuringIngest, boolean sendIngestMessages){ this.hashSetName = hashSetName; this.version = version; this.referenceSetID = referenceSetID; @@ -348,8 +348,8 @@ final class HashLookupSettings implements Serializable { } HashDbInfo(HashDbManager.HashDb db) throws TskCoreException{ - if(db instanceof HashDbManager.HashDatabase){ - HashDbManager.HashDatabase fileTypeDb = (HashDbManager.HashDatabase)db; + if(db instanceof HashDbManager.SleuthkitHashSet){ + HashDbManager.SleuthkitHashSet fileTypeDb = (HashDbManager.SleuthkitHashSet)db; this.hashSetName = fileTypeDb.getHashSetName(); this.knownFilesType = fileTypeDb.getKnownFilesType(); this.searchDuringIngest = fileTypeDb.getSearchDuringIngest(); @@ -364,7 +364,7 @@ final class HashLookupSettings implements Serializable { this.path = fileTypeDb.getDatabasePath(); } } else { - HashDbManager.CentralRepoHashDb centralRepoDb = (HashDbManager.CentralRepoHashDb)db; + HashDbManager.CentralRepoHashSet centralRepoDb = (HashDbManager.CentralRepoHashSet)db; this.hashSetName = centralRepoDb.getHashSetName(); this.version = centralRepoDb.getVersion(); this.knownFilesType = centralRepoDb.getKnownFilesType(); @@ -407,7 +407,7 @@ final class HashLookupSettings implements Serializable { * * @return The known files type setting. */ - HashDbManager.HashDatabase.KnownFilesType getKnownFilesType() { + HashDbManager.SleuthkitHashSet.KnownFilesType getKnownFilesType() { return knownFilesType; } @@ -471,8 +471,8 @@ final class HashLookupSettings implements Serializable { return false; } - if((this.dbType == DatabaseType.CENTRAL_REPOSITORY) && (! (hashDb instanceof CentralRepoHashDb)) - || (this.dbType == DatabaseType.FILE) && (! (hashDb instanceof HashDatabase))){ + if((this.dbType == DatabaseType.CENTRAL_REPOSITORY) && (! (hashDb instanceof CentralRepoHashSet)) + || (this.dbType == DatabaseType.FILE) && (! (hashDb instanceof SleuthkitHashSet))){ return false; } @@ -480,8 +480,8 @@ final class HashLookupSettings implements Serializable { return false; } - if(hashDb instanceof CentralRepoHashDb){ - CentralRepoHashDb crDb = (CentralRepoHashDb) hashDb; + if(hashDb instanceof CentralRepoHashSet){ + CentralRepoHashSet crDb = (CentralRepoHashSet) hashDb; if(this.referenceSetID != crDb.getReferenceSetID()){ return false; } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java index f765fcbd4b..d4a77883d6 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java @@ -45,8 +45,8 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.CentralRepoHashDb; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.SleuthkitHashSet; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.CentralRepoHashSet; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.KnownFilesType; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; @@ -180,8 +180,8 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan addHashesToDatabaseButton.setEnabled(false); } - if(db instanceof HashDatabase){ - HashDatabase hashDb = (HashDatabase)db; + if(db instanceof SleuthkitHashSet){ + SleuthkitHashSet hashDb = (SleuthkitHashSet)db; // Disable the central repo fields hashDbVersionLabel.setText(Bundle.HashLookupSettingsPanel_notApplicable()); @@ -253,7 +253,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan indexButton.setEnabled(false); deleteDatabaseButton.setEnabled(false); - CentralRepoHashDb crDb = (CentralRepoHashDb)db; + CentralRepoHashSet crDb = (CentralRepoHashSet)db; hashDbVersionLabel.setText(crDb.getVersion()); hashDbOrgLabel.setText(crDb.getOrgName()); @@ -304,11 +304,11 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan "HashLookupSettingsPanel.saveFail.title=Save Fail"}) public void saveSettings() { //Checking for for any unindexed databases - List unindexed = new ArrayList<>(); + List unindexed = new ArrayList<>(); for (HashDb db : hashSetManager.getAllHashSets()) { - if(db instanceof HashDatabase){ + if(db instanceof SleuthkitHashSet){ try { - HashDatabase hashDatabase = (HashDatabase)db; + SleuthkitHashSet hashDatabase = (SleuthkitHashSet)db; if (!hashDatabase.hasIndex()) { unindexed.add(hashDatabase); } @@ -373,8 +373,8 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan } @Messages({"# {0} - hash lookup name", "HashLookupSettingsPanel.removeDatabaseFailure.message=Failed to remove hash lookup: {0}"}) - void removeThese(List toRemove) { - for (HashDatabase hashDb : toRemove) { + void removeThese(List toRemove) { + for (SleuthkitHashSet hashDb : toRemove) { try { hashSetManager.removeHashDatabaseNoSave(hashDb); } catch (HashDbManager.HashDbManagerException ex) { @@ -392,7 +392,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan * @param plural Whether or not there are multiple unindexed databases * @param unindexed The list of unindexed databases. Can be of size 1. */ - private void showInvalidIndex(boolean plural, List unindexed) { + private void showInvalidIndex(boolean plural, List unindexed) { String total = ""; String message; for (HashDb hdb : unindexed) { @@ -937,15 +937,15 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan private void indexButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_indexButtonActionPerformed final HashDb hashDatabase = ((HashSetTable) hashSetTable).getSelection(); assert hashDatabase != null; - assert hashDatabase instanceof HashDatabase; + assert hashDatabase instanceof SleuthkitHashSet; // Add a listener for the INDEXING_DONE event. This listener will update // the UI. - HashDatabase hashDb = (HashDatabase)hashDatabase; + SleuthkitHashSet hashDb = (SleuthkitHashSet)hashDatabase; hashDb.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(HashDatabase.Event.INDEXING_DONE.toString())) { + if (evt.getPropertyName().equals(SleuthkitHashSet.Event.INDEXING_DONE.toString())) { HashDb selectedHashDb = ((HashSetTable) hashSetTable).getSelection(); if (selectedHashDb != null && hashDb != null && hashDb.equals(selectedHashDb)) { updateComponents(); @@ -969,8 +969,8 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan private void importDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importDatabaseButtonActionPerformed HashDb hashDb = new HashDbImportDatabaseDialog().getHashDatabase(); if (null != hashDb) { - if(hashDb instanceof CentralRepoHashDb){ - int newReferenceSetID = ((CentralRepoHashDb)hashDb).getReferenceSetID(); + if(hashDb instanceof CentralRepoHashSet){ + int newReferenceSetID = ((CentralRepoHashSet)hashDb).getReferenceSetID(); newReferenceSetIDs.add(newReferenceSetID); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java index 6f14459eb6..1f44df404e 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java @@ -77,7 +77,7 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P } void importFile(String hashSetName, String version, int orgId, - boolean searchDuringIngest, boolean sendIngestMessages, HashDbManager.HashDatabase.KnownFilesType knownFilesType, + boolean searchDuringIngest, boolean sendIngestMessages, HashDbManager.SleuthkitHashSet.KnownFilesType knownFilesType, boolean readOnly, String importFileName){ setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); @@ -139,16 +139,16 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P private final int orgId; private final boolean searchDuringIngest; private final boolean sendIngestMessages; - private final HashDbManager.HashDatabase.KnownFilesType knownFilesType; + private final HashDbManager.SleuthkitHashSet.KnownFilesType knownFilesType; private final boolean readOnly; private final File importFile; private final long totalLines; private int referenceSetID = -1; - private HashDbManager.CentralRepoHashDb newHashDb = null; + private HashDbManager.CentralRepoHashSet newHashDb = null; private final AtomicLong numLines = new AtomicLong(); ImportIDXWorker(String hashSetName, String version, int orgId, - boolean searchDuringIngest, boolean sendIngestMessages, HashDbManager.HashDatabase.KnownFilesType knownFilesType, + boolean searchDuringIngest, boolean sendIngestMessages, HashDbManager.SleuthkitHashSet.KnownFilesType knownFilesType, boolean readOnly, File importFile){ this.hashSetName = hashSetName; @@ -194,7 +194,7 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P protected Void doInBackground() throws Exception { TskData.FileKnown knownStatus; - if (knownFilesType.equals(HashDbManager.HashDatabase.KnownFilesType.KNOWN)) { + if (knownFilesType.equals(HashDbManager.SleuthkitHashSet.KnownFilesType.KNOWN)) { knownStatus = TskData.FileKnown.KNOWN; } else { knownStatus = TskData.FileKnown.BAD; diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ModalNoButtons.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ModalNoButtons.java index 5795233479..41a9fe4fe8 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ModalNoButtons.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ModalNoButtons.java @@ -26,7 +26,7 @@ import java.util.List; import javax.swing.JOptionPane; import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.SleuthkitHashSet; /** * This class exists as a stop-gap measure to force users to have an indexed @@ -43,8 +43,8 @@ import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; */ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListener { - List unindexed; - HashDatabase toIndex; + List unindexed; + SleuthkitHashSet toIndex; HashLookupSettingsPanel hdbmp; int length = 0; int currentcount = 1; @@ -58,7 +58,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen * @param parent Swing parent frame. * @param unindexed the list of unindexed databases to index. */ - ModalNoButtons(HashLookupSettingsPanel hdbmp, java.awt.Frame parent, List unindexed) { + ModalNoButtons(HashLookupSettingsPanel hdbmp, java.awt.Frame parent, List unindexed) { super(parent, NbBundle.getMessage(ModalNoButtons.class, "ModalNoButtons.indexingDbsTitle"), true); this.unindexed = unindexed; this.toIndex = null; @@ -75,7 +75,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen * @param parent Swing parent frame. * @param unindexed The unindexed database to index. */ - ModalNoButtons(HashLookupSettingsPanel hdbmp, java.awt.Frame parent, HashDatabase unindexed) { + ModalNoButtons(HashLookupSettingsPanel hdbmp, java.awt.Frame parent, SleuthkitHashSet unindexed) { super(parent, NbBundle.getMessage(ModalNoButtons.class, "ModalNoButtons.indexingDbTitle"), true); this.unindexed = null; this.toIndex = unindexed; @@ -183,7 +183,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen "ModalNoButtons.dlgTitle.unfinishedIndexing"), JOptionPane.YES_NO_OPTION); if (res == JOptionPane.YES_OPTION) { - List remove = new ArrayList<>(); + List remove = new ArrayList<>(); if (this.toIndex == null) { remove = this.unindexed; } else { @@ -230,7 +230,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen private void indexThese() { length = this.unindexed.size(); this.INDEXING_PROGBAR.setIndeterminate(true); - for (HashDatabase db : this.unindexed) { + for (SleuthkitHashSet db : this.unindexed) { currentDb = db.getHashSetName(); this.CURRENTDB_LABEL.setText("(" + currentDb + ")"); this.CURRENTLYON_LABEL.setText( @@ -255,7 +255,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen * this dialog if all indexing is complete. */ public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(HashDatabase.Event.INDEXING_DONE.name())) { + if (evt.getPropertyName().equals(SleuthkitHashSet.Event.INDEXING_DONE.name())) { if (currentcount >= length) { this.INDEXING_PROGBAR.setValue(100); this.setModal(false); diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/SharedConfiguration.java b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/SharedConfiguration.java index e3f6a23bf5..1720b4b647 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/SharedConfiguration.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/SharedConfiguration.java @@ -47,7 +47,7 @@ import org.sleuthkit.autopsy.keywordsearch.KeywordListsManager; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.core.ServicesMonitor; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.autopsy.experimental.configuration.AutoIngestSettingsPanel.UpdateConfigSwingWorker; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CategoryNode; @@ -1017,17 +1017,15 @@ public class SharedConfiguration { // If a copy of the database is loaded, close it before deleting and copying. if (localDb.exists()) { List hashDbs = HashDbManager.getInstance().getAllHashSets(); - HashDbManager.HashDatabase matchingDb = null; + HashDbManager.HashDb matchingDb = null; for (HashDbManager.HashDb db : hashDbs) { - if(db instanceof HashDbManager.HashDatabase){ - try { - if (localDb.getAbsolutePath().equals(db.getDatabasePath()) || localDb.getAbsolutePath().equals(db.getIndexPath())) { - matchingDb = (HashDbManager.HashDatabase)db; - break; - } - } catch (TskCoreException ex) { - throw new SharedConfigurationException(String.format("Error getting hash database path info for %s", localDb.getParentFile().getAbsolutePath()), ex); + try { + if (localDb.getAbsolutePath().equals(db.getDatabasePath()) || localDb.getAbsolutePath().equals(db.getIndexPath())) { + matchingDb = db; + break; } + } catch (TskCoreException ex) { + throw new SharedConfigurationException(String.format("Error getting hash database path info for %s", localDb.getParentFile().getAbsolutePath()), ex); } } @@ -1125,12 +1123,10 @@ public class SharedConfiguration { HashDbManager hashDbManager = HashDbManager.getInstance(); hashDbManager.loadLastSavedConfiguration(); for (HashDbManager.HashDb hashDb : hashDbManager.getAllHashSets()) { - if(hashDb instanceof HashDatabase){ - if (hashDb.hasIndexOnly()) { - results.add(hashDb.getIndexPath()); - } else { - results.add(hashDb.getDatabasePath()); - } + if (hashDb.hasIndexOnly()) { + results.add(hashDb.getIndexPath()); + } else { + results.add(hashDb.getDatabasePath()); } } } catch (TskCoreException ex) { From 156970c9e51b64dcad976b64a52aceac67118f91 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Wed, 15 Nov 2017 09:08:29 -0500 Subject: [PATCH 104/115] Made reference set methods less hash-specific --- .../datamodel/AbstractSqlEamDb.java | 40 +++++++++++++------ .../centralrepository/datamodel/EamDb.java | 15 ++++++- .../datamodel/SqliteEamDb.java | 4 +- .../modules/hashdatabase/HashDbManager.java | 4 +- 4 files changed, 45 insertions(+), 18 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java index fad0196288..5fba1f1670 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java @@ -1251,13 +1251,13 @@ public abstract class AbstractSqlEamDb implements EamDb { } /** - * Remove a reference set and all hashes contained in it. + * Remove a reference set and all entries contained in it. * @param referenceSetID * @throws EamDbException */ @Override public void deleteReferenceSet(int referenceSetID) throws EamDbException{ - deleteReferenceSetFiles(referenceSetID); + deleteReferenceSetEntries(referenceSetID); deleteReferenceSetEntry(referenceSetID); } @@ -1285,16 +1285,18 @@ public abstract class AbstractSqlEamDb implements EamDb { } /** - * Remove all entries for this reference set from the reference_file table + * Remove all entries for this reference set from the reference tables + * (Currently only removes entries from the files table) * @param referenceSetID * @throws EamDbException */ - private void deleteReferenceSetFiles(int referenceSetID) throws EamDbException{ + private void deleteReferenceSetEntries(int referenceSetID) throws EamDbException{ Connection conn = connect(); PreparedStatement preparedStatement = null; String sql = "DELETE FROM %s WHERE reference_set_id=?"; + // When other reference types are added, this will need to loop over all the tables String fileTableName = EamDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID)); try { @@ -1312,29 +1314,43 @@ public abstract class AbstractSqlEamDb implements EamDb { /** * Check whether the given reference set exists in the central repository. * @param referenceSetID - * @param hashSetName + * @param setName * @param version * @return true if a matching entry exists in the central repository * @throws EamDbException */ @Override - public boolean referenceSetIsValid(int referenceSetID, String hashSetName, String version) throws EamDbException{ + public boolean referenceSetIsValid(int referenceSetID, String setName, String version) throws EamDbException{ EamGlobalSet refSet = this.getReferenceSetByID(referenceSetID); if(refSet == null){ return false; } - return(refSet.getSetName().equals(hashSetName) && refSet.getVersion().equals(version)); + return(refSet.getSetName().equals(setName) && refSet.getVersion().equals(version)); } - + /** - * Check if the given hash is in a specific reference set + * Check if the given file hash is in this reference set. + * Only searches the reference_files table. * @param hash * @param referenceSetID * @return true if the hash is found in the reference set + * @throws EamDbException */ @Override - public boolean isHashInReferenceSet(String hash, int referenceSetID) throws EamDbException{ + public boolean isFileHashInReferenceSet(String hash, int referenceSetID) throws EamDbException{ + return isValueInReferenceSet(hash, referenceSetID, CorrelationAttribute.FILES_TYPE_ID); + } + + /** + * Check if the given value is in a specific reference set + * @param value + * @param referenceSetID + * @param correlationTypeID + * @return true if the hash is found in the reference set + */ + @Override + public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws EamDbException{ Connection conn = connect(); @@ -1343,11 +1359,11 @@ public abstract class AbstractSqlEamDb implements EamDb { ResultSet resultSet = null; String sql = "SELECT count(*) FROM %s WHERE value=? AND reference_set_id=?"; - String fileTableName = EamDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID)); + String fileTableName = EamDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(correlationTypeID)); try { preparedStatement = conn.prepareStatement(String.format(sql, fileTableName)); - preparedStatement.setString(1, hash); + preparedStatement.setString(1, value); preparedStatement.setInt(2, referenceSetID); resultSet = preparedStatement.executeQuery(); resultSet.next(); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java index 4edeb5b734..1f1bd8a942 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java @@ -380,12 +380,23 @@ public interface EamDb { public boolean referenceSetExists(String hashSetName, String version) throws EamDbException; /** - * Check if the given hash is in a specific reference set + * Check if the given file hash is in this reference set. + * Only searches the reference_files table. * @param hash * @param referenceSetID * @return true if the hash is found in the reference set + * @throws EamDbException */ - public boolean isHashInReferenceSet(String hash, int referenceSetID) throws EamDbException; + public boolean isFileHashInReferenceSet(String hash, int referenceSetID) throws EamDbException; + + /** + * Check if the given value is in a specific reference set + * @param value + * @param referenceSetID + * @param correlationTypeID + * @return true if the hash is found in the reference set + */ + public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws EamDbException; /** * Is the artifact known as bad according to the reference entries? diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java index 45a0388561..4ee57db0b2 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java @@ -657,10 +657,10 @@ public class SqliteEamDb extends AbstractSqlEamDb { * @return true if the hash is found in the reference set */ @Override - public boolean isHashInReferenceSet(String hash, int referenceSetID) throws EamDbException{ + public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws EamDbException { try{ acquireSharedLock(); - return super.isHashInReferenceSet(hash, referenceSetID); + return super.isValueInReferenceSet(value, referenceSetID, correlationTypeID); } finally { releaseSharedLock(); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java index 4f68120f6a..27935cc3d9 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -1240,7 +1240,7 @@ public class HashDbManager implements PropertyChangeListener { AbstractFile file = (AbstractFile) content; if (null != file.getMd5Hash()) { try{ - return EamDb.getInstance().isHashInReferenceSet(file.getMd5Hash(), this.referenceSetID); + return EamDb.getInstance().isFileHashInReferenceSet(file.getMd5Hash(), this.referenceSetID); } catch (EamDbException ex){ Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup", ex); //NON-NLS throw new TskCoreException("Error performing central reposiotry hash lookup", ex); @@ -1268,7 +1268,7 @@ public class HashDbManager implements PropertyChangeListener { AbstractFile file = (AbstractFile) content; if (null != file.getMd5Hash()) { try{ - if(EamDb.getInstance().isHashInReferenceSet(file.getMd5Hash(), this.referenceSetID)){ + if(EamDb.getInstance().isFileHashInReferenceSet(file.getMd5Hash(), this.referenceSetID)){ // Make a bare-bones HashHitInfo for now result = new HashHitInfo(file.getMd5Hash(), "", ""); } From 143e530c327f32f51ecaab3779ecb8ac203ff050 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Wed, 15 Nov 2017 09:18:03 -0500 Subject: [PATCH 105/115] Missed a "hash" reference --- .../autopsy/centralrepository/datamodel/AbstractSqlEamDb.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java index 5fba1f1670..fa03d01321 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java @@ -1347,7 +1347,7 @@ public abstract class AbstractSqlEamDb implements EamDb { * @param value * @param referenceSetID * @param correlationTypeID - * @return true if the hash is found in the reference set + * @return true if the value is found in the reference set */ @Override public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws EamDbException{ From 16abf6bf4cfc01dfb7360dfd299d0d7900dcbb2b Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 15 Nov 2017 09:41:08 -0500 Subject: [PATCH 106/115] Update develpers folder contents --- developers/README.txt | 13 ++++++++----- .../netbeans_ide_java_editor_settings.zip | Bin 0 -> 42562 bytes .../Braces_DO_WHILE_LOOP.properties | 1 - .../Braces_FOR_LOOP.properties | 1 - .../Braces_IF.properties | 1 - .../Braces_WHILE_LOOP.properties | 1 - .../EmptyStatements_IF.properties | 1 - .../Imports_STAR.properties | 1 - .../Javac_DEPRECATED.properties | 1 - .../Javac_DIVISION_BY_ZERO.properties | 1 - .../Javac_EMPTY_STATEMENT_AFTER_IF.properties | 1 - .../Javac_FALLTHROUGH.properties | 1 - .../Javac_FINALLY.properties | 1 - .../Javac_OVERRIDES.properties | 1 - .../Javac_RAWTYPES.properties | 1 - .../Javac_SERIALIZATION.properties | 1 - .../Javac_UNCHECKED.properties | 1 - .../Javac_UNNECESSARY_CAST.properties | 1 - .../MAVEN_SEARCH_HINT.properties | 1 - ...verification.ConsistentAccessType.properties | 1 - ....verification.HasNoArgConstructor.properties | 1 - ...IdClassOverridesEqualsAndHashCode.properties | 1 - ...verification.IdDefinedInHierarchy.properties | 1 - ...rification.JPAAnnotsOnlyOnAccesor.properties | 1 - ...e.jpa.verification.JPQLValidation.properties | 1 - ...ion.LegalCombinationOfAnnotations.properties | 1 - ...ication.NoIdClassOnEntitySubclass.properties | 1 - ...ee.jpa.verification.NonFinalClass.properties | 1 - ...tyOrMappedSuperclassCanUseIdClass.properties | 1 - ...rification.PersistenceUnitPresent.properties | 1 - ...j2ee.jpa.verification.PublicClass.properties | 1 - ...rification.QueriesProperlyDefined.properties | 1 - ...pa.verification.SerializableClass.properties | 1 - ...ee.jpa.verification.TopLevelClass.properties | 1 - ...jpa.verification.UniqueEntityName.properties | 1 - ....jpa.verification.ValidAttributes.properties | 1 - ...erification.ValidPrimaryTableName.properties | 1 - ...java.hints.AssignResultToVariable.properties | 1 - ...s.assignmentToCatchBlockParameter.properties | 1 - ...ntIssues.assignmentToForLoopParam.properties | 1 - ...entIssues.assignmentToMethodParam.properties | 1 - ...mentIssues.incrementDecrementUsed.properties | 1 - ...AssignmentIssues.nestedAssignment.properties | 1 - ...tIssues.replaceAssignWithOpAssign.properties | 1 - ...lassStructure.classMayBeInterface.properties | 1 - ...a.hints.ClassStructure.finalClass.properties | 1 - ...Structure.finalMethodInFinalClass.properties | 1 - ...ClassStructure.finalPrivateMethod.properties | 1 - ...ts.ClassStructure.markerInterface.properties | 1 - ...ure.multipleTopLevelClassesInFile.properties | 1 - ...ructure.noopMethodInAbstractClass.properties | 1 - ...cture.protectedMemberInFinalClass.properties | 1 - ...publicConstructorInNonPublicClass.properties | 1 - ...nts.EmptyCancelForCancellableTask.properties | 1 - ....hints.ExportNonAccessibleElement.properties | 1 - ...ules.java.hints.IllegalInstanceOf.properties | 1 - ...dules.java.hints.IncompatibleMask.properties | 1 - ...odules.java.hints.OrganizeImports.properties | 1 - ...odules.java.hints.OrganizeMembers.properties | 1 - ....hints.PointlessBitwiseExpression.properties | 1 - ...odules.java.hints.ShiftOutOfRange.properties | 1 - ...s.modules.java.hints.StaticImport.properties | 1 - ....hints.SuspiciousNamesCombination.properties | 2 -- ...eans.modules.java.hints.SystemOut.properties | 1 - ...modules.java.hints.UtilityClass_1.properties | 1 - ...modules.java.hints.UtilityClass_2.properties | 1 - ...s.bugs.BroadCatchBlock.broadCatch.properties | 4 ---- ...loneable.cloneInNonCloneableClass.properties | 1 - ...ndCloneable.cloneableWithoutClone.properties | 1 - ...ion.ClassEncapsulation.packageCls.properties | 2 -- ...n.ClassEncapsulation.protectedCls.properties | 1 - ...tion.ClassEncapsulation.publicCls.properties | 2 -- ...n.FieldEncapsulation.packageField.properties | 1 - ...n.FieldEncapsulation.privateField.properties | 1 - ...FieldEncapsulation.protectedField.properties | 1 - ...on.FieldEncapsulation.publicField.properties | 1 - ...sulation.ParamEncapsulation.array.properties | 1 - ...ion.ParamEncapsulation.collection.properties | 1 - ...psulation.ParamEncapsulation.date.properties | 1 - ...ulation.ReturnEncapsulation.array.properties | 1 - ...on.ReturnEncapsulation.collection.properties | 1 - ...sulation.ReturnEncapsulation.date.properties | 1 - ...nts.finalize.FinalizeNotProtected.properties | 1 - ...les.java.hints.jdk.AddUnderscores.properties | 4 ---- ...mapreduce.ForLoopToFunctionalHint.properties | 1 - ...erf.InitialCapacity.stringBuilder.properties | 1 - ...ints.perf.Tiny.collectionsToArray.properties | 1 - ...va.hints.perf.Tiny.constantIntern.properties | 1 - ...rf.Tiny.getClassInsteadOfDotClass.properties | 1 - ....perf.Tiny.lengthOneStringIndexOf.properties | 1 - ...hints.perf.Tiny.stringEqualsEmpty.properties | 1 - ...ints.suggestions.ConstantNameHint.properties | 5 ----- ...tions.TooStrongCast.broadTypeCast.properties | 1 - ...nner.ui.hints.CreateTestClassHint.properties | 1 - 94 files changed, 8 insertions(+), 110 deletions(-) create mode 100755 developers/netbeans_ide_java_editor_settings.zip delete mode 100755 developers/netbeans_ide_java_hint_settings/Braces_DO_WHILE_LOOP.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/Braces_FOR_LOOP.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/Braces_IF.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/Braces_WHILE_LOOP.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/EmptyStatements_IF.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/Imports_STAR.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/Javac_DEPRECATED.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/Javac_DIVISION_BY_ZERO.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/Javac_EMPTY_STATEMENT_AFTER_IF.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/Javac_FALLTHROUGH.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/Javac_FINALLY.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/Javac_OVERRIDES.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/Javac_RAWTYPES.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/Javac_SERIALIZATION.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/Javac_UNCHECKED.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/Javac_UNNECESSARY_CAST.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/MAVEN_SEARCH_HINT.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.ConsistentAccessType.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.HasNoArgConstructor.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.IdClassOverridesEqualsAndHashCode.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.IdDefinedInHierarchy.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.JPAAnnotsOnlyOnAccesor.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.JPQLValidation.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.LegalCombinationOfAnnotations.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.NoIdClassOnEntitySubclass.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.NonFinalClass.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.OnlyEntityOrMappedSuperclassCanUseIdClass.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.PersistenceUnitPresent.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.PublicClass.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.QueriesProperlyDefined.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.SerializableClass.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.TopLevelClass.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.UniqueEntityName.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.ValidAttributes.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.ValidPrimaryTableName.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignResultToVariable.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.assignmentToCatchBlockParameter.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.assignmentToForLoopParam.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.assignmentToMethodParam.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.incrementDecrementUsed.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.nestedAssignment.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.replaceAssignWithOpAssign.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.classMayBeInterface.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.finalClass.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.finalMethodInFinalClass.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.finalPrivateMethod.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.markerInterface.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.multipleTopLevelClassesInFile.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.noopMethodInAbstractClass.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.protectedMemberInFinalClass.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.publicConstructorInNonPublicClass.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.EmptyCancelForCancellableTask.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ExportNonAccessibleElement.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.IllegalInstanceOf.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.IncompatibleMask.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.OrganizeImports.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.OrganizeMembers.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.PointlessBitwiseExpression.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ShiftOutOfRange.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.StaticImport.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.SuspiciousNamesCombination.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.SystemOut.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.UtilityClass_1.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.UtilityClass_2.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.bugs.BroadCatchBlock.broadCatch.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.bugs.CloneAndCloneable.cloneInNonCloneableClass.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.bugs.CloneAndCloneable.cloneableWithoutClone.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ClassEncapsulation.packageCls.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ClassEncapsulation.protectedCls.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ClassEncapsulation.publicCls.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.FieldEncapsulation.packageField.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.FieldEncapsulation.privateField.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.FieldEncapsulation.protectedField.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.FieldEncapsulation.publicField.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ParamEncapsulation.array.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ParamEncapsulation.collection.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ParamEncapsulation.date.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ReturnEncapsulation.array.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ReturnEncapsulation.collection.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ReturnEncapsulation.date.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.finalize.FinalizeNotProtected.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.jdk.AddUnderscores.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.jdk.mapreduce.ForLoopToFunctionalHint.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.InitialCapacity.stringBuilder.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.Tiny.collectionsToArray.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.Tiny.constantIntern.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.Tiny.getClassInsteadOfDotClass.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.Tiny.lengthOneStringIndexOf.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.Tiny.stringEqualsEmpty.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.suggestions.ConstantNameHint.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.suggestions.TooStrongCast.broadTypeCast.properties delete mode 100755 developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.testrunner.ui.hints.CreateTestClassHint.properties diff --git a/developers/README.txt b/developers/README.txt index ce28add84d..61fcac0963 100755 --- a/developers/README.txt +++ b/developers/README.txt @@ -1,3 +1,6 @@ +CURRENTLY NOT WORKING for NETBEANS IDE 8.2, +NETBEANS BUG REPORT: https://netbeans.org/bugzilla/show_bug.cgi?id=271811 + Common NetBeans IDE settings for the Autopsy project are stored here. All contributors are kindly asked to use these settings. @@ -7,11 +10,11 @@ Select Options to Import dialog. Push the Browse... button to pop up a file chooser. Select ~\autopsy\developers\netbeans_ide_formatting_settings.zip. NetBeans IDE will require a restart for the settings to take effect. Formatting can be done by selecting Source, Format (Alt + Shift + F). -2. To make Java code hygiene hints (lint) settings, copy the entire contents of -~\autopsy\developers\netbeans_ide_java_hint_settings to the hint/default -subdirectory of your user settings directory for the IDE. For Windows, this is -~\AppData\Roaming\NetBeans\8.2\config\Preferences\org\netbeans\modules\java\hints -\default. Restart the IDE. +2. To make Java code hygiene hints (lint) settings, select Tools, +Options, Editor tab, Hints tab. Push the Import... button to pop up the +Select Options to Import dialog. Push the Browse... button to pop up a file +chooser. Select ~\autopsy\developers\netbeans_ide_editor_settings.zip. +NetBeans IDE will require a restart for the settings to take effect diff --git a/developers/netbeans_ide_java_editor_settings.zip b/developers/netbeans_ide_java_editor_settings.zip new file mode 100755 index 0000000000000000000000000000000000000000..102d366250252dd4948d7ab4187e2436c412266d GIT binary patch literal 42562 zcmcGWV|?CQyR91=jT$>?Y}>Zc*tXR)b{gBZ&8D$!yGfeHjn9*Gt@UE>(|7ItJ13v= zeO&)>k2&u#A2~@7P?R^2kdSYr#cU+s{L>!-;C}-fYhyDLS{iG8Jx51-hx}N1*)Mb` z0qfEa2=%9BKa5ABAwk~0O{7DT7L#h!%FUBjw1HyHZ6L@uiYs@|CzkhV#83-|BgXj`Hw zonZ5Z<95IMoS%v=$EabRF@FT61fC{RQ z@Q;B}#?p5L2M1ed$xAdp-L4gcl?AWOgr4ck7&1v7_ElM!R={Ev@?}e$keD*M9v4%+ zNAdxE%#Au~;FObufc#8V6)Xz$=8ZDwn>TX*R}HBDp@FcWnWK%p11-O`wT+{mqnVAh zlAEoO1Fe9)k)DOEjhVG0jjNTVm3+7PHXUL+?Iqq!bH4<9K*NmYH&UZv8Z$DQ;f!$0 z2&1>c3^CZO_g9?uDaLv?_|ccfYi+Ej-=Dlp7I3{L#`dZP_PQomWXwzLT`4n-=WU;_ zwuV=C&v&aI>eZ`V4?bJ1h2o7z!5XJk(xZ`CZg{HGBv;J|zYRH76Z222oa@R8tM1(O z#O@!_FH@AKeDIong^bx(I(G7W*D|l9+Bs&J|^O%?t}KQis>+SfVhln>n(} z{Iu_54oi|Cr4*m;C}PgCGQVV5KqaP0+PL1+TEl#K8!#z7llDzW`O+3akj?l}4TZKU z!a6IhBUr&m_NjeUeZTGphvC>Cu`nGD_H^iMlL!*o`%1gu>l5!JaMJfpCe>|Ft7J;Y zCPHGv_e9p}y6R3Qj@0VMa?h=+&WV}td@Uz*^)79o3re7*z{UIAlJOX7V#ALWMO37& zy2=(d*C|2gJWfo>lC?+3?>>5P@vNd1fI84EDI6hI-8~aVeM5ROJJK;l@hB4myAyKx z!VA1~lvUVO;4YK>4D=$oXu{N3545}_W@7GVidp`g4W;*ug zF*R{eGjz~3r7WzovUgqfNu}OA+q@{er!76Xc$&8!-D(zW@SyZ=<6=y*>*!X?s`I^= z_3q89rx_A6R>a4!?^t`|$I|yb@az30= zwg}|sUOWU+LSB4iIkE&Po0YaWh=7t%zNGRsTh5u6pBXdQ*0PyJ<+{sA$+??4Sg*s7 zk4ai0Nm*v1Wm=3Uz0Vp9rN>Q*7k%&ud`G66J|Ag5O^oJn2L_yB%h3W7o;uQPDhcn! zclLZJ6D|IH@Lk6&`aKG$AJ3xJ)$p7Q$AMj#0axMfFXg*|1czRf&-{O=yo2M5^uLtX z0w|9XcnWck@U1y2{sXK)vFbNcgM1>Wa*t|C0?q!0U_uP>$kfL>oZVcEGIYQE8&9tN zwvJYxb&Lj4yt-QUks5Nkx_ZT>2KKgiUQ&mq=clXT)lvONwWl>Ib*{?+7MtG6LQ!z! zF;#S!I2PLuvUgG%M>*k2$0%Z8>^c=6`QI7%4BxUvCikl4$Bo=3lokPZ7Dy{B8Il%Y zKt*%l9Sv}V5Cnb6UAdN7{%P9+tm4KB9v9z@jcEo9TpEP9Dg#1KM zaR)A?SJeJp5vaOX5S}+vC7(CTf{XKq|lx19Y_3%=nTJ-pP$O`zk)MY^J2 zcUST7M8g5QaC7&(V}OL{{w=Di|G_F+?OH<@$EtJST2hvh^f-1>1CBe6@HSV&8k~w& zS1z6@**DsVC&97c(63B1lOG!03I=JI79pfnu(y5Hn|pj*TmyjtpM4Rll|Dx6}c@W8PEE6D27A4=||cK`>0R46NUEg9*>u_A-o*V(8mWKI$u8fcI61s z)c+_x<$wO{1@$Z~70n!9HP`wqE89Z{+j}bJ8MNV%dIFk4hJ5dr!~{p&0#Zn3)y_gF zSwd`uk%?K;G>|-B^2NK8C;P>8BSs@ik4c`#ifo*&aRGg>&I%r&D%rH@=DFgY8w7s)v!w4X`mgS+ z;%R+n?CYYa*o{d&~(D&uBHg+=(9Mh~XT2jqF7dZg56#wmqO#e5uw6Qk)x5*tN zZL>@V8+ZzGjil+b(H@xtKWCNzVFrl6278HR(tyUT`(q&O4zI^^&&IX#(Di$`uzmQ&Cu)z?3iJ`S zae8Ais|`=BvgEosVGQ!c-p@$(9fQ97SOzy=Z|Pt|detHcLVnpdOlpK)Z9vj{;x09} zA)-=wSaL($-E4=YzTIBXvP)}7GD$!3nJG|El`DdlTu2Q)^7f)MJDz}B4=vuAZ@5Wc zfDev@32w*;{LPYL*!LEde>MTZ!8N_oQRx-SD86fZYhN7!X9Px*<${b103i$D#Xvj#`u z`p^Yig1s)3kR&77r^Bc3ChAWRg2Y+C0~?$HAOy{yWKN>s;(0$cJ=c@%FE@_H^g4uD zUTAPt?!k(@MmPWn)mn6B4nJEpYj+*oW1VdZw^^t`2#QeyMfo(x151FV3LU~Jac z^QX~FquG@HplugtBd{(vryf1Z6)9+HU4aXs8b8vr8S!m?AN$c;topYCPRVFsggd;m}xaI?9`!_@5mgfsWdp z<1#TBQ>UUJUAr!3Pd1nqu)`Y+*+5aAZLTqx4l_}`<3-%~`1uYLo5G&xzxu)7G0nts z7k2(Yc;VmzBP${Yz(K`tIrtmtUeL+j-pJZf*wxnF$iV?{&U?vtT5_6_J#;AE?;a4& z+A0^4$O( z8}41iVgs!sN~=-McUcm+q@rWDSa%yoWBLQ;RILU4Ly&%_MO!)-KnPzBL2A)(-nOWv zX^7-`^Vb=2c{r$jXWw|si#Nt;oG6VMdh!K12vw-JiY4xLsl$9k}-@VYbVr@kdGN}~I^ect*ySi$Zs%V5f z-$|X+kA_n*m?sc7zWr?e^rcTo)?UXj-HiXT;D|aisptHY&N3RWA6Wr%XGm_JQIqA!M-y5=@I z_JHg4{&zP!pz)vQwmiOO_UsGEY~V^)=sCQ_x(m|N)CWgw$eZQ8KB;08dE-TFZxu>z zGOsN^C95)Ckl38izQ~-Cgn8==kXh}wGIRcosr}!{tRo=z@{Oh|NQeDW8gTcLptd+X zMPv6arilr0s*1RZ8)`9wO&>Ml^N#1`yvvSdjFlNJGrG?~JFCs!=)qZ2t$q{_x;^`f zks#s$MM;E(y;@}lJWuy_;?1cDUcvhNQoLb-uZm&%&A8(x$Uq?E@6h{;w4&`>QlL+; zg>lr6VGa4o!@wXH`WAS^+}N-gf~uwB!aa$O)F9k);gGCs3j;Cm_)1oe;xgc0zt)If zU#rcMkOHmi(B`sbwL&t#EdqBw_@2{WA84LwdCmTtf;^I|3Ia7c{@J z>f;pfc0&}Wjx8OvR59&H?r(_+;bC}*v1Lwh!R2NR38zUtKY}w^vDzT?R?yl*%ms0= zWYbHPg%dpCCtWO)Ei5d&&n=Y)gNiYn?Nj?pV~@9pTR8^%xN-fbIgO<`PA7Y}78nSH zSy|!lRWxmaseiDs4FaxPeAw)zWO7HkQ!dxQl$75Qo+#0Mkh>3?pT8yTsvlmz7ZZhO z7ws*Wc;C+3YQ)4e}X?gg8efYHGCh1_J9=@r3H3JGQYe% zp{abNxl~gGzi1uW3vBp#=HV#mnVL7ohC`~9G8VS;0r-Uq7gAiul1;rie5 zBlsske_2II1&PXaO`YUQ02>XQKNA&{rK~{1`$#o)17dcWyDOaDBSXz4Nw~h4tF=_t z3nmXP=0Kcow+NP9m%%v3DiW2YIr4R@P8puFe%jOZQ68!elV!Zrv;YSf%i7e+1dMHD zf;q&!tg?6dfb3^P4UQ^i`6ea{@iv9g8#3DqG3WIDs{k1x3BPI>g_8D)X{=c4%AlD5 z1eZ$30SdeaLJ3{;c{>9xTWMFKOyg%_osG0}o8c=Jgk&1+)55^a8CiU!% zL2=7pd|B0ag4NvW2r$byK(v+Q9G&1~5TQ9$r)Y~D`Q9_s)n!Qxjo=g|qSeFUv8qok zrPTUWAOx;OpC3Z;oZi@uCpSRYatv^D6yZ2G#E@V*k|R_Q-5UyGJjU)(!El5}d@f$L z)Rrd6E#5JwNY?q0rap^Ed6Wi%b*?BGjJ_?QiN0i=E^^LSo2|x;t+$|7_chW%x_Q!W z)h*g+AB1JfqNHfW^xA3Rt*zC?jmVaKWhDL}YE#h-#7$9q2dGQ8VqSQLdWdxPiLLU) zTgKfR#TpDU1-1Z!ske`TKvJlNjE<-mEnvME4T7#j{127i*Nq=-Zj)W7 zjoO9@hbFe(y@13Kf)KI}0LkV54@g3Pg0%cHbG%+|f!(O9YiK1~ziNqXy$&6|d%)1y z3RWg&jBz-ecR{g!m8bx+NbTTA((LszJr>O$vKKT0USt64v(cv_a7vHA2~e2bTK5EFimqx=A4 zfy_Nv3{~vRO*%7P&PvmvBU3ZSjNeeOsL^2n-$UfRV)+Bt-%gVldA1LkWrtI>bVyT{ zUFh2ar^m$H!v;ZV41%KS@c~QHJJH2nd1t4%h;dg$nbRcZ!{CWmJ2GMe*inWiLk9N` zUAF0u9>=_CE+aC6qkq~_&U&$KQ%*tHVxsu_uKH0OEb&)6s)&wRvsr0}+Dlu)7L6Vgl# zX(7YkQWm?qrccbC=kACz^kQ~O+ng>T-_2$%wQ%qvo7oa#%%YCmN31W+x4deuLHySJ z%IPwM*T?PI`kdf7quiSc1}ze&YS*13(RjL!u)gSkml14 z7PjJ(RfF1~<>R@+M5C+L5CEeAu2dR!i;?Q(f|UgLw(f7@U+3Q8 zotz<}9`zvNHC@6Tyj7ehSL9z5xdVm|l9d(`mf#b?aR?Nj*hrIozXS-Pe`!}*C-_)A zl}nk=u(!1391E^`)4htc4cki43nTaN{#hsJ$>uJk$pOozF_@|D=j)}0sBHkoE`XJf4$LaM_BNgaE;pi5SUY>i7yj~N>-C42G0#u)4T8mWiV@}X|WP7 zp2^Dh1YhlZ`ySuz=7+oORxpay57dz`B+xq+^rKd2=ViQFEZ3&zyWQ{0=c?^qi)BI_ zaAYj4z0(HNx}>|9)4=sn3N($9+3g78@6lROYO>-=nIR7pF|G5{3W|RurAUzjJ53QI z??PB5nAJ8@z<}d(W;$U)D+;Z$mFZS$2_c@KE3y@t!m*?%VSUJg9-8mla4F|U52s!v z2rF54E!o)Lb}#+5dT|ljnTjd2FC(bqYXg}Jb5cIyRdiSa#p5jxZ}b0vEdk2jI-dxMuZF~w>VU`)KdeYtLL}c=SC0h z)jrwcc=C4ec~maF>naX)lNqW`6^U)VulLUSm;>w{08veUn|c4nhVhRBshl9gual^x zEHFJ{N9s?!Z!3$RAPmAOpi|cY zKDp0}?_=Ei72#zsdL>Yg=I1ed5__3nGpg)}o-36_+a%^cW`gD)Gr?Sa{!T*kq8qFz zCTQ@pLx$j~=c)#5vNL^YwPh+eIT36}eyESEJ3M5e%LtVQp<}gd?fdP;q*(hwAcUV+ zwrliUR>^+Mhil+U%2+Q`VL@P8_RHxk@`g)e=izkGG=vg12>IdTHm($%R|L1VeNX0# zqdQ1D0x1B*0{yL6%>RQgkm2P3DyL`vx)#=o9+l~#L-aotYx7(5*iHZu2>v)z7c5bv zRK#stlV&JR{ee@1Q+jy1R_69Cb`II%t+C1e^-~q#RDu%j!Y)-q59t_R2{@H3l;MfY z+xob8JA2T3(9BhqHV5~k^_nw!X`ld$DA3T$$hYF}T5=;VvEw-z*2YG|<)_i|cd_(c ziwpto69I=3v0t)1^ol@XNzbrt1LckS$%=O%yvWvOhJ`2;kxe*FD%QSDAJpG#UmiL- zJe;;(x@DhF{%Ik_*y0v&iGW}fp{n6WXB}pk<9^`}cRMy)az3XB|C!^up<`;!(-x{^ zM{j9J-Nz50ocb^20B4pL<#GYaL4X6!8Khy6kXk!JvVEK6%94E!Z)8RTAXc^yd))ff zTG$|lx114OfRtwg4qPbEwF?h9PgGIGe>m)~OHLKddnjQ;k-I$^+>j<^&+*eXpS@0G zPJ3?}Er5O~ztxZKf1=+%PL(fvfj?X{{ySZna2xO~x{B_=CqnjP;sKUzNM#|vn2Ty1 zUJA1q>n<8bT{VW=pKC69@P z5F1;>rDs?d@O!{rjMc>6FkBSN^wve0Qbv)Kl}ACAbgR`KF$}bARQub=UgRg2Wn`M1 zYf15>oB=BxMXeV2%h8L-Uiposy#sQWls={Z2431>^|{_qe!TwSOCO0ow{aaUPIGi9 zOUl$mzvgw)Kwvdo+2$h4&T{`m$3u1Ix2pFur zT;t`{^qR%UD-=S{pg<@V%JJWGGX^@+FH{q4qCGRT1aorf0E6-Gti^9=@!Y(XUhNms zL{6_#>j?I=GL>msx}WBQKRJPqAmbmqdiwJHgJa=l+PRUXM25Wd@=(A92O><3zpUWr zWJ60=vHfbTnst1+MG7RB0y0=;W|}&ZvIHH7#viuN zXFUhge?l_x3JKo({{jirBDp+dea0w%H%I<=nWI%}RZuDAK$NfL)(Xg1s4N3j-4PgQ zNFU2QcZ!po-&*Zf`TJprngDSx?E>-Bja zQs8|-!aZ6XjD=z12qS%il$WWLbVif^*LGJlkhxZ!sSk?cbgD$o6>x6#ifZ!gniMn% zp=WOaphWxvrMS*Ol#nJpnm}Y_>ySteQS7@u)Y`5C-sFszR2}_fNce8;@ci7KzoeIs zO0*znt1yvDG~>F?LV4JCwgQ6=Sh+#w5;MhSTMbx!{)8V!WGu0;h&P8!T@Ke+pcILTQ0*zOv_BRSvLL3NWC6C_@t5K@t z%)`tAmPGUCTI(m)g7T1ATi-NiE2L7tCbRgI0&#aK>4E{ibcR8pD{)Q3rL6*O2^v0? zjC&@Og5VZAwJ!eFV0_rVgyU%OE6NO*pI1$*v%62XZapr_Dk(_8W9dO1Z`Kh--Ysdy zGgpGo&;w$a5_oF$Q8Y^K7cpv|>}vAp5{bn{kl;1v_U%|`wGL+RP7Am%cesNEcZiUj z(7CKmfV2mU6k+)ptiIOAHNmN;*D_<5_o8!H@+7uRBN`8F$9(VOkGp{pdt!milJi0L zHh-)E@VWitwua#MZCsu|Mur?HyXak$x(&Xz;21#nb7-hcJ2Kz%Ou+sOzO{+|ka7uS z;p`vh@zl?~Xu7{U;@azR5A)&$Ar>xY9{~z${B~mejfpR0=Afr zX{tw|VHVoFMp~Zb%anliH zX2$@F1DZ8CjgYJrgjBrGiRzItq@%(QR|Uk`5x^Rl#}NYOt)`;o}GRHbL>JU!*3`T1f1LK<>9y5y{wn zA@8sYwXcNOn+g2ztO#`EcQ%vOz%Lrv)Y}tv5ozf*3|uz2E-17JOMe>?9;i`lo5NMX z3e&NF@9`-Oa~6$cQ+MF%>C9T1>0a^VDvjphb=SbqLy8gwP~88wivNvE#Q&~x%ZxO9!-n9Iwuu$M)$VKF|*B<|zod3B_vA_JfS z7`NPQhV`xxv8u0?Jj)Vx?+1-EpDwiE(N#34epnDTZepoM-0-~c*@yTX*J3o;RHxAP zIohK_Xf+dfz#hVi3w(PCD`R0S%X5Fml+HF_biwI>y?Et76FPfp(oOqYG~`Tx>}vt2 z+quhq^(wFtta!i6ww-PhNm#u#B+*QJtM>T*+0{G$s-mG>#FlBMfq z-?Z-u*f;50#*jF4Y*UnURW_*Cj9T|{<$~so6>`)_55BYjJK$uNo7jRrGOtMk85z(8 zsRFuSis%}ZLBxnQt|OZs^~J*Kj~XaP%H#>l((1Fb&b4Y`Tl?l`295b#Rb$veJP^yS zuzmG6TtM2Uw`;|dx*N~{>z{B?Xr63Dd1?Q(%@F7n<=3KQ?M;1ftNnw5H2?)#^_MF^ z(+#4PxvoyQoTnnCLPy~j>_WU#Y+nf@o}^jd!jVj82|2HBL#R6w4D$@uY~?{1?`C}P z0nr}(2&c^noFzQ@2!i|L!62Q)f`boUr110?2il<0CwZOG-j+O2JSGn=p>ZiYKwt#f zvR6+RxQ-Krlo^+4k2r~Vro7u8+!4mT}TDqMHN zqr@#cdK0=$&yZ?9Gm!n=f?wqU{r3c@J8c@kel&eg2^V(QfHsLt!XMqh1=2y5X0+*W zq}OgBDalKlr1|8fO#%&6+KvS>w4@7f189>J&;c61;`j}&1Do^u&2M+N+*G&#Wx$M* z#UA%~{qfYoSwXNe=Ae$@?m1jPyHRRcOB1;c2Xi{~rZ4WMnwM!x)<56^UMfViPGX?u z->JZgDw*CXz0Gma9C2R;K5|^fa5sRTcA1@U0FhdTZ;#v>b+c^8Dnp6@bWjl=`9R*r zFx|0Q3D3kyri2!DWtoE7dNC zD-S0qR^CpZ)~9NZmU8VO&IB1;_1iYDrcR?Oq^-BpX!#KW$0ay`$v})8FdBeD_H~tr z?m+QeRUmwOfVzNGvk4|$PF(m*Pt$1GT(OcJDq1JQ-Y~USjgQ=kPZ_*%9$d1}>W*2m zD`lfExQ1S>OFJdFYl(o=r6^ZrVL+~NtVyoxuDrP`%nL?J&(iOjJ+u1!YAnrD=c5&{$o3ND=gCB#uieGnx+vb)pqpL|!t|!unxBvZ1zJhsj5&MlZ8&w? zzq<>*_X3}8=+9DYcL8eM053)Ri2`mOj-EGp8mGicyq6GiU{GU1*nxP)_!f_8T?SlN z1$W?@1cMH*j_3{Mps}gc@|M9Wl*Pj``eW`xWFJX!lUfU89t>-9*HvB2)80e^ZKvDNT-)$$$IFP*ZJRO{PT;B5N3j6f8*&Mo$!k`fqbazS49 ze7s3-E@&Z>u|M;HMKVR1*UseOq;7Q2)|owe4E4Zg;(AzexFBZ>vT@f)>Y8q6eD`ne zJ(S+W#LKybYIte=W37|l>V+?fSPdbK4iH3V;lheJiQ1!neu^s>TLdG=B3~W{M^wRC zyk^G??v6D8#vQXBt|Z!kO4PZ5z96ZMr|J&}IvR)Q$Rd5z>3_}_Pp>itT;^KO(!O)c z;k)P^yC>-k>wJ+OT`N*N4j}#Si(`MI7i?wbYGnAwZBc!!)vs3o2-i4u9(a^`uuDjl zOm=-=mPjqhEi3);#v+5MFvQ0Mc^_q*aiMX%>M?;Mzkm1PU47>2Se*~Gn&dEZgv~XD zgmtopE-ppSP+138wY|UE4mv9|q}O^>A4}q88c2|hy}ym?{&*pJi7ZvW&81F4HM{h4 zCRQy|>{Hq}u5b6!{a)b3s`WdwOLel4@N(Bpn0{I#KRFik5IrFv$aKzhCItR>Jzw=( z%))1$DtLht)N37*jG+z46n7ET);Mg;Hw}H&&4sPws_9{GjNFvbbUvaU*i)wBKuinuH`hqycJdGzS~+sw8kyoM1U>58?)GT={s;E|yTr1^SC6HI+@-jgsf~ z9Q^|>`_6+@+}!jcF|~j+ht10m_Brz&TAFBl#oI+F+sPt&hf-ADy|=W{Y(a98jrSzg z5fbUPRo8DGIUhhuSIc3PWI8=>haUvn{I@qI)|K3V}| z1Vu1vQgt3`&pzMDpzO+h;{!@*@0K^SPR5LmV;1UgT6MBmJO`21Tn*lr(n%73TTl-B zi)SKkFVPcXwI`XWY1X>_hk)eG;XQso?Wfnef@qV#5-`9~0)G3rh~Yn{i$Br&r+R96 ztYp*@;GGFzjNq&^Bm0#|mKg3tS zz#)@4)5{=5-U;f{FEfjnKil#ECulm@ChbBSEEoQ zR`38^CZwvi2ntl)qX@hHZdi$n)_c^1@V44LjrNem$Mr+y!NdD1iS!gJSdPYnIP&kV z_@~1g_2ilXk%~19B@_1N4CT}ZkdlWHyW{2O=YcekZb2O8j$oFQrR6!D2p^63=h2g9 zH0!3qBC6HYr@z(Eepya{CJvSwDv==FzS{yz_kWVUT(z==JaXCjT?kH99Bg)xcmm=c~a1 zl%4(dj*8}QQ08RmXa+E_Ki1CmivPSfjE6;^KsyWN7_8DYv#=c0d*6*0P9&57D?Zlm z{Yb`X4ei)!1rEDFxV}w<$K1|48;UdWVqvkSu&_>g5&#QhIik(QYI=TnTD|OfaBFx< zrb*&u9hj1?(HKJyXY&!r)Gff-zqm>>(!k1eBRoP5iN5GXrdx1ZU$OJ%!X=8}L5Ln$ z2u~XLX&Mz)aTrPOF4|T&K_>kY-m~G(9$L~G?-a_DQ_Z>g|IPLg+ z&_`svj?Rh3sZ+In=8NOp+fQ`>w3_sPqAPjWqsn%;ICXVyWhoD(S2qvDVG3zAR-T@Z zx)y!S-vIma40U$wLpO|^;Fs&OnQ^Xq0jnAgfpqs1?qx2j7I!_|1Lh+9Z_Vp(T#Q-$ z1FL`Xulj%WFTwmj{j27q2HU0KEwxY`N0yuF{TFZF7$D}BleMlvl7OQjhyBQP%6bh2dWW+N{K-M=W5N62!A z)JGBz+&TimIKnXgg`&Jj$(o- zyIXSK-X# zN@Ik?xBXdpq~(3tKOL4eS9CjPZ|5AP5Xc~5tfG&O=k0LwViV7_AI!+nadKCbl4nk8 zloenclHUs>QqmcSQwB!)E=?Dm?JUc?oK-TJb~2b)k}BkL6x~ZSD0duAl?!XFSr9+J zzuSIJ;>)P|X*J>_PQO)|g6%DWTX(Se+Qk}v+zx&5FSg%;M*DaD3$Td!hk?C}$ad9l zKDK}d9Ngt9d6WW0p+hxAFhLn*o+IEdgh4C-0yi@7vPye>2;d0^pf@v;Dup*zuP<6B zgNf5aj0qyBm89^EB5?Kk;s73(r`?D3F`8$zah(-rPY25|RSV!>7~yO>xw3TAkr$4s zHBuJajIxGagm3LT)Ij{&Z$`QI3#ZAa4ldsOIUuX#KSq%1W6Qr0*o}NoDKOC+tu_K5 z@p)q~e)-i6*8o=C`BEGpbV-gZmk11#57#wh5mDu{Ch#^44J)-|<+UA# z1CrPBuzBUd8GZP;5&sPiUGa@+{yW+}eIw~oNqKZ5OW3uB8SvtPxCegi;IvQK{8Nsp z>%xjmrlA!nIeEhn1+^)1f?tZ@F@;ks_Xfe$4Dz$@m@)^G!d+ayK22k1UC@G)Fjv>X z3s1g8NaD{%&WP?9u3}9MKP`|69ET#w#NIA--C$jlr5}$Roe$cJ%>QyQi5Ca6M*8&i z4+k^!V89&jV0G{6+{`)|{KLUk(JE{%#)0G`Bzs{3pRx9CpR*E7s46R-0z8M-!<%2ckTZ;IaDG5|tG6DXcfc zQR&DYd8U4}n+0kg`E-K%?kfBnPjuX1hJ%hu?|F|B`%mtVV#R`hdXJXPFHYq@Dt*J4 zhK`7mC~vgTYeN_$M&krL4Ja-I9PA32R>+y96*uXXlNCU}DaED~(J&>Oor};y5J({cZp@Mx-^LHtL z1(?SpM1>!Wl0eR9keXDx z>)6y8R0Idd>kdnwbDD+LpVu@hj41xBtwj78Q0GF?Qqc}Vh#-qy7_J`hD0Wf(Q3x3% z_6{U$M|N~^eBp1Mxcg9?IhMdF1^2rOB^Wn6W;2I(CJnEP*l`u+9(q@oP4_PVo14V@ z*L2N`Hy&mSkoUuH&+LCAUCTO}8rdtE0v_-iI{bBh(|qZW2du+9B9s7L0isB_gtRgx z#stJrwXOy607~Qw`bK~f`G=Rz-8S(APdp2vErY|DXD*Q}9(;rzr>%Cb^er)l19(H1 z!ZO8fzXMu#yMWf6GN5%Q z{8FMlLbBgA^aa-%>JMu3mzA(n`9zy$om=ebXE3B1btGk7GkdOXT)MwI-y4?3ZKslK zpjo)G2PoogX$zGA$up@rgSTZ7Xes+5&jh4X9?+6G@x7;;*)S}^DVmbBm$#ud$BLO# zNtM8+;T0 zAuDFFIFqpyQ^AT*(^({JxIu_c3wJCOepl0NS-v&(2ccNUe6HG3@Q8}#$T6~O;j1@6TaeWA0T+( zfOE-;+okk^U|)VZIg5P2ZR8v;d427( z=5&XbZF*>`#qbz7ikbZ0q7F=t$F;78=-%r>t7x=E6k=$qpt7aYBvdcXy^u{aP~^E{hC1v2dHC$mVg0 z4-H4|g}MYnVzlpP)uf69z3FOJ??j%S0S$%cpC$C^k4x6RFuol;0*+fs)WFv%yE>)oJHUjLFYI9g9+;HLR5YL``J1B zw^W`&#{+i$a1?_yw{hr`y0a`byQ)lS7>&&kg5pPU!f#eaEkpY}*!Z5!%euFkZsW{R zGdU3+#<5P-4IWr_PP22_-iVUg%3BBPq;ru~(u`@JPda>>Z>y8emhwr!G-_&B3qci= z3~?%opSt#UHV@+B zy>y|UfXh1~zi0WVvs;X?>qEb9X%SRmJ~UyoKYzR~pcha*kX|kcjD8Cm;!LmBK~>Ljt9Fn*E+Yv$jD^ogpSI3Xp-0*`VqgSC`NY$J+pJ zVIuYs`bA>7*(%G#52=zBfD7srk}2}XZ*K;1ynf!D^*ksxXzg`6QzFSwN3ULN^>4?# z5(b0V$C$8-@wRUPA2kVH3DyEEod;2>bnS-29D`+`kYeC-~Q_l#QCELwxxS z1c>dIQsXD(p3nkeEvWk0n3qlA{E!m4*AU>r%+&q3&HBhXb)))|K_lVj4Dcd1bqBYhzYO{^pV~*d zjB29};xFh}LVUFyZ{aXBt;n(gvl7Q3sE2?aF_cWatTYLBs5GW0{{rmD_vSMXri-$l>5hJ-GV4ntf3KLGEe(q04wxa%TH6Fjx zx%&1tap!0u*z!q=)a`sqpc;Dw7+ID%7Ssih?Lv#w(3UM%@}gsCv&Vwq^Rk-Xkn0cf zSqdH(+@F~UZ4ePx!-1WN@cIbYzFoqt)jXihs@my(+&2b0pu87TECCFU%I0yK*J;EQ zh>1u?6O{R-@d?Sy=e!G% z>ar;^5CP)G^dmmKE9?-Y$2FS$9XIs}jjE@o6%NkGuAV3AO4~iOFR1Yfy*q>ipqBGn zGy5COx_?6LFU=x_2n%S0tNnHSl;i~y#LaJLCl>!i(Odxqd%n9rd#8BCADSjc=UOnWWM^8c$ zPeB>6jyUMt+upV=p93qQw843l<=DV%pM_A-JBlc1dWB51!H%{)2I<7zz^KH)NAj-7 zaPA6VWf3LPhQl0n*7JSjVSZ;+qz14{J-Bz7eV8b{u`gEEeAV^r`Gwn{Oef*K-4W4a zV*r?D3GT|l9$;mOhVxMv$PZF5n)^eSE`=(A%QPHH_|znG*{Tw}ULxN=7Js3?EQY_s zLck}yncD?;86cABzeF+x)0ar54~S%qA}^6_Pk!}V7Tq6_?89fx@eU8V^qN%LEzZFl zbi7}YOjTo!?In`&{uZvkv77x@xc=Kj28jLNtC12C0Q2%2F^Qxk(x;n=*ys~=O`(Kv z;{Dvt4kAt&*puQqaKDpexBXU`BHA#`TN;K5?N=iMVn5r4h5|giUN+>jkv)~HC-$| zb*oSnUxS4bYRM|tS}6;M2T;JGhGCnsYDE=IXp^lZSkNHvT0U1&fqJ>{rJW)0TjakJCL~|)S;ImyK z#6%pE3g&TCYO?gCGlb}YPW_}B)-|poNsq(P$7i>7Zu8)E;|Fd>B+-pvP?iC>v(hM0 zz`DjFF)9);GGEsHjh1`g6=+pBYtK#V5Es_VQ$B3 z@*deSUa;a8?59M(m)s4Q?0r_mYs;J|KSx^C3Wt3X4_f9gGvFVkFPwxU86q78gEI@>lAe*w%N3=sK;&%+@NED?bQ1BHkU zE$g%W=LqU14*%%!RPDC$zrzKAAJC`v$l40jUecKJ&8}rg@yB8tpN2oFs zntbLque(QcjFMg^-5*{N3%FMLPKW#^ zSz_gaC*yKHb14qQ=}T=lr_^(##MBk#6>?sT?E8{SM>#=kn1IsE%MtzskkLFjUj>?m zAf7av(f%3}p-{_y#w$KSq(Y=8x^==;3?91{FRMS)tZelge2woCwCV~ z;D!}+32ZX9x2_El^xb2BR6mO0*$69yHC5$}l1C@}Qj)bKmV)S-1TAfp&Qsg=V#eLj zAxX0-ACGPK0Xxp;%PWj=pOeQdqZXrV+X%&%R$B7*gXD)!XjfGRWBo*x18I;Oas|4tN>*5ke@6l-8hi9!-e8qg>KPT8JSXALljh)uYIHB)H& zG9r!3MXvH8xR!G6VR7nKJqzUA!mr4xMW-VxtJ;?yf`^RQO@DbmS1rV!}K;*2o)E+mRxB53m620N;H(i3mIr=ekd%@ zF0*)3)+mWR6E~ykG1VM?^vMb(gT~+^@dE+@zx?8bi-ZMfDgJlyzQj*Pb0ExBG}+p( zgplDmhoi_AEpGvxf+;UFn>t)xcy!^ErnTrdf;clsUD@l_EfOkSm+`#$vC35 zL3%@;&`{7{cq{@R(^1oSpHh!j`emybuI)I9H)?-$;b08a6ovELUY;@E0+R9JNnlTN zi1UUgMqv!$@o7-c;@VoY2sp!uUuONzQJD_y4F8GgYn0FI8)?9RAH?SZ_KnwZAp6FN z;Y4z6n9_?OF!AU*Ji&MviPSmR#y1IsZosSKpgP!uIJo3}YWa~z7S z)p{P$e*yE}8DASt*mpJQsWd>mpkp05u$XW-h&<{KLbyx8oHrIeSYIjP9Ta?Xc01$gc4Mgrg9HFRP+LS z>R2Il=ps0&78fOwC6V?qYxQb@FxD;bk&o8;4WATeutUze6F#(C;1^F+PJP#k(YZD;g5GKToXw=OxNv=saWge(Z}wx zHHETTq(>lWpdT2s*PE%w+=;GwkS=0sfyR3iZb3np+NOEC(`ab5Uw7f_#KExdrD_f(<^2fiRh?YwW7yB({m^R1VQ!d$%TDU z-!5Rt7M$0*uh+!#CG5r#^Z|QHJJB@`c>~C5L!#iW@HGom_-8A;2mKNeV*F%28DS3G%?GNq6+ zZTB(tneL5?JQ!lQ}4^5IRz zDq$2_;|}zE@P3AVgf8uiCT9mcvW+)wN660TbF_{e-YP=b6h@cDjJMZ1E_dn@Fep|8 z5W@RC%A)sWO`WC>Yj4oFcQJb>quJi)QA&P2Oz{`YHk6oJMW&Alf>$?JPQq=E4PR8$ za4Wo@J1xD|^S5Rk0SuSPFAdi@(tW480u{XfqcXdE&uwW6!v&)a0$zc5C8B8pD8?bN z71xvXgRDG8JIDzf&R*ZziOpaC22N7h=6uO!RSdA&|FoX%r+KT}SDj?MM+b2|zYF&C9FN zMG%3;jkgn!S(Jeim?-o6{P$E}XcHuJfIq*Xyvi#Ni}^}4Vki@?OmSFd@Oo-Vb(1T_ zLyBU-EblS($C1S$6s`yLEJOI>Vd`IQq6^8?k1=1W>RzQJe~&=w^Gtta5uR!D?sHxp ztcjld2CrcmwHLBXvBB+Dp`t4utAy&)3Vj_{B5YuNZleGZ8r zC=2s_25Pgk-JNPRm_%d8UuLqNwkiYL9QHhnT zk*w?{aPn#P@$YeopY<}(t3xpzQo?5ECkNfaN7GrpRf$VuvDeVJxrVOmYwM27Hc{9y7{Fsr!dcHTO;O?$Cpm1 z6NfNv|i|g$$VwDA(~7b>@lq?ELKgP61~@#>K=iPE!(r5nC@4P-vrFhX-6OC!$bGE-|7#= zxm?x1@i`!XQ>VU4b3{f$FuIBQd&9HAsb=h&T~F)^7#_={%+RbFL!@tpXIwq@j^F4` zc|Q-g$CrJbLzA+OQNAD!Am&!vh~uHNLA=!yjmrpbvE|k1jbUy<#PiR!ye-hPB&l71 zn&Lilz8W_oNhs&3G*bW>J+5N6_q zVa|J0c|EncL~tE=JXMh&l-t-c-ZSJAI>Wgs#+a^BOMY2ifuV{_z8v9ofCQp^yRuTa z<{<<&cBqd&@VFQb0v+3464f5VxaU-NJosq_QxjPoufdV9dHUX4$>5!waz05>02xrB zPq-@O80Q_ovwgt!fUFLaOJ?NT=#K5^Q}c6;1rhnGYzn&VGQ|8yT53|HkBnlJ#}CH` zlDr*&HJsorgsnS?F1JOKCg1c_lsVus+A!R@nDKS*X7DbOW%;-2bB+dcza8H5NW5Hz)X&L$s)d`bSzM`+F@yzMJc|_$OLKDUB>D7ZRB^LQp*n9(-{8^vN>zEd0+HI%2`s7ieP$Xw>(6b%y7tOGF}uhJ18736 z6u>b-Dp@XYOt3W4_wa>8A_w@@2;j~XH9zP)zGET{56X$l%j6SkHVAQ4fKxOKl0hge zM7wUprHHPHFe={)gvL8TxfrAfbJSuJ<_Xu#+n>=?no1Vg^3vbh^To#$NvG@$3}V#I zQ;fRMmwQJ~{X!_x%1Z|%BR)mIp-C?R4(+&R0JpYm-)NZ}9jI5S5@Tzkdrb(wXO!G~ zPy!qL+QeWlgYk=@nrIu=r_`3aXmb?XXz1f>SK9R7=TZ3$9jeckS-30q7scNjwH_-g zx31eb$yfs-qQIkRu;OukeZ>y9!29*!6K&MiE>C(=xQ&2uFTskx!(tQf_ zn%sYoGc(^eY>Hh)d0Y9O2B~p8&$jPnDSzx%A5a7&0Z0-S`9>?y*EiPLC@FSyt96UN z_?Bu`Uy~b-GzYw*ZiW=W7U0y{zdE&}M%_dU4@1dCI@E#{mV;w3BQJ(70xzsd!j+(I z0H(T6QnvX}h?2a?rWtSAd7As8HD}^Y_}3T1FPhU(KH#v9koE>Kc4lE9I4w^OQ&1<} zXcG|ZDp%l|$pt003Vu>T@GEf+z&G#8T3X%p&~Ts4g}bLd?3;Q(NXu}tTk>XJEsl(? zldgB1GrPt>`FlQ+*}TYs@ep<4(f)8fRSQintGp!xd;N76CWxXFWU1N4z)G4%fnMHw^2n zYJ|fET2Bv^95W2HmH;IR{G}3|&#(Q1WpLIa6@h_-OPL~mm3}uXq&{Ic_g1QyNO%OO z_H~+5;)OCGpe|qmEK(NR)~h+0VxCir6a};|XPc)<#W!pnPRyfBx&wagINPafw6+5Q zNDX#(ewL!h%nGkRt{&uON z=51^ZH|ckuZAx(rXag5|Kd

    `>&W-pQO2^>uKkCtg=$XbN~_c>jn7}JcbUuPC zpMzMtY~FqR{{}`}Ai)c6wiEs%thsU@c}R>l$u%nZ3#Z zc6+?wKGPU$+4 z=2*J-X;uqxW}$o#!_)sRV*D+jGd{o6ne!PQKxd%39TTBY)R{FOtF~w02096w8>#l) zWO%b(5J5bVOC$93@8WS8IJ;L}cVSxRC3)vN4;rnr+6Z%j?gTp=X$n})IEfFOnU?WH z5tiHUJ}=2`(T#JyJ?gmDl&nsCps`skbt#d)3@+KL?@1vj0wbk#qd~8b1OtV!OjTas z`r3qR3)*AB^!jW3n0Ok+9rvDS8blC73J)4!P!m6M`mrD(rOI6ybWFJ+r{K^NPvBVO zEugA}Zvc|YYEAX#A|cPNi&QB~A)jub$mEO8LG4vcqIp0Ru_W9Q5#2ne_!=$w0UOW^ zjX+w;St>1MuTxK9e$ z5)Zr$y=CIvx~CUGfBfX zG%5L)nnZc7sQMf1-9P3B0>f#e)`97$HbH@k8emckIRWbBycr0<-i5CM=!q}c9+pJ| zN05sU99NTLD_&fO3rj3-z`fxVM%ree5_84lk}r%0O+>u4o@^&_pv~1@oB9Sxq+GWS zmCl5XfGcJf@qm+T@-hU)5nZ{5O^C#okPB69TO3L3_5>1u?YzKq0ETlk@D8)qeG>qN zvumC?1uis^jx(|`0!bN9?4TF|!|6)2PF!R0OhIPExG%%aB_F>+F|ZiXZPo6Y@B*Qh z!m)kjR0m^p^Jc4FnK~BZbZ*dsL!}yDzW%QJ#(v)972o2KYP(n9i4Fj$b2@0*mYD`^ zY#XS@D|4UlzUtdBHEeew1Z`O;#og}ByzzUlL#ha1lZFOt(mJ`{gF44$%DDtBD_HU% zd$UbEf)X^>iC`au(ZN1_QM@lf15dHB=Q!IY?bBW^hWFp!G^A~(b?V9Gykd4iYF1z~ zcRtq^KbwWdlr=+R=H10cx=#nBUBKo{{MjDy$?Kzfz1&*VJ)`&O0466&1v%Tu13@0s zmvkf#*0K1~jI`!b1{^9>mi=QlUoA7pRa>D6R^K`VKsl8OHAy2GENSu`&2c}l=9x() z=&%W~VK#eySgNtr7K}a7u%WfM6YQuZMCpEncxsZG+dMaZt4Qa_jR5gAM3H`DlPdnQ zN$Pv2Ht80$O#(sLq`9*;DOUZ%oy@i7y>_<4{q=*vBgrzEpyUJZeMOYpp0Zj|6e(9* zRA#PTdBYHejdz;c#kr1INURrxO=>si?%E5~5BM|hGm72RyRP#2O(9UGqW^bp_d!<4 z;>=wzvhE=X7+&HM0=_`p<03}rS$p>5sC>qA(UCOW2LJV;rT5ZrYjVN#so`d;7CIyrRls@r1Zc%%Zl zr~x&lp35~{o;Vayz8EgUX>u?B0Xz+xl%b5~oq`ZmQt^Bo45CF(Yov=n-BD; z_wmY}Xxj8xAfi6*^~QSO0T0n9C&VjO5PeGjrC~Y;`W~Q9r(Jk|BfIuPkX_vXWLKpc zV9PHUI_K{?1Z?@&Fb5Bx0mUda)qI$Ys2f@ zpJl}JWL9Z2s|seo6l-9$2*`p?9Z3bN14ZyV-h4wNE zeqo$m%h0;vm3E`xp+#=3zGIjSni|@d7{+=dt+>pv!)l(En~a%k{AsON@0L%V-t1+I zf9w_+V)v5#p??FOhE>XtaHIWFkK%(#{M^}kDke~9h4z@ILRMnwGxwmJ6r6TBU41wdn@`MO4nSMF62 z9}mHZKZsab2=2qsqguaoaTPb-$o6IltCkZM7g_38`}EQMw7v(5uT$G6lL+M0;*r)x9@kz@L+0&d`JaLDkRp9&b z1%VMJ{$qy_jrV58ByEk0SHg)!86sNO;RHFFS zkw~{xz@qJ1c`$Rm!NXG|WsxXF+n?~^8+^2H)m3|1ETE+AbDyXdw<=o30nzcmn5TXk z(yy}PoDtmI5i^A#5<1e*Uu(WPL(x0(aS0T=Yr__PSLjo4ccq-Eb_MP1!BAsgRlr94 z(^!k*Cb^E|;>O%koDx~1lc z5&7ApfT9;FDLDcPET*hMZ{`cgI_szlbwT>^5Lo=nDB{Db8De5HvCdz*s+m05M+0x1 zYL`(z_%H3Mn(#<;OGO6;n8bUka%W5|fy9q8V8d6#cPL5i8paUa;DCHC&IAHfWs{BI zrMIrrlS~f4NdPJ@I_c9wY%2HnW2GR>4v5L32TWF?j74|*!#3=uZQ*}w*LFfQ#QTv} zG<4kY--N%fduU!dzDd0h`fA4^GB29@pzvsu$F*TD8LaeSU`6kREs9L+Y!X7nL-24W z2q@8XEIm!?nwUQnm6Ncfb_GR72OwA*1D)@BQ6eGv3ba=r+~d(@@;_PJ+ATVwk()-)YT)DzW+KP9= zFyoosJ1*_1Q>!LdA36h&80HpAElKrXogCJ5vN-+UobDwlbnOx}m!EBXznA0k`fEKV9trUel_TcK` z=VcW4L!hdBdk_SiDjC?$_M(P?;;FAu0EL)e11Z*tF8{taPVeM%9fkN?7O5nbdp<8d zEu7oHHCaDxJ%`i=Sm>l(VU1h2_C>^JbmXjL5kWOG;26CcN=CO}I~7tF|- zIj5-A;PbUM0I*YgR!`oCHk&pUgKI(2@xo;ZTl4nEs~j40Te93Qli`gZ?ZBCw<$wz$ zRMWoUrDom%l*+{vvh0R4$&p9!tCoO&O=~bm00)T<)kEE2~^pq%h&R}YVOQKA0*Eu{x z+<_!Ly>Ni|;;t!Ui?EfI*RkntNxYF%?RAKi^&YVw z`8mhCE4NxviT9;Z6qgkC;ti-pTDD2(T@vUM-1y$rf2M`=Z%ZuXxF(^gI60C>M`@mi zuv!ep9Ha@ZI4n8=SC<{u@Sae$gWpEtIV2-6a37ua!#q{+!&?WmD(jb8b&jIAf3ylX zG5D51f!LVEk+V#CkJsXyF#oJ0*@+!R>&)O-_Ygkhi-e^C~FlSF5+ zdnOL#mUPV<~ zJ7Q#@=<-L=6mWoeiC-KczoZB?-3@&y#zQloja&9$(4kaqF$bYHiY~O>^y$X@=h+R7 z5d0n#Q2Q)=N_BULf{y9E_ZVd% z@owJJH=bRC&xct^xzyIMULULE4sjI>Y~9mKDa#xjW)B0RsvrTN0+Rt-OPgWLt0-UQ zb$g(QTEDOgc-skxstSN@UZ4LR@&&c=W?Sk?{A!TzVugD z7;XV7mGn!MItP3{Frdl6PQkzyFjltz23)cSfOi0tO+Uy)Kjx`hckZGK%D+^NL&K#n z;a?(jVAPK<^rH+XZnqwM@SsCx1nwu7`ajn^hb>G=6imr#wfU3omO(k;MQ#BX z%YorPvh5FUKA9t@$>7vTMZ(R{qa7t5xQl%qsnJBz6mO{g2 z;^DIW=yi_)S0Qs(WKLzSYtKq9nzxWqJGX?BQF9nq zCS4}ZeN()8;zaD$_k_YpAcyq9Q!%7C&$m~l;%U8dI86POzPNs1vKTqpJ&?yAen^>_ z8aCH+XcCV^uv79joAAJ<`m}x1NvK&i0+4jNagkWvo8>Iu7p1E8TI0TTRSX86VeQ5sWpH9SuS$W(2m#N%I_6B; zI61iat4Wl`_-gS=jN7tOG4Gk)BuphC<(6mBE6u#|Z$JE`4(6m44)7UGYrfqu8*tNC zS5lX`!A^*B_LV-RX-~eh6;DC^woe9ItpSTgopI6RXMgwYw83Z>n;Y3GH|0l;Qpm@{ zRjcma2Rh7cH&Cwe*>3c&uYzC}haQ4X-ofLfZus)oyvcoEbens2^JB7hk~2a{Vo{6l z=Jb~bPC>^C%dRF0qF`UY!Y0k_t^1*OVx4=oJorcFPn$)Uq{AYk01asWr3P^RUIT3H zEUg@M?DUL(`0<~Sz5p6&6Y5(KAb$K0H*7GAxXpr$NlDs2f`Fo+U5ki;-Df^dTS>2D z`@2^=>x*u+=vU`xH;&fznM~u2-di7YQ*-y7kX@U8>o(?IYnJrEHA)s%?Mua%-JK`( z68=bC8cMX63e6m(IF^b#u*$F$o?Y2PuhVYhxR1ghebq5$LiZi-Zfd6{=F2kW!aP=+ zZgH>8&4e^N3`K-eMvPaShc$(&u5+79!f+!Ze56Ww&B(hQcP?bMg1_+J8Pv&19hy2+ ztv}4DX~?NT9MKu*_r)Ym-caHnY$Fj9W5&a zC20;lfrB+2x?JItxAW5j=}*WnUD6A9wY)@1D9yN~u;jw;`E~rxV^5}va6s~9zm)tr z=79Y~@~0m@VE6wL{SlJEC$rNJzX^ zJD?t|pIVR+2FKy)1cxXnaU8d05{Dd=-5u57mz0x!)3ZFU$h;KeqxXe2wqA~+PF?Dh zD9&dud?rkMN(Wir(qI;_R#2pZP@@VW?%XV}2yR~$9zxc@6Iu#JAWBNfq9+reaCLwt4mMzA#j}Y9vc@v0bqN) zrukeA^BZfbaa%X;V^8hYA-+X_By%X1z3RnJR%i?Rc}66sCo!E~A=;M&K;M*4C1u!? zm0Q!}<;OO9K6^nqxN58i0NeZ2zRSn1&1)=rnK`vPZc3~Pp0@TA!lH8Y-32UW5v&u! z&v5ZOe3~9ncYsO^DO{ULHNL#9XK6{JT%)!w1gELWxbgz!NI?2^zm)zt{Jx!znSr8( zj+L#krQMG{{eClGm(l`EVka7M4W)g^8?5k>S{lWtAK?SUb zR!K2Uuukz>Fmsn4eT66_S$OHql9#D$7FAg`eE@meZw=)$QHgCRcv2#}9P|MPS&~iew3RD>CRI!ze9jP34LX3M9>~yA z?JPUpwfy1Gz;X;$aHt2TU{+Gw`1+{n1opbpTN>J#!@XXjd$k>&Y{OfNQNZV4=B$2F zQ>#;OWfpc2KQcrBtlSPRrOg)7u_Zx3w*Cxr`4D`Rab=F(CMdfH=aT^0n<0@63rN&Q z8l7;VjZBu~MY}Hb%+tEd7Ty!4hwSEq$!c&aNNgfXrS))S9YPmIE;Cft1XneyBaE}p z3BYznm!&MhsRluW4^!Ew2dhjfNnk6Ykxjs>zM!`@(7NSizqtGv4n#nYKYBlKvbB<; z&~a6p9+}V8d!2V86}O}h^=aTXMQmJLk>n?Hq+CD+mZgc*N>>?{Z4o~Y2d7DVxbS9soK)X7}yCw@L1@62+m@lZ(?U@Lj!CJ>>$5QBWMqJ3UjFIPZ2qv z$eK0W1sazTY8%=2Rw~#i#09rR!*Eb<6LLpp;xU(e>i9IYT+SvBN0=~peae+j3pW|v z(@J+q!|dje>7%;ER@S_6;fidW`WtiQ?UL->BPOLZHqSMfVh97JH!G!J;Zw0C8>U;X z8Ym+=4+h$=*GKDjx!_b@%43#)El^j}wh{UKBd3Athm`!>3He(gSzNOZuPoE$xu86z zne){W^eiXxIKb4w12?5C8`C z=V7$+zh9=Dje(&7FyU6u;E&!R)Mb!&*d0-C3XCBFj)GnbcJTyE1?C1;;UG7=sG$Ael=3Qmg{omjU;~o2P)Iax+jxPc>6sAF%$shTGX!YGuVp;@Ub`g?RUG9 zmi3SJ!?p*?op)cWUy;>RK*2(?us(c*(*qI=ArwMcRayqI&x|#$I8I78zNk6}T zb2w&IXdxl8HT#VUzZgf&$peMw&%N0lwOESkMU(Xc9O(J*=q1-lwbS^*Wyd>KR2%&r zFxUp7+!hn~(Is+o3%qW@O>hjNb|4!C=fcyQ)9g32T_LY;zAQ+Cf|Vu@GYwZWmXND% zf{#m9)6Jb|IM^){2Q#tCj40q21@{f zboymyn9je2X=mVMN9ROis^g$T2PL6D`8c31I~A;wH00v|=H(KN)R5(r-;`${5(pZT z8xX{xFk@_4He_4Lmp^eQYw?jo&&V*A>FjddntF{o7lM{S%wnua&hd<=T=G(zl7U|r z(l$>lyR03vo7+0)JF_siCX9!<1rl75kFbq>y-7A+@wua2w8xEqxbsl5Q8mW*Hm8ob z+e2Z5mQ*}aJ9G14BT()1E6kN5ol1!%>f%@(nl10;ZQfV3WyX4ouaI&vkGR8Bh}s{G za&xHAKkIJCzQ36N5_}g`;x=7jz3|h{Yb%D7A!rmzIPe$i)2rACP)TE?rj@vbnJMx5 zSo(^4#B&yPkpy2dp*L7FCTZ08H0v%GmU*x?$vipMr(47~!`XI!;|l+3FuMQk$Q#U{ z2@?{X>V~#YYz;ZQ6Vz9erbn)ey~dhBiL`)Mj%tf1*R(OSraDS1R=E+4&Q3)dhdrMz zaZwA;3YmgG%lo<;D{96IjB%;Vl_e%t^R`+dui8F!gM0f-{H?Cr0V<${ z@T>2c|C7t#qO-KJ1EyEo(tWjwv{p8jRt7e9CI+@!bmZ+_y;KhE zQeEw`qmI(;)a`Twdu?4*6eHy{;(6r#FZ;SBs3qqYHd{0M*b2!f_&6#{o|CiCabRnr z0LBLCA}RA@CCCo_KJe$~#s>rVse#4ma13!f19Mwi6AMF2+f#O%bnRj^vv8-xD)yp1 z(12gP{7YiUz)yAUO+fmmRHUECL*{Y&O~W6c?^*lM-nM_68HV)n0ygX8;RDPtyGxh_ zl?!+BJf~HzxUoOBopG~z!dpJoqJ;jgvpL0#=e@#DLe0UQ~VnWLhdP(vz98}|AYgRRsfS}`=y>;03vU#1MrwE7%K zJmPB04P83MPupVnsM?>l0ME91`t-1HSTI;H7cX9fkruO*d`ey5FAC@c1i%9w`1#qT zXK7(*Vnj!4p{rwOXJacTdG=z_sDYjs;NoZ?+J@x0zb#+jZ~wYj_|#w8((zkZSla18 z^hL?p3UCYp04SE3)!)$N-;=I~73_eJhM?y|(w^TIWUlJDNkb(;zvob+93mS3Lk`x! z_i=s>-%4V?=RiGr^4u2SAPzhO1myYKvOxMR2SFVWNYTXZbinxcgmnvM?I1|<8318O z#_rqVy!3m*{~9OpJ$d?+djUBBc?fJZB$xATaijbp`Cq*MExczTsQ{P!e{qpU{ZlSK zmjU$j_p^GW45<5Wr2N-dL}4c@;2_Wz&|HZ3`u=S}4<0}Jwom};^rsyDo+oi!q9q~|C9 ztJecPIO?nf{K$UG;qO5~zxJrmbBWG=ZjM0d{%`Emzga+4KYlN3=*c$_6vJ=J6>x*+ zDw-^YJq^NWXq9^-M=%!7f3;@@!l;pmPZITPrK5ocdr5TMup zh0E!I)%OyDo*r;EGI<1`0se-~-xC9VbpOzR@sNc5xAhKC>vIzRMbH3^91ek<|F%Q{ zq5O{iw~CV=-8(c`^x1DP2}l&3pY|_q9~w3o&>EL2LP;NW;Kr z^Zl0i50ARe;1GY$4jRSutf=__?!S2!C}fboadE$=4-H;<_ESg{{8ReB5D7GbAp{BY z+d>riGd4eQ9?-aTXVuDB?9Uhg31qAQp+v-sH zEr*}#4m9Y&S(CJ@dOoVZkSTOW{8{2G8s{Yb^Q|3pzci%z@Y}N2JP+}oMDWlpvu7jK zk_YD``-?XM-Aj3v`bFLIQvdlYf$q9H`%0ws&qMtupAK{j*4dkWXn0Ptzlf~*q55(l zZCu}0r}4R{|3r|`{TXLJcr3H?(*4D4LznEI-H+*;pNBkD%g6Wj9J*HftSu?9`~%Xz zP($cK-m~up)8y;p<-rv@-%m0Jb4}*W`3K>WR6x4G6Ew7(c#r)`*pldPC9$6iF{8v6d zd?4tw|5-Whd;ONt&r|(BdM4=n@>x0UdjCII{qV7%)2~`kLV|(W_x%?ysQmN)B7gn8 zMS{*ADxbL*;Ya_vm+#U>|DJF1;}km7Wj}iL(Ag`UGq-^0|F2v4-zP1 Date: Wed, 15 Nov 2017 11:55:52 -0500 Subject: [PATCH 107/115] Rename DataSource => AutoIngestDataSource for clarity --- .../experimental/autoingest/AddArchiveTask.java | 4 ++-- .../autoingest/AddDataSourceCallback.java | 4 ++-- .../{DataSource.java => AutoIngestDataSource.java} | 4 ++-- .../experimental/autoingest/AutoIngestManager.java | 14 +++++++------- 4 files changed, 13 insertions(+), 13 deletions(-) rename Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/{DataSource.java => AutoIngestDataSource.java} (96%) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index be6a047bc3..ffe121cb7d 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -172,7 +172,7 @@ class AddArchiveTask implements Runnable { try { UUID taskId = UUID.randomUUID(); currentCase.notifyAddingDataSource(taskId); - DataSource internalDataSource = new DataSource(deviceId, newFilePath); + AutoIngestDataSource internalDataSource = new AutoIngestDataSource(deviceId, newFilePath); DataSourceProcessorCallback internalArchiveDspCallBack = new AddDataSourceCallback(currentCase, internalDataSource, taskId, archiveDspLock); selectedProcessor.process(deviceId, newFilePath, progressMonitor, internalArchiveDspCallBack); archiveDspLock.wait(); @@ -224,7 +224,7 @@ class AddArchiveTask implements Runnable { synchronized (archiveDspLock) { UUID taskId = UUID.randomUUID(); currentCase.notifyAddingDataSource(taskId); - DataSource internalDataSource = new DataSource(deviceId, destinationFolder); + AutoIngestDataSource internalDataSource = new AutoIngestDataSource(deviceId, destinationFolder); DataSourceProcessorCallback internalArchiveDspCallBack = new AddDataSourceCallback(currentCase, internalDataSource, taskId, archiveDspLock); // folder where archive was extracted to diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java index db19fc2fbc..fc00149249 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java @@ -35,7 +35,7 @@ import org.sleuthkit.datamodel.Content; class AddDataSourceCallback extends DataSourceProcessorCallback { private final Case caseForJob; - private final DataSource dataSourceInfo; + private final AutoIngestDataSource dataSourceInfo; private final UUID taskId; private final Object lock; @@ -48,7 +48,7 @@ class AddDataSourceCallback extends DataSourceProcessorCallback { * @param dataSourceInfo The data source * @param taskId The task id to associate with ingest job events. */ - AddDataSourceCallback(Case caseForJob, DataSource dataSourceInfo, UUID taskId, Object lock) { + AddDataSourceCallback(Case caseForJob, AutoIngestDataSource dataSourceInfo, UUID taskId, Object lock) { this.caseForJob = caseForJob; this.dataSourceInfo = dataSourceInfo; this.taskId = taskId; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSource.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDataSource.java similarity index 96% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSource.java rename to Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDataSource.java index db9d3d5ad9..89a0d0ad5f 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSource.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDataSource.java @@ -26,7 +26,7 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback import org.sleuthkit.datamodel.Content; @ThreadSafe -class DataSource { +class AutoIngestDataSource { private final String deviceId; private final Path path; @@ -34,7 +34,7 @@ class DataSource { private List errorMessages; private List content; - DataSource(String deviceId, Path path) { + AutoIngestDataSource(String deviceId, Path path) { this.deviceId = deviceId; this.path = path; } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index de2b65a966..35b563b961 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -2229,7 +2229,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen return; } - DataSource dataSource = identifyDataSource(); + AutoIngestDataSource dataSource = identifyDataSource(); if (null == dataSource) { currentJob.setProcessingStage(AutoIngestJob.Stage.COMPLETED, Date.from(Instant.now())); return; @@ -2280,7 +2280,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen * interrupted while blocked, i.e., * if auto ingest is shutting down. */ - private DataSource identifyDataSource() throws AutoIngestJobLoggerException, InterruptedException, CaseNodeData.InvalidDataException, CoordinationServiceException { + private AutoIngestDataSource identifyDataSource() throws AutoIngestJobLoggerException, InterruptedException, CaseNodeData.InvalidDataException, CoordinationServiceException { Manifest manifest = currentJob.getManifest(); Path manifestPath = manifest.getFilePath(); SYS_LOGGER.log(Level.INFO, "Identifying data source for {0} ", manifestPath); @@ -2297,7 +2297,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen return null; } String deviceId = manifest.getDeviceId(); - return new DataSource(deviceId, dataSourcePath); + return new AutoIngestDataSource(deviceId, dataSourcePath); } /** @@ -2314,7 +2314,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen * while blocked, i.e., if auto * ingest is shutting down. */ - private void runDataSourceProcessor(Case caseForJob, DataSource dataSource) throws InterruptedException, AutoIngestJobLoggerException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException, CaseNodeData.InvalidDataException, CoordinationServiceException { + private void runDataSourceProcessor(Case caseForJob, AutoIngestDataSource dataSource) throws InterruptedException, AutoIngestJobLoggerException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException, CaseNodeData.InvalidDataException, CoordinationServiceException { Manifest manifest = currentJob.getManifest(); Path manifestPath = manifest.getFilePath(); SYS_LOGGER.log(Level.INFO, "Adding data source for {0} ", manifestPath); @@ -2393,7 +2393,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen * while blocked, i.e., if auto * ingest is shutting down. */ - private void logDataSourceProcessorResult(DataSource dataSource) throws AutoIngestJobLoggerException, InterruptedException, CaseNodeData.InvalidDataException, CoordinationServiceException { + private void logDataSourceProcessorResult(AutoIngestDataSource dataSource) throws AutoIngestJobLoggerException, InterruptedException, CaseNodeData.InvalidDataException, CoordinationServiceException { Manifest manifest = currentJob.getManifest(); Path manifestPath = manifest.getFilePath(); Path caseDirectoryPath = currentJob.getCaseDirectoryPath(); @@ -2463,7 +2463,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen * while blocked, i.e., if auto * ingest is shutting down. */ - private void analyze(DataSource dataSource) throws AnalysisStartupException, AutoIngestJobLoggerException, InterruptedException, CaseNodeData.InvalidDataException, CoordinationServiceException { + private void analyze(AutoIngestDataSource dataSource) throws AnalysisStartupException, AutoIngestJobLoggerException, InterruptedException, CaseNodeData.InvalidDataException, CoordinationServiceException { Manifest manifest = currentJob.getManifest(); Path manifestPath = manifest.getFilePath(); SYS_LOGGER.log(Level.INFO, "Starting ingest modules analysis for {0} ", manifestPath); @@ -2560,7 +2560,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen * while blocked, i.e., if auto * ingest is shutting down. */ - private void exportFiles(DataSource dataSource) throws FileExportException, AutoIngestJobLoggerException, InterruptedException, CaseNodeData.InvalidDataException, CoordinationServiceException { + private void exportFiles(AutoIngestDataSource dataSource) throws FileExportException, AutoIngestJobLoggerException, InterruptedException, CaseNodeData.InvalidDataException, CoordinationServiceException { Manifest manifest = currentJob.getManifest(); Path manifestPath = manifest.getFilePath(); SYS_LOGGER.log(Level.INFO, "Exporting files for {0}", manifestPath); From 61b7f89788ad9aa42fe412874dddb8f8cde24f85 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Thu, 16 Nov 2017 09:40:29 -0500 Subject: [PATCH 108/115] Cleanup --- .../datamodel/AbstractSqlEamDb.java | 13 +++++++------ .../autopsy/centralrepository/datamodel/EamDb.java | 14 ++++++++------ .../centralrepository/datamodel/SqliteEamDb.java | 9 +++++---- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java index fa03d01321..eb73f9ef66 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java @@ -34,7 +34,6 @@ import java.time.LocalDate; import java.util.HashMap; import java.util.Map; import java.util.Set; -import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; @@ -1312,7 +1311,8 @@ public abstract class AbstractSqlEamDb implements EamDb { } /** - * Check whether the given reference set exists in the central repository. + * Check whether a reference set with the given parameters exists in the central repository. + * Used to check whether reference sets saved in the settings are still present. * @param referenceSetID * @param setName * @param version @@ -1773,14 +1773,15 @@ public abstract class AbstractSqlEamDb implements EamDb { } /** - * Check whether a reference set with the given name/version is in the central repo - * @param hashSetName + * Check whether a reference set with the given name/version is in the central repo. + * Used to check for name collisions when creating reference sets. + * @param referenceSetName * @param version * @return true if a matching set is found * @throws EamDbException */ @Override - public boolean referenceSetExists(String hashSetName, String version) throws EamDbException{ + public boolean referenceSetExists(String referenceSetName, String version) throws EamDbException{ Connection conn = connect(); PreparedStatement preparedStatement1 = null; @@ -1789,7 +1790,7 @@ public abstract class AbstractSqlEamDb implements EamDb { try { preparedStatement1 = conn.prepareStatement(sql1); - preparedStatement1.setString(1, hashSetName); + preparedStatement1.setString(1, referenceSetName); preparedStatement1.setString(2, version); resultSet = preparedStatement1.executeQuery(); return (resultSet.next()); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java index 1f1bd8a942..2ab708e5de 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java @@ -361,23 +361,25 @@ public interface EamDb { public void deleteReferenceSet(int referenceSetID) throws EamDbException; /** - * Check whether the given reference set exists in the central repository. + * Check whether a reference set with the given parameters exists in the central repository. + * Used to check whether reference sets saved in the settings are still present. * @param referenceSetID - * @param hashSetName + * @param referenceSetName * @param version * @return true if a matching entry exists in the central repository * @throws EamDbException */ - public boolean referenceSetIsValid(int referenceSetID, String hashSetName, String version) throws EamDbException; + public boolean referenceSetIsValid(int referenceSetID, String referenceSetName, String version) throws EamDbException; /** - * Check whether a reference set with the given name/version is in the central repo - * @param hashSetName + * Check whether a reference set with the given name/version is in the central repo. + * Used to check for name collisions when creating reference sets. + * @param referenceSetName * @param version * @return true if a matching set is found * @throws EamDbException */ - public boolean referenceSetExists(String hashSetName, String version) throws EamDbException; + public boolean referenceSetExists(String referenceSetName, String version) throws EamDbException; /** * Check if the given file hash is in this reference set. diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java index 4ee57db0b2..efbda95156 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java @@ -667,17 +667,18 @@ public class SqliteEamDb extends AbstractSqlEamDb { } /** - * Check whether a reference set with the given name/version is in the central repo - * @param hashSetName + * Check whether a reference set with the given name/version is in the central repo. + * Used to check for name collisions when creating reference sets. + * @param referenceSetName * @param version * @return true if a matching set is found * @throws EamDbException */ @Override - public boolean referenceSetExists(String hashSetName, String version) throws EamDbException { + public boolean referenceSetExists(String referenceSetName, String version) throws EamDbException { try{ acquireSharedLock(); - return super.referenceSetExists(hashSetName, version); + return super.referenceSetExists(referenceSetName, version); } finally { releaseSharedLock(); } From 6955416f02884eac332bedf3342e04a19611e45c Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 16 Nov 2017 15:32:16 -0500 Subject: [PATCH 109/115] Clean up EmbeddedFileExtractorIngestModule.java --- .../EmbeddedFileExtractorIngestModule.java | 123 +++++++++--------- 1 file changed, 60 insertions(+), 63 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java index 582c5c04c4..7d4328da59 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2014 Basis Technology Corp. + * Copyright 2013-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,66 +19,57 @@ package org.sleuthkit.autopsy.modules.embeddedfileextractor; import java.io.File; -import java.util.logging.Level; +import java.nio.file.Paths; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.autopsy.ingest.FileIngestModule; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.autopsy.ingest.IngestModule.ProcessResult; import org.sleuthkit.autopsy.ingest.IngestJobContext; -import org.sleuthkit.autopsy.ingest.IngestMessage; -import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter; -import org.sleuthkit.autopsy.modules.embeddedfileextractor.ImageExtractor.SupportedImageExtractionFormats; import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; import net.sf.sevenzipjbinding.SevenZipNativeInitializationException; +import org.sleuthkit.autopsy.ingest.FileIngestModuleAdapter; /** - * Embedded File Extractor ingest module extracts embedded files from supported - * archives and documents, adds extracted embedded DerivedFiles, reschedules - * extracted DerivedFiles for ingest. + * A file level ingest module that extracts embedded files from supported + * archive and document formats. */ @NbBundle.Messages({ "CannotCreateOutputFolder=Unable to create output folder.", "CannotRunFileTypeDetection=Unable to run file type detection.", "UnableToInitializeLibraries=Unable to initialize 7Zip libraries." }) -public final class EmbeddedFileExtractorIngestModule implements FileIngestModule { +public final class EmbeddedFileExtractorIngestModule extends FileIngestModuleAdapter { - private static final Logger logger = Logger.getLogger(EmbeddedFileExtractorIngestModule.class.getName()); - private final IngestServices services = IngestServices.getInstance(); static final String[] SUPPORTED_EXTENSIONS = {"zip", "rar", "arj", "7z", "7zip", "gzip", "gz", "bzip2", "tar", "tgz",}; // "iso"}; NON-NLS - - private IngestJobContext context; - private long jobId; - private final static IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter(); - private String moduleDirRelative; private String moduleDirAbsolute; - - private boolean archivextraction; - private boolean imageExtraction; private ImageExtractor imageExtractor; private SevenZipExtractor archiveExtractor; - SupportedImageExtractionFormats abstractFileExtractionFormat; - FileTypeDetector fileTypeDetector; + private FileTypeDetector fileTypeDetector; + /** + * Constructs a file level ingest module that extracts embedded files from + * supported archive and document formats. + */ EmbeddedFileExtractorIngestModule() { } @Override public void startUp(IngestJobContext context) throws IngestModuleException { - this.context = context; - jobId = context.getJobId(); - + /* + * Construct absolute and relative paths to the output directory. The + * relative path is relative to the case folder, and will be used in the + * case database for extracted (derived) file paths. The absolute path + * is used to write the extracted (derived) files to local storage. + */ final Case currentCase = Case.getCurrentCase(); + moduleDirRelative = Paths.get(currentCase.getModuleOutputDirectoryRelativePath(), EmbeddedFileExtractorModuleFactory.getModuleName()).toString(); + moduleDirAbsolute = Paths.get(currentCase.getModuleDirectory(), EmbeddedFileExtractorModuleFactory.getModuleName()).toString(); - moduleDirRelative = currentCase.getModuleOutputDirectoryRelativePath() + File.separator + EmbeddedFileExtractorModuleFactory.getModuleName(); //relative to the case, to store in db - moduleDirAbsolute = currentCase.getModuleDirectory() + File.separator + EmbeddedFileExtractorModuleFactory.getModuleName(); //absolute, to extract to - - // initialize the folder where the embedded files are extracted. + /* + * Create the output directory. + */ File extractionDirectory = new File(moduleDirAbsolute); if (!extractionDirectory.exists()) { try { @@ -88,71 +79,77 @@ public final class EmbeddedFileExtractorIngestModule implements FileIngestModule } } - // initialize the filetypedetector + /* + * Construct a file type detector. + */ try { fileTypeDetector = new FileTypeDetector(); } catch (FileTypeDetector.FileTypeDetectorInitException ex) { throw new IngestModuleException(Bundle.CannotRunFileTypeDetection(), ex); } - // initialize the extraction modules. + /* + * Construct a 7Zip file extractor for processing archive files. + */ try { this.archiveExtractor = new SevenZipExtractor(context, fileTypeDetector, moduleDirRelative, moduleDirAbsolute); } catch (SevenZipNativeInitializationException ex) { throw new IngestModuleException(Bundle.UnableToInitializeLibraries(), ex); } + /* + * Construct an embedded images extractor for processing Microsoft + * Office documents. + */ this.imageExtractor = new ImageExtractor(context, fileTypeDetector, moduleDirRelative, moduleDirAbsolute); } @Override public ProcessResult process(AbstractFile abstractFile) { - // skip the unallocated blocks - if ((abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) || - (abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK))) { + /* + * Skip unallocated space files. + */ + if ((abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) + || (abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK))) { return ProcessResult.OK; } - // skip known files + /* + * Skip known files. + */ if (abstractFile.getKnown().equals(TskData.FileKnown.KNOWN)) { return ProcessResult.OK; } - // check if the file is supported by either of the two embedded file extractors. - this.archivextraction = archiveExtractor.isSevenZipExtractionSupported(abstractFile); - this.imageExtraction = imageExtractor.isImageExtractionSupported(abstractFile); - - if (!abstractFile.isFile() && (!this.archivextraction || !this.imageExtraction)) { + /* + * Skip directories, etc. + */ + if (!abstractFile.isFile()) { return ProcessResult.OK; } - // call the archive extractor if archiveExtraction flag is set. - if (this.archivextraction) { + /* + * Attempt embedded file extraction for the file if it is a supported + * type/format. + */ + if (archiveExtractor.isSevenZipExtractionSupported(abstractFile)) { archiveExtractor.unpack(abstractFile); - } - - // calling the image extractor if imageExtraction flag set. - if (this.imageExtraction) { + } else if (imageExtractor.isImageExtractionSupported(abstractFile)) { imageExtractor.extractImage(abstractFile); } - return ProcessResult.OK; } - @Override - public void shutDown() { - // We don't need the value, but for cleanliness and consistency - refCounter.decrementAndGet(jobId); + /** + * Creates a unique name for a file by concatentating the file name and the + * file object id. + * + * @param file The file. + * + * @return The unique file name. + */ + static String getUniqueName(AbstractFile file) { + return file.getName() + "_" + file.getId(); } - /** - * Get local relative path to the unpacked archive root - * - * @param archiveFile - * - * @return - */ - static String getUniqueName(AbstractFile archiveFile) { - return archiveFile.getName() + "_" + archiveFile.getId(); - } } From 7698597682702c475d1b0f7c35e5cba030c441a5 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 16 Nov 2017 15:36:29 -0500 Subject: [PATCH 110/115] Update docs of EmbeddedFileExtractorModuleFactory.java --- .../EmbeddedFileExtractorModuleFactory.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorModuleFactory.java index 1cf8ae462b..57534287a4 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorModuleFactory.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2014-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,8 +27,8 @@ import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; /** - * A factory for creating archive extractor file ingest modules and the user - * interface panels used to configure the settings for instances of the modules. + * A factory for creating file level ingest module that extracts embedded files + * from supported archive and document formats. */ @NbBundle.Messages({ "EmbeddedFileExtractorIngestModule.ArchiveExtractor.moduleName=Embedded File Extractor", @@ -65,4 +65,5 @@ public class EmbeddedFileExtractorModuleFactory extends IngestModuleFactoryAdapt public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings ingestOptions) { return new EmbeddedFileExtractorIngestModule(); } + } From c062a20213a3fcddcd0d8d37b66b4fc9bfa80657 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Fri, 17 Nov 2017 08:47:43 -0500 Subject: [PATCH 111/115] Addresses most of the review comments --- .../datamodel/AbstractSqlEamDb.java | 39 ++++--------------- .../centralrepository/datamodel/EamDb.java | 19 ++------- .../datamodel/EamGlobalSet.java | 32 +++++++++------ .../datamodel/SqliteEamDb.java | 10 ++--- .../modules/hashdatabase/HashDbManager.java | 38 +++++++++++------- .../hashdatabase/HashLookupSettings.java | 12 +++--- .../ImportCentralRepoDbProgressDialog.java | 11 +++--- 7 files changed, 72 insertions(+), 89 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java index eb73f9ef66..7c7d22066e 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java @@ -1276,7 +1276,7 @@ public abstract class AbstractSqlEamDb implements EamDb { preparedStatement.setInt(1, referenceSetID); preparedStatement.executeUpdate(); } catch (SQLException ex) { - throw new EamDbException("Error deleting reference set", ex); // NON-NLS + throw new EamDbException("Error deleting reference set " + referenceSetID, ex); // NON-NLS } finally { EamDbUtil.closePreparedStatement(preparedStatement); EamDbUtil.closeConnection(conn); @@ -1285,7 +1285,7 @@ public abstract class AbstractSqlEamDb implements EamDb { /** * Remove all entries for this reference set from the reference tables - * (Currently only removes entries from the files table) + * (Currently only removes entries from the reference_file table) * @param referenceSetID * @throws EamDbException */ @@ -1303,7 +1303,7 @@ public abstract class AbstractSqlEamDb implements EamDb { preparedStatement.setInt(1, referenceSetID); preparedStatement.executeUpdate(); } catch (SQLException ex) { - throw new EamDbException("Error deleting files from reference set", ex); // NON-NLS + throw new EamDbException("Error deleting files from reference set " + referenceSetID, ex); // NON-NLS } finally { EamDbUtil.closePreparedStatement(preparedStatement); EamDbUtil.closeConnection(conn); @@ -1369,7 +1369,7 @@ public abstract class AbstractSqlEamDb implements EamDb { resultSet.next(); matchingInstances = resultSet.getLong(1); } catch (SQLException ex) { - throw new EamDbException("Error determining if file is in reference set.", ex); // NON-NLS + throw new EamDbException("Error determining if value (" + value + ") is in reference set " + referenceSetID, ex); // NON-NLS } finally { EamDbUtil.closePreparedStatement(preparedStatement); EamDbUtil.closeResultSet(resultSet); @@ -1388,7 +1388,7 @@ public abstract class AbstractSqlEamDb implements EamDb { * @return Global known status of the artifact */ @Override - public boolean isArtifactlKnownBadByReference(CorrelationAttribute.Type aType, String value) throws EamDbException { + public boolean isArtifactKnownBadByReference(CorrelationAttribute.Type aType, String value) throws EamDbException { // TEMP: Only support file correlation type if (aType.getId() != CorrelationAttribute.FILES_TYPE_ID) { @@ -1537,30 +1537,6 @@ public abstract class AbstractSqlEamDb implements EamDb { EamGlobalSet globalSet = getReferenceSetByID(referenceSetID); return (getOrganizationByID(globalSet.getOrgID())); } - - /** - * Add a new reference set - * - * @param orgID - * @param setName - * @param version - * @param importDate - * @return the reference set ID of the newly created set - * @throws EamDbException - */ - @Override - public int newReferenceSet(int orgID, String setName, String version, TskData.FileKnown knownStatus, - boolean isReadOnly) throws EamDbException { - EamDb dbManager = EamDb.getInstance(); - EamGlobalSet eamGlobalSet = new EamGlobalSet( - orgID, - setName, - version, - knownStatus, - isReadOnly, - LocalDate.now()); - return dbManager.newReferencelSet(eamGlobalSet); - } /** * Update an existing organization. @@ -1634,7 +1610,7 @@ public abstract class AbstractSqlEamDb implements EamDb { * @throws EamDbException */ @Override - public int newReferencelSet(EamGlobalSet eamGlobalSet) throws EamDbException { + public int newReferenceSet(EamGlobalSet eamGlobalSet) throws EamDbException { Connection conn = connect(); PreparedStatement preparedStatement1 = null; @@ -1796,7 +1772,8 @@ public abstract class AbstractSqlEamDb implements EamDb { return (resultSet.next()); } catch (SQLException ex) { - throw new EamDbException("Error getting reference instances by type and value.", ex); // NON-NLS + throw new EamDbException("Error testing whether reference set exists (name: " + referenceSetName + + " version: " + version, ex); // NON-NLS } finally { EamDbUtil.closePreparedStatement(preparedStatement1); EamDbUtil.closeResultSet(resultSet); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java index 2ab708e5de..9f7e31fbc5 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java @@ -354,7 +354,7 @@ public interface EamDb { List getListCasesHavingArtifactInstancesKnownBad(CorrelationAttribute.Type aType, String value) throws EamDbException; /** - * Remove a reference set and all hashes contained in it. + * Remove a reference set and all values contained in it. * @param referenceSetID * @throws EamDbException */ @@ -408,7 +408,7 @@ public interface EamDb { * * @return Global known status of the artifact */ - boolean isArtifactlKnownBadByReference(CorrelationAttribute.Type aType, String value) throws EamDbException; + boolean isArtifactKnownBadByReference(CorrelationAttribute.Type aType, String value) throws EamDbException; /** * Add a new organization @@ -477,20 +477,7 @@ public interface EamDb { * * @throws EamDbException */ - int newReferencelSet(EamGlobalSet eamGlobalSet) throws EamDbException; - - /** - * Add a new reference set - * - * @param orgID - * @param setName - * @param version - * @param importDate - * @return the reference set ID of the newly created set - * @throws EamDbException - */ - int newReferenceSet(int orgID, String setName, String version, TskData.FileKnown knownStatus, - boolean isReadOnly) throws EamDbException; + int newReferenceSet(EamGlobalSet eamGlobalSet) throws EamDbException; /** * Get a global set by ID diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java index e4292dc6ca..23a4c257ae 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java @@ -19,7 +19,6 @@ package org.sleuthkit.autopsy.centralrepository.datamodel; import java.time.LocalDate; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; import org.sleuthkit.datamodel.TskData; /** @@ -61,6 +60,26 @@ public class EamGlobalSet { LocalDate importDate) { this(-1, orgID, setName, version, knownStatus, isReadOnly, importDate); } + + /** + * Create a new EamGlobalSet object. + * This is intended to be used when creating a new global set as the + * globalSetID will be unknown to start. + * importDate will be automatically set to the current time. + * @param orgID + * @param setName + * @param version + * @param knownStatus + * @param isReadOnly + */ + public EamGlobalSet( + int orgID, + String setName, + String version, + TskData.FileKnown knownStatus, + boolean isReadOnly) { + this(-1, orgID, setName, version, knownStatus, isReadOnly, LocalDate.now()); + } /** * @return the globalSetID @@ -145,17 +164,6 @@ public class EamGlobalSet { public void setFileKnownStatus(TskData.FileKnown fileKnownStatus) { this.fileKnownStatus = fileKnownStatus; } - - /** - * Return the FileKnown status as a KnownFilesType - * @return KNOWN or KNOWN_BAD - */ - public HashDbManager.HashDb.KnownFilesType getKnownStatus(){ - if(fileKnownStatus.equals(TskData.FileKnown.BAD)){ - return HashDbManager.HashDb.KnownFilesType.KNOWN_BAD; - } - return HashDbManager.HashDb.KnownFilesType.KNOWN; - } /** * @return the importDate diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java index efbda95156..719a58385b 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java @@ -636,7 +636,7 @@ public class SqliteEamDb extends AbstractSqlEamDb { } /** - * Remove a reference set and all hashes contained in it. + * Remove a reference set and all values contained in it. * @param referenceSetID * @throws EamDbException */ @@ -693,10 +693,10 @@ public class SqliteEamDb extends AbstractSqlEamDb { * @return Global known status of the artifact */ @Override - public boolean isArtifactlKnownBadByReference(CorrelationAttribute.Type aType, String value) throws EamDbException { + public boolean isArtifactKnownBadByReference(CorrelationAttribute.Type aType, String value) throws EamDbException { try{ acquireSharedLock(); - return super.isArtifactlKnownBadByReference(aType, value); + return super.isArtifactKnownBadByReference(aType, value); } finally { releaseSharedLock(); } @@ -786,10 +786,10 @@ public class SqliteEamDb extends AbstractSqlEamDb { * @throws EamDbException */ @Override - public int newReferencelSet(EamGlobalSet eamGlobalSet) throws EamDbException { + public int newReferenceSet(EamGlobalSet eamGlobalSet) throws EamDbException { try{ acquireExclusiveLock(); - return super.newReferencelSet(eamGlobalSet); + return super.newReferenceSet(eamGlobalSet); } finally { releaseExclusiveLock(); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java index 27935cc3d9..35dd424c39 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -52,6 +52,7 @@ import org.sleuthkit.datamodel.HashEntry; import org.sleuthkit.datamodel.HashHitInfo; import org.sleuthkit.datamodel.SleuthkitJNI; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; /** * This class implements a singleton that manages the set of hash databases used @@ -233,7 +234,7 @@ public class HashDbManager implements PropertyChangeListener { return hashDb; } - private SleuthkitHashSet addHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, SleuthkitHashSet.KnownFilesType knownFilesType) throws TskCoreException { + private SleuthkitHashSet addHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws TskCoreException { // Wrap an object around the handle. SleuthkitHashSet hashDb = new SleuthkitHashSet(handle, hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); @@ -426,7 +427,7 @@ public class HashDbManager implements PropertyChangeListener { */ public synchronized List getKnownFileHashSets() { List hashDbs = new ArrayList<>(); - this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == SleuthkitHashSet.KnownFilesType.KNOWN)).forEach((db) -> { + this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == HashDb.KnownFilesType.KNOWN)).forEach((db) -> { hashDbs.add(db); }); return hashDbs; @@ -439,7 +440,7 @@ public class HashDbManager implements PropertyChangeListener { */ public synchronized List getKnownBadFileHashSets() { List hashDbs = new ArrayList<>(); - this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == SleuthkitHashSet.KnownFilesType.KNOWN_BAD)).forEach((db) -> { + this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == HashDb.KnownFilesType.KNOWN_BAD)).forEach((db) -> { hashDbs.add(db); }); return hashDbs; @@ -478,9 +479,9 @@ public class HashDbManager implements PropertyChangeListener { // Defaults for fields not stored in the central repository: // searchDuringIngest: false // sendIngestMessages: true if the hash set is notable - boolean sendIngestMessages = globalSet.getKnownStatus().equals(SleuthkitHashSet.KnownFilesType.KNOWN_BAD); + boolean sendIngestMessages = convertFileKnown(globalSet.getFileKnownStatus()).equals(HashDb.KnownFilesType.KNOWN_BAD); crHashSets.add(new HashDbInfo(globalSet.getSetName(), globalSet.getVersion(), - globalSet.getGlobalSetID(), globalSet.getKnownStatus(), globalSet.isReadOnly(), false, sendIngestMessages)); + globalSet.getGlobalSetID(), convertFileKnown(globalSet.getFileKnownStatus()), globalSet.isReadOnly(), false, sendIngestMessages)); } } catch (EamDbException ex){ Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS @@ -488,6 +489,13 @@ public class HashDbManager implements PropertyChangeListener { } return crHashSets; } + + private static HashDb.KnownFilesType convertFileKnown(TskData.FileKnown fileKnown){ + if(fileKnown.equals(TskData.FileKnown.BAD)){ + return HashDb.KnownFilesType.KNOWN_BAD; + } + return HashDb.KnownFilesType.KNOWN; + } /** * Restores the last saved hash sets configuration. This supports @@ -700,7 +708,7 @@ public class HashDbManager implements PropertyChangeListener { public abstract String getDatabasePath() throws TskCoreException; - public abstract SleuthkitHashSet.KnownFilesType getKnownFilesType(); + public abstract HashDb.KnownFilesType getKnownFilesType(); public abstract boolean getSearchDuringIngest(); @@ -773,7 +781,7 @@ public class HashDbManager implements PropertyChangeListener { private final String hashSetName; private boolean searchDuringIngest; private boolean sendIngestMessages; - private final SleuthkitHashSet.KnownFilesType knownFilesType; + private final HashDb.KnownFilesType knownFilesType; private boolean indexing; private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); @@ -1052,7 +1060,7 @@ public class HashDbManager implements PropertyChangeListener { private final String hashSetName; private boolean searchDuringIngest; private boolean sendIngestMessages; - private final SleuthkitHashSet.KnownFilesType knownFilesType; + private final HashDb.KnownFilesType knownFilesType; private final int referenceSetID; private final String version; private String orgName; @@ -1061,7 +1069,7 @@ public class HashDbManager implements PropertyChangeListener { @Messages({"HashDbManager.CentralRepoHashDb.orgError=Error loading organization"}) private CentralRepoHashSet(String hashSetName, String version, int referenceSetID, - boolean useForIngest, boolean sendHitMessages, SleuthkitHashSet.KnownFilesType knownFilesType, + boolean useForIngest, boolean sendHitMessages, HashDb.KnownFilesType knownFilesType, boolean readOnly) throws TskCoreException{ this.hashSetName = hashSetName; @@ -1075,7 +1083,7 @@ public class HashDbManager implements PropertyChangeListener { try{ orgName = EamDb.getInstance().getReferenceSetOrganization(referenceSetID).getName(); } catch (EamDbException ex){ - Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error looking up central repository organization", ex); //NON-NLS + Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error looking up central repository organization for reference set " + referenceSetID, ex); //NON-NLS orgName = Bundle.HashDbManager_CentralRepoHashDb_orgError(); } } @@ -1139,7 +1147,7 @@ public class HashDbManager implements PropertyChangeListener { } @Override - public SleuthkitHashSet.KnownFilesType getKnownFilesType() { + public HashDb.KnownFilesType getKnownFilesType() { return knownFilesType; } @@ -1242,7 +1250,8 @@ public class HashDbManager implements PropertyChangeListener { try{ return EamDb.getInstance().isFileHashInReferenceSet(file.getMd5Hash(), this.referenceSetID); } catch (EamDbException ex){ - Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup", ex); //NON-NLS + Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup for hash " + + file.getMd5Hash() + " in reference set " + referenceSetID, ex); //NON-NLS throw new TskCoreException("Error performing central reposiotry hash lookup", ex); } } @@ -1273,7 +1282,8 @@ public class HashDbManager implements PropertyChangeListener { result = new HashHitInfo(file.getMd5Hash(), "", ""); } } catch (EamDbException ex){ - Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup", ex); //NON-NLS + Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup for hash " + + file.getMd5Hash() + " in reference set " + referenceSetID, ex); //NON-NLS throw new TskCoreException("Error performing central reposiotry hash lookup", ex); } } @@ -1364,7 +1374,7 @@ public class HashDbManager implements PropertyChangeListener { try { SleuthkitJNI.createLookupIndexForHashDatabase(hashDb.getHandle()); } catch (TskCoreException ex) { - Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error indexing hash database", ex); //NON-NLS + Logger.getLogger(HashDbIndexer.class.getName()).log(Level.SEVERE, "Error indexing hash set " + hashDb.getHashSetName(), ex); //NON-NLS JOptionPane.showMessageDialog(null, NbBundle.getMessage(this.getClass(), "HashDbManager.dlgMsg.errorIndexingHashSet", diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java index 8630b516c4..948f18451d 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java @@ -202,7 +202,7 @@ final class HashLookupSettings implements Serializable { // Handle legacy known files types. if (knownFilesType.equals("NSRL")) { //NON-NLS - knownFilesType = HashDbManager.SleuthkitHashSet.KnownFilesType.KNOWN.toString(); + knownFilesType = HashDbManager.HashDb.KnownFilesType.KNOWN.toString(); updatedSchema = true; } @@ -236,7 +236,7 @@ final class HashLookupSettings implements Serializable { } else { throw new HashLookupSettingsException(String.format(elementErrorMessage, PATH_ELEMENT)); } - hashDbInfoList.add(new HashDbInfo(hashSetName, HashDbManager.SleuthkitHashSet.KnownFilesType.valueOf(knownFilesType), + hashDbInfoList.add(new HashDbInfo(hashSetName, HashDbManager.HashDb.KnownFilesType.valueOf(knownFilesType), searchDuringIngestFlag, sendIngestMessagesFlag, dbPath)); hashSetNames.add(hashSetName); } @@ -304,7 +304,7 @@ final class HashLookupSettings implements Serializable { private static final long serialVersionUID = 1L; private final String hashSetName; - private final HashDbManager.SleuthkitHashSet.KnownFilesType knownFilesType; + private final HashDbManager.HashDb.KnownFilesType knownFilesType; private boolean searchDuringIngest; private final boolean sendIngestMessages; private final String path; @@ -323,7 +323,7 @@ final class HashLookupSettings implements Serializable { * @param sendIngestMessages Whether or not ingest messages are sent * @param path The path to the db */ - HashDbInfo(String hashSetName, HashDbManager.SleuthkitHashSet.KnownFilesType knownFilesType, boolean searchDuringIngest, boolean sendIngestMessages, String path) { + HashDbInfo(String hashSetName, HashDbManager.HashDb.KnownFilesType knownFilesType, boolean searchDuringIngest, boolean sendIngestMessages, String path) { this.hashSetName = hashSetName; this.knownFilesType = knownFilesType; this.searchDuringIngest = searchDuringIngest; @@ -335,7 +335,7 @@ final class HashLookupSettings implements Serializable { this.dbType = DatabaseType.FILE; } - HashDbInfo(String hashSetName, String version, int referenceSetID, HashDbManager.SleuthkitHashSet.KnownFilesType knownFilesType, boolean readOnly, boolean searchDuringIngest, boolean sendIngestMessages){ + HashDbInfo(String hashSetName, String version, int referenceSetID, HashDbManager.HashDb.KnownFilesType knownFilesType, boolean readOnly, boolean searchDuringIngest, boolean sendIngestMessages){ this.hashSetName = hashSetName; this.version = version; this.referenceSetID = referenceSetID; @@ -407,7 +407,7 @@ final class HashLookupSettings implements Serializable { * * @return The known files type setting. */ - HashDbManager.SleuthkitHashSet.KnownFilesType getKnownFilesType() { + HashDbManager.HashDb.KnownFilesType getKnownFilesType() { return knownFilesType; } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java index 1f44df404e..880feabcb7 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java @@ -39,6 +39,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import org.sleuthkit.autopsy.centralrepository.datamodel.EamGlobalFileInstance; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamGlobalSet; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; @@ -77,7 +78,7 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P } void importFile(String hashSetName, String version, int orgId, - boolean searchDuringIngest, boolean sendIngestMessages, HashDbManager.SleuthkitHashSet.KnownFilesType knownFilesType, + boolean searchDuringIngest, boolean sendIngestMessages, HashDbManager.HashDb.KnownFilesType knownFilesType, boolean readOnly, String importFileName){ setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); @@ -139,7 +140,7 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P private final int orgId; private final boolean searchDuringIngest; private final boolean sendIngestMessages; - private final HashDbManager.SleuthkitHashSet.KnownFilesType knownFilesType; + private final HashDbManager.HashDb.KnownFilesType knownFilesType; private final boolean readOnly; private final File importFile; private final long totalLines; @@ -148,7 +149,7 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P private final AtomicLong numLines = new AtomicLong(); ImportIDXWorker(String hashSetName, String version, int orgId, - boolean searchDuringIngest, boolean sendIngestMessages, HashDbManager.SleuthkitHashSet.KnownFilesType knownFilesType, + boolean searchDuringIngest, boolean sendIngestMessages, HashDbManager.HashDb.KnownFilesType knownFilesType, boolean readOnly, File importFile){ this.hashSetName = hashSetName; @@ -194,14 +195,14 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P protected Void doInBackground() throws Exception { TskData.FileKnown knownStatus; - if (knownFilesType.equals(HashDbManager.SleuthkitHashSet.KnownFilesType.KNOWN)) { + if (knownFilesType.equals(HashDbManager.HashDb.KnownFilesType.KNOWN)) { knownStatus = TskData.FileKnown.KNOWN; } else { knownStatus = TskData.FileKnown.BAD; } // Create an empty hashset in the central repository - referenceSetID = EamDb.getInstance().newReferenceSet(orgId, hashSetName, version, knownStatus, readOnly); + referenceSetID = EamDb.getInstance().newReferenceSet(new EamGlobalSet(orgId, hashSetName, version, knownStatus, readOnly)); EamDb dbManager = EamDb.getInstance(); CorrelationAttribute.Type contentType = dbManager.getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID); // get "FILES" type From 5bccb82c685882dab0523fc93de5642957aff3b7 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Fri, 17 Nov 2017 09:41:37 -0500 Subject: [PATCH 112/115] Update central repo hashsets automatically when getting known, known bad, or updateable hash sets --- .../modules/hashdatabase/HashDbManager.java | 17 ++++++++++++++++- .../HashLookupModuleSettingsPanel.java | 5 ----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java index 35dd424c39..e8de1893ca 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -427,6 +427,11 @@ public class HashDbManager implements PropertyChangeListener { */ public synchronized List getKnownFileHashSets() { List hashDbs = new ArrayList<>(); + try{ + updateHashSetsFromCentralRepository(); + } catch (TskCoreException ex){ + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS + } this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == HashDb.KnownFilesType.KNOWN)).forEach((db) -> { hashDbs.add(db); }); @@ -440,6 +445,11 @@ public class HashDbManager implements PropertyChangeListener { */ public synchronized List getKnownBadFileHashSets() { List hashDbs = new ArrayList<>(); + try{ + updateHashSetsFromCentralRepository(); + } catch (TskCoreException ex){ + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS + } this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == HashDb.KnownFilesType.KNOWN_BAD)).forEach((db) -> { hashDbs.add(db); }); @@ -457,6 +467,11 @@ public class HashDbManager implements PropertyChangeListener { private List getUpdateableHashSets(List hashDbs) { ArrayList updateableDbs = new ArrayList<>(); + try{ + updateHashSetsFromCentralRepository(); + } catch (TskCoreException ex){ + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS + } for (HashDb db : hashDbs) { try { if (db.isUpdateable()) { @@ -603,7 +618,7 @@ public class HashDbManager implements PropertyChangeListener { } } - void updateHashSetsFromCentralRepository() throws TskCoreException { + private void updateHashSetsFromCentralRepository() throws TskCoreException { if(EamDb.isEnabled()){ List crHashDbInfoList = getCentralRepoHashSetsFromDatabase(); for(HashDbInfo hashDbInfo : crHashDbInfoList) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java index c6d3e109fe..bbe2a4e7d9 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java @@ -53,11 +53,6 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe } private void initializeHashSetModels(HashLookupModuleSettings settings) { - try{ - hashDbManager.updateHashSetsFromCentralRepository(); - } catch (TskCoreException ex){ - Logger.getLogger(HashLookupModuleSettingsPanel.class.getName()).log(Level.SEVERE, "Error updating central repository hash sets", ex); //NON-NLS - } initializeHashSetModels(settings, hashDbManager.getKnownFileHashSets(), knownHashSetModels); initializeHashSetModels(settings, hashDbManager.getKnownBadFileHashSets(), knownBadHashSetModels); } From f156b2c0bdf0299e7e85f5cefe85f720110e1e11 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Fri, 17 Nov 2017 15:44:32 -0500 Subject: [PATCH 113/115] Cleanup --- .../core.jar/org/netbeans/core/startup/Bundle.properties | 4 ++-- .../org/netbeans/core/windows/view/ui/Bundle.properties | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties index 2922cd2054..0de39782ca 100644 --- a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties +++ b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Thu, 07 Sep 2017 13:53:53 -0400 +#Wed, 08 Nov 2017 17:45:11 -0500 LBL_splash_window_title=Starting Autopsy SPLASH_HEIGHT=314 SPLASH_WIDTH=538 @@ -8,4 +8,4 @@ SplashRunningTextBounds=0,289,538,18 SplashRunningTextColor=0x0 SplashRunningTextFontSize=19 -currentVersion=Autopsy 4.4.2 +currentVersion=Autopsy 4.5.0 diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties index 2ac51b0cbd..f18b1cb91d 100644 --- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties +++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties @@ -1,4 +1,4 @@ #Updated by build script -#Thu, 07 Sep 2017 13:53:53 -0400 -CTL_MainWindow_Title=Autopsy 4.4.2 -CTL_MainWindow_Title_No_Project=Autopsy 4.4.2 +##Wed, 08 Nov 2017 17:45:11 -0500 +CTL_MainWindow_Title=Autopsy 4.5.0 +CTL_MainWindow_Title_No_Project=Autopsy 4.5.0 From 83d805aa9b46d6b79afb682f01d3f63a23a55683 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Fri, 17 Nov 2017 15:48:15 -0500 Subject: [PATCH 114/115] Cleanup --- .../org/netbeans/core/windows/view/ui/Bundle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties index f18b1cb91d..fa55dddb62 100644 --- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties +++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties @@ -1,4 +1,4 @@ #Updated by build script -##Wed, 08 Nov 2017 17:45:11 -0500 +#Wed, 08 Nov 2017 17:45:11 -0500 CTL_MainWindow_Title=Autopsy 4.5.0 CTL_MainWindow_Title_No_Project=Autopsy 4.5.0 From e24518be5139fae1c863bc8d32649c312b335ace Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Fri, 17 Nov 2017 15:52:37 -0500 Subject: [PATCH 115/115] Cleanup --- .../sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java index bfe10f2c08..8e0f5422a1 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -1281,7 +1281,7 @@ public class HashDbManager implements PropertyChangeListener { EamDb.getInstance().bulkInsertReferenceTypeEntries(globalFileInstances, EamDb.getInstance().getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID)); } catch (EamDbException ex){ - throw new TskCoreException("Error adding hashes", ex); + throw new TskCoreException("Error adding hashes to " + getDisplayName(), ex); } }