From c860006f1ac9c19d9def96f66755c254f3ba1562 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 9 Feb 2021 16:42:17 -0500 Subject: [PATCH 01/42] first commit --- .../sleuthkit/autopsy/casemodule/Case.java | 3 + Core/src/org/sleuthkit/autopsy/core/layer.xml | 1 + .../datamodel/hosts/OpenHostsAction.java | 85 +++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/hosts/OpenHostsAction.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index c2fd9d822f..393d687807 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -104,6 +104,7 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.ThreadUtils; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; import org.sleuthkit.autopsy.coreutils.Version; +import org.sleuthkit.autopsy.datamodel.hosts.OpenHostsAction; import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.autopsy.events.AutopsyEventException; import org.sleuthkit.autopsy.events.AutopsyEventPublisher; @@ -1111,6 +1112,7 @@ public class Case { * Enable the case-specific actions. */ CallableSystemAction.get(AddImageAction.class).setEnabled(FeatureAccessUtils.canAddDataSources()); + CallableSystemAction.get(OpenHostsAction.class).setEnabled(true); CallableSystemAction.get(CaseCloseAction.class).setEnabled(true); CallableSystemAction.get(CaseDetailsAction.class).setEnabled(true); CallableSystemAction.get(DataSourceSummaryAction.class).setEnabled(true); @@ -1166,6 +1168,7 @@ public class Case { * Disable the case-specific menu items. */ CallableSystemAction.get(AddImageAction.class).setEnabled(false); + CallableSystemAction.get(OpenHostsAction.class).setEnabled(false); CallableSystemAction.get(CaseCloseAction.class).setEnabled(false); CallableSystemAction.get(CaseDetailsAction.class).setEnabled(false); CallableSystemAction.get(DataSourceSummaryAction.class).setEnabled(false); diff --git a/Core/src/org/sleuthkit/autopsy/core/layer.xml b/Core/src/org/sleuthkit/autopsy/core/layer.xml index 288c25ff3a..d2805c606b 100644 --- a/Core/src/org/sleuthkit/autopsy/core/layer.xml +++ b/Core/src/org/sleuthkit/autopsy/core/layer.xml @@ -49,6 +49,7 @@ + diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/OpenHostsAction.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/OpenHostsAction.java new file mode 100644 index 0000000000..fbfb14be59 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/OpenHostsAction.java @@ -0,0 +1,85 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.datamodel.hosts; + +import java.awt.Frame; +import java.beans.PropertyChangeEvent; +import java.util.EnumSet; +import javax.swing.Action; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.awt.ActionReferences; +import org.openide.awt.ActionRegistration; +import org.openide.util.HelpCtx; +import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; +import org.openide.util.actions.CallableSystemAction; +import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.ThreadConfined; + +/** + * An Action that opens the Host Management window. + */ +@ActionID(category = "Case", id = "org.sleuthkit.autopsy.datamodel.hosts.OpenHostsAction") +@ActionRegistration(displayName = "#CTL_OpenHosts", lazy = false) +@ActionReferences(value = { + @ActionReference(path = "Toolbars/Case", position = 99, separatorBefore = 98) +}) +@Messages({ + "CTL_OpenHosts=Hosts" +}) +public final class OpenHostsAction extends CallableSystemAction { + + private static final long serialVersionUID = 1L; + + public OpenHostsAction() { + putValue(Action.NAME, Bundle.CTL_OpenHosts()); + this.setEnabled(false); + Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> { + setEnabled(null != evt.getNewValue()); + }); + +// menuItem = super.getMenuPresenter(); + } + + @Override + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) + public void performAction() { + Frame parent = WindowManager.getDefault().getMainWindow(); + ManageHostsDialog dialog = new ManageHostsDialog(parent, true); + dialog.setVisible(true); + } + + @Override + @NbBundle.Messages("OpenHostsAction_displayName=Hosts") + public String getName() { + return Bundle.OpenHostsAction_displayName(); + } + + @Override + public HelpCtx getHelpCtx() { + return HelpCtx.DEFAULT_HELP; + } + + @Override + public boolean asynchronous() { + return false; // run on edt + } +} From 2feff3dca2efe4877659a62bcfef55d89d3cf2d1 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 9 Feb 2021 16:42:33 -0500 Subject: [PATCH 02/42] first commit --- .../datamodel/hosts/AddEditHostDialog.form | 117 +++++ .../datamodel/hosts/AddEditHostDialog.java | 246 ++++++++++ .../autopsy/datamodel/hosts/Bundle.properties | 15 + .../datamodel/hosts/Bundle.properties-MERGED | 23 + .../datamodel/hosts/ManageHostsDialog.form | 359 +++++++++++++++ .../datamodel/hosts/ManageHostsDialog.java | 428 ++++++++++++++++++ 6 files changed, 1188 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.form create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.form create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.form b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.form new file mode 100644 index 0000000000..3ffa0901da --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.form @@ -0,0 +1,117 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java new file mode 100644 index 0000000000..70041e1105 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java @@ -0,0 +1,246 @@ +/* + * Central Repository + * + * Copyright 2021 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.datamodel.hosts; + +import org.sleuthkit.datamodel.Host; +import java.util.Collection; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import org.openide.util.NbBundle.Messages; + +/** + * + * Dialog for adding or editing a host. + */ +class AddEditHostDialog extends javax.swing.JDialog { + + private static final long serialVersionUID = 1L; + + private boolean changed = false; + + private final Set hostNamesUpper; + private final Host initialHost; + + AddEditHostDialog(java.awt.Frame parent, Collection currentHosts) { + this(parent, currentHosts, null); + } + + /** + * Main constructor. + * + * @param parent The parent frame for this dialog. + * @param currentHosts The current set of hosts (used for determining if + * name is unique). + * @param initialHost If adding a new host, this will be a null value. + * Otherwise, if editing, this will be the host being edited. + */ + @Messages({ + "AddEditHostDialog_addHost_title=Add Host", + "AddEditHostDialog_editHost_title=Edit Host" + }) + AddEditHostDialog(java.awt.Frame parent, Collection currentHosts, Host initialHost) { + super(parent, true); + this.initialHost = initialHost; + setTitle(initialHost == null ? Bundle.AddEditHostDialog_addHost_title() : Bundle.AddEditHostDialog_editHost_title()); + + Stream curHostStream = (currentHosts == null) ? Stream.empty() : currentHosts.stream(); + hostNamesUpper = curHostStream + .filter(h -> h != null && h.getName() != null) + .map(h -> h.getName().toUpperCase()) + .collect(Collectors.toSet()); + + initComponents(); + onNameUpdate(initialHost == null ? null : initialHost.getName()); + + // initially, don't show validation message (for empty strings or repeat), + // but do disable ok button if not valid. + validationLabel.setText(""); + + inputTextField.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void changedUpdate(DocumentEvent e) { + onNameUpdate(inputTextField.getText()); + } + + @Override + public void removeUpdate(DocumentEvent e) { + onNameUpdate(inputTextField.getText()); + } + + @Override + public void insertUpdate(DocumentEvent e) { + onNameUpdate(inputTextField.getText()); + } + }); + } + + /** + * @return The current string value for the name in the input field. + */ + String getValue() { + return inputTextField.getText(); + } + + /** + * @return Whether or not the value has been changed and the user pressed + * okay to save the new value. + */ + boolean isChanged() { + return changed; + } + + /** + * When the text field is updated, this method is called. + * + * @param newNameValue + */ + private void onNameUpdate(String newNameValue) { + String newNameValueOrEmpty = newNameValue == null ? "" : newNameValue; + // update input text field if it is not the same. + if (!newNameValueOrEmpty.equals(this.inputTextField.getText())) { + inputTextField.setText(newNameValue); + } + + // validate text input against invariants setting validation + // message and whether or not okay button is enabled accordingly. + String validationMessage = getValidationMessage(newNameValue); + okButton.setEnabled(validationMessage == null); + validationLabel.setText(validationMessage == null ? "" : validationMessage); + } + + /** + * Gets the validation message based on the current text checked against the + * host names. + * + * @param name The current name in the text field. + * @return The validation message if the name is not valid or null. + */ + @Messages({ + "AddEditHostDialog_getValidationMessage_onEmpty=Please provide some text for the host name.", + "AddEditHostDialog_getValidationMessage_sameAsOriginal=Please provide a new name for this host.", + "AddEditHostDialog_getValidationMessage_onDuplicate=Another host already has the same name. Please choose a different name for this host.",}) + private String getValidationMessage(String name) { + if (name == null || name.isEmpty()) { + return Bundle.AddEditHostDialog_getValidationMessage_onEmpty(); + } else if (initialHost != null && name.equalsIgnoreCase(initialHost.getName())) { + return Bundle.AddEditHostDialog_getValidationMessage_sameAsOriginal(); + } else if (hostNamesUpper.contains(name.toUpperCase())) { + return Bundle.AddEditHostDialog_getValidationMessage_onDuplicate(); + } else { + return null; + } + } + + /** + * 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() { + + inputTextField = new javax.swing.JTextField(); + javax.swing.JLabel nameLabel = new javax.swing.JLabel(); + validationLabel = new javax.swing.JLabel(); + okButton = new javax.swing.JButton(); + javax.swing.JButton cancelButton = new javax.swing.JButton(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + + inputTextField.setText(org.openide.util.NbBundle.getMessage(AddEditHostDialog.class, "AddEditHostDialog.inputTextField.text")); // NOI18N + + nameLabel.setText(org.openide.util.NbBundle.getMessage(AddEditHostDialog.class, "AddEditHostDialog.nameLabel.text")); // NOI18N + + validationLabel.setForeground(new java.awt.Color(204, 0, 51)); + validationLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP); + + okButton.setText(org.openide.util.NbBundle.getMessage(AddEditHostDialog.class, "AddEditHostDialog.okButton.text")); // NOI18N + okButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + okButtonActionPerformed(evt); + } + }); + + cancelButton.setText(org.openide.util.NbBundle.getMessage(AddEditHostDialog.class, "AddEditHostDialog.cancelButton.text")); // NOI18N + cancelButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cancelButtonActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(validationLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(inputTextField) + .addGroup(layout.createSequentialGroup() + .addComponent(nameLabel) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 222, Short.MAX_VALUE) + .addComponent(cancelButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(okButton))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(nameLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(inputTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(validationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 38, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(okButton) + .addComponent(cancelButton)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + + private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed + this.changed = true; + dispose(); + }//GEN-LAST:event_okButtonActionPerformed + + + private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed + this.changed = false; + dispose(); + }//GEN-LAST:event_cancelButtonActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JTextField inputTextField; + private javax.swing.JButton okButton; + private javax.swing.JLabel validationLabel; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties new file mode 100644 index 0000000000..1c2607cb95 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties @@ -0,0 +1,15 @@ +# To change this license header, choose License Headers in Project Properties. +# To change this template file, choose Tools | Templates +# and open the template in the editor. +ManageHostsDialog.hostDetailsLabel.text=Host Details +ManageHostsDialog.hostNameLabel.text=Host Name: +ManageHostsDialog.closeButton.text=Close +ManageHostsDialog.hostDescriptionTextArea.text=Hosts represent individual devices that may have multiple data sources. +ManageHostsDialog.hostListLabel.text=Hosts +ManageHostsDialog.newButton.text=New +ManageHostsDialog.editButton.text=Edit +ManageHostsDialog.deleteButton.text=Delete +AddEditHostDialog.nameLabel.text=Name: +AddEditHostDialog.okButton.text=OK +AddEditHostDialog.cancelButton.text=Cancel +AddEditHostDialog.inputTextField.text=jTextField1 diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED new file mode 100644 index 0000000000..bc9689aa11 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED @@ -0,0 +1,23 @@ +AddEditHostDialog_addHost_title=Add Host +AddEditHostDialog_editHost_title=Edit Host +AddEditHostDialog_getValidationMessage_onDuplicate=Another host already has the same name. Please choose a different name for this host. +AddEditHostDialog_getValidationMessage_onEmpty=Please provide some text for the host name. +AddEditHostDialog_getValidationMessage_sameAsOriginal=Please provide a new name for this host. +CTL_OpenHosts=Hosts +# To change this license header, choose License Headers in Project Properties. +# To change this template file, choose Tools | Templates +# and open the template in the editor. +ManageHostsDialog.hostDetailsLabel.text=Host Details +ManageHostsDialog.hostNameLabel.text=Host Name: +ManageHostsDialog.closeButton.text=Close +ManageHostsDialog.hostDescriptionTextArea.text=Hosts represent individual devices that may have multiple data sources. +ManageHostsDialog.hostListLabel.text=Hosts +ManageHostsDialog.newButton.text=New +ManageHostsDialog.editButton.text=Edit +ManageHostsDialog.deleteButton.text=Delete +AddEditHostDialog.nameLabel.text=Name: +AddEditHostDialog.okButton.text=OK +AddEditHostDialog.cancelButton.text=Cancel +AddEditHostDialog.inputTextField.text=jTextField1 +ManageHostsDialog_title_text=Manage Hosts +OpenHostsAction_displayName=Hosts diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.form b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.form new file mode 100644 index 0000000000..40ff2c13e5 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.form @@ -0,0 +1,359 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java new file mode 100644 index 0000000000..3da8f9a303 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java @@ -0,0 +1,428 @@ +/* + * Central Repository + * + * Copyright 2021 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.datamodel.hosts; + +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import java.util.stream.Collectors; +import javax.swing.JFrame; +import javax.swing.ListModel; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.Host; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Dialog for managing CRUD operations with hosts from the UI. + */ +@Messages({ + "ManageHostsDialog_title_text=Manage Hosts" +}) +public class ManageHostsDialog extends javax.swing.JDialog { + + private static final Logger logger = Logger.getLogger(ManageHostsDialog.class.getName()); + private static final long serialVersionUID = 1L; + + private List hostListData = Collections.emptyList(); + + /** + * + * @param parent + * @param modal + */ + public ManageHostsDialog(java.awt.Frame parent, boolean modal) { + super(parent, modal); + initComponents(); + refresh(); + + // refreshes UI when selection changes including button enabled state and data. + this.hostList.addListSelectionListener((evt) -> refreshComponents()); + } + + /** + * @return The currently selected host in the list or null if no host is + * selected. + */ + Host getSelectedHost() { + return this.hostList.getSelectedValue(); + } + + /** + * Shows add/edit dialog, and if a value is returned, creates a new Host. + */ + private void addHost() { + String newHostName = getAddEditDialogName(null); + if (newHostName != null) { + try { + Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().createHost(newHostName); + } catch (NoCurrentCaseException | TskCoreException e) { + logger.log(Level.WARNING, String.format("Unable to add new host '%s' at this time.", newHostName), e); + } + System.out.println(String.format("Should create a host of name %s", newHostName)); + refresh(); + } + } + + /** + * Deletes the selected host if possible. + * + * @param selectedHost + */ + private void deleteHost(Host selectedHost) { + if (selectedHost != null) { + System.out.println("Deleting: " + selectedHost); + refresh(); + } + } + + /** + * Shows add/edit dialog, and if a value is returned, creates a new Host. + * + * @param selectedHost The selected host. + */ + private void editHost(Host selectedHost) { + if (selectedHost != null) { + String newHostName = getAddEditDialogName(selectedHost); + if (newHostName != null) { + //TODO + logger.log(Level.SEVERE, String.format("This needs to edit host %d to change to %s.", selectedHost.getId(), newHostName)); + //Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().updateHost(selectedHost.getId(), newHostName); + refresh(); + } + } + } + + /** + * Shows the dialog to add or edit the name of a host. + * + * @param origValue The original values for the host or null if adding a + * host. + * @return The new name for the host or null if operation was cancelled. + */ + private String getAddEditDialogName(Host origValue) { + JFrame parent = (this.getRootPane() != null && this.getRootPane().getParent() instanceof JFrame) + ? (JFrame) this.getRootPane().getParent() + : null; + + AddEditHostDialog addEditDialog = new AddEditHostDialog(parent, hostListData, origValue); + if (addEditDialog.isChanged()) { + String newHostName = addEditDialog.getName(); + return newHostName; + } + + return null; + } + + /** + * Refreshes the data and ui components for this dialog. + */ + private void refresh() { + refreshData(); + refreshComponents(); + } + + /** + * Refreshes the data for this dialog and updates the host JList with the + * hosts. + */ + private void refreshData() { + Host selectedHost = hostList.getSelectedValue(); + Long selectedId = selectedHost == null ? null : selectedHost.getId(); + hostListData = getHostListData(); + hostList.setListData(hostListData.toArray(new Host[0])); + + if (selectedId != null) { + ListModel model = hostList.getModel(); + + for (int i = 0; i < model.getSize(); i++) { + Object o = model.getElementAt(i); + if (o instanceof Host && ((Host) o).getId() == selectedId) { + hostList.setSelectedIndex(i); + break; + } + } + } + } + + /** + * Retrieves the current list of hosts for the case. + * + * @return The list of hosts to be displayed in the list (sorted + * alphabetically). + */ + private List getHostListData() { + List toRet = null; + try { + toRet = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getHosts(); + } catch (TskCoreException | NoCurrentCaseException ex) { + logger.log(Level.WARNING, "There was an error while fetching hosts for current case.", ex); + } + return (toRet == null) + ? Collections.emptyList() + : toRet.stream() + .filter(h -> h != null) + .sorted((a, b) -> getNameOrEmpty(a).compareToIgnoreCase(getNameOrEmpty(b))) + .collect(Collectors.toList()); + } + + /** + * Returns the name of the host or an empty string if the host or name of + * host is null. + * + * @param h The host. + * @return The name of the host or empty string. + */ + private String getNameOrEmpty(Host h) { + return (h == null || h.getName() == null) ? "" : h.getName(); + } + + /** + * Refreshes component's enabled state and displayed host data. + */ + private void refreshComponents() { + Host selectedHost = this.hostList.getSelectedValue(); + boolean itemSelected = selectedHost != null; + this.editButton.setEnabled(itemSelected); + this.deleteButton.setEnabled(itemSelected); + String nameTextFieldStr = selectedHost != null && selectedHost.getName() != null ? selectedHost.getName() : ""; + this.hostNameTextField.setText(nameTextFieldStr); + + } + + /** + * 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() { + + javax.swing.JScrollPane manageHostsScrollPane = new javax.swing.JScrollPane(); + javax.swing.JPanel manageHostsPanel = new javax.swing.JPanel(); + javax.swing.JScrollPane hostListScrollPane = new javax.swing.JScrollPane(); + hostList = new javax.swing.JList<>(); + javax.swing.JScrollPane hostDescriptionScrollPane = new javax.swing.JScrollPane(); + hostDescriptionTextArea = new javax.swing.JTextArea(); + newButton = new javax.swing.JButton(); + deleteButton = new javax.swing.JButton(); + closeButton = new javax.swing.JButton(); + javax.swing.JLabel hostListLabel = new javax.swing.JLabel(); + javax.swing.JSeparator jSeparator1 = new javax.swing.JSeparator(); + javax.swing.JLabel hostNameLabel = new javax.swing.JLabel(); + hostNameTextField = new javax.swing.JTextField(); + editButton = new javax.swing.JButton(); + javax.swing.JLabel hostDetailsLabel = new javax.swing.JLabel(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setMinimumSize(new java.awt.Dimension(600, 450)); + + manageHostsScrollPane.setMinimumSize(new java.awt.Dimension(600, 450)); + manageHostsScrollPane.setPreferredSize(new java.awt.Dimension(600, 450)); + + manageHostsPanel.setPreferredSize(new java.awt.Dimension(527, 407)); + + hostList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); + hostListScrollPane.setViewportView(hostList); + + hostDescriptionTextArea.setEditable(false); + hostDescriptionTextArea.setBackground(new java.awt.Color(240, 240, 240)); + hostDescriptionTextArea.setColumns(20); + hostDescriptionTextArea.setLineWrap(true); + hostDescriptionTextArea.setRows(3); + hostDescriptionTextArea.setText(org.openide.util.NbBundle.getMessage(ManageHostsDialog.class, "ManageHostsDialog.hostDescriptionTextArea.text")); // NOI18N + hostDescriptionTextArea.setWrapStyleWord(true); + hostDescriptionScrollPane.setViewportView(hostDescriptionTextArea); + + newButton.setText(org.openide.util.NbBundle.getMessage(ManageHostsDialog.class, "ManageHostsDialog.newButton.text")); // NOI18N + newButton.setMargin(new java.awt.Insets(2, 6, 2, 6)); + newButton.setMaximumSize(new java.awt.Dimension(70, 23)); + newButton.setMinimumSize(new java.awt.Dimension(70, 23)); + newButton.setPreferredSize(new java.awt.Dimension(70, 23)); + newButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + newButtonActionPerformed(evt); + } + }); + + deleteButton.setText(org.openide.util.NbBundle.getMessage(ManageHostsDialog.class, "ManageHostsDialog.deleteButton.text")); // NOI18N + deleteButton.setMargin(new java.awt.Insets(2, 6, 2, 6)); + deleteButton.setMaximumSize(new java.awt.Dimension(70, 23)); + deleteButton.setMinimumSize(new java.awt.Dimension(70, 23)); + deleteButton.setPreferredSize(new java.awt.Dimension(70, 23)); + deleteButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + deleteButtonActionPerformed(evt); + } + }); + + closeButton.setText(org.openide.util.NbBundle.getMessage(ManageHostsDialog.class, "ManageHostsDialog.closeButton.text")); // NOI18N + closeButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + closeButtonActionPerformed(evt); + } + }); + + hostListLabel.setText(org.openide.util.NbBundle.getMessage(ManageHostsDialog.class, "ManageHostsDialog.hostListLabel.text")); // NOI18N + + jSeparator1.setOrientation(javax.swing.SwingConstants.VERTICAL); + + hostNameLabel.setText(org.openide.util.NbBundle.getMessage(ManageHostsDialog.class, "ManageHostsDialog.hostNameLabel.text")); // NOI18N + + hostNameTextField.setEditable(false); + + editButton.setText(org.openide.util.NbBundle.getMessage(ManageHostsDialog.class, "ManageHostsDialog.editButton.text")); // NOI18N + editButton.setMaximumSize(new java.awt.Dimension(70, 23)); + editButton.setMinimumSize(new java.awt.Dimension(70, 23)); + editButton.setPreferredSize(new java.awt.Dimension(70, 23)); + editButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + editButtonActionPerformed(evt); + } + }); + + hostDetailsLabel.setText(org.openide.util.NbBundle.getMessage(ManageHostsDialog.class, "ManageHostsDialog.hostDetailsLabel.text")); // NOI18N + + javax.swing.GroupLayout manageHostsPanelLayout = new javax.swing.GroupLayout(manageHostsPanel); + manageHostsPanel.setLayout(manageHostsPanelLayout); + manageHostsPanelLayout.setHorizontalGroup( + manageHostsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(manageHostsPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(manageHostsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(hostDescriptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(hostListLabel) + .addGroup(manageHostsPanelLayout.createSequentialGroup() + .addComponent(newButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(editButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(deleteButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(hostListScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 224, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(manageHostsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(manageHostsPanelLayout.createSequentialGroup() + .addGroup(manageHostsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(manageHostsPanelLayout.createSequentialGroup() + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(closeButton)) + .addGroup(manageHostsPanelLayout.createSequentialGroup() + .addGap(29, 29, 29) + .addComponent(hostNameLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(hostNameTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 79, Short.MAX_VALUE))) + .addContainerGap()) + .addGroup(manageHostsPanelLayout.createSequentialGroup() + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(hostDetailsLabel) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) + ); + manageHostsPanelLayout.setVerticalGroup( + manageHostsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(manageHostsPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(manageHostsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(manageHostsPanelLayout.createSequentialGroup() + .addComponent(hostDetailsLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(manageHostsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(hostNameLabel) + .addComponent(hostNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(closeButton)) + .addComponent(jSeparator1) + .addGroup(manageHostsPanelLayout.createSequentialGroup() + .addComponent(hostDescriptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(hostListLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(hostListScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 325, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(manageHostsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(newButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(deleteButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(editButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))) + .addContainerGap()) + ); + + java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("com/mycompany/hostsmanagement/Bundle"); // NOI18N + newButton.getAccessibleContext().setAccessibleName(bundle.getString("ManageHostsDialog.newButton.text")); // NOI18N + deleteButton.getAccessibleContext().setAccessibleName(bundle.getString("ManageHostsDialog.deleteButton.text")); // NOI18N + closeButton.getAccessibleContext().setAccessibleName(bundle.getString("ManageHostsDialog.closeButton.text")); // NOI18N + hostListLabel.getAccessibleContext().setAccessibleName(bundle.getString("ManageHostsDialog.hostListLabel.text")); // NOI18N + hostNameLabel.getAccessibleContext().setAccessibleName(bundle.getString("ManageHostsDialog.hostNameLabel.text")); // NOI18N + editButton.getAccessibleContext().setAccessibleName(bundle.getString("ManageHostsDialog.editButton.text")); // NOI18N + hostDetailsLabel.getAccessibleContext().setAccessibleName(bundle.getString("ManageHostsDialog.hostDetailsLabel.text")); // NOI18N + + manageHostsScrollPane.setViewportView(manageHostsPanel); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(manageHostsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(manageHostsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + + private void newButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newButtonActionPerformed + addHost(); + }//GEN-LAST:event_newButtonActionPerformed + + private void deleteButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteButtonActionPerformed + Host host = this.hostList.getSelectedValue(); + if (host != null) { + deleteHost(host); + } + }//GEN-LAST:event_deleteButtonActionPerformed + + private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed + dispose(); + }//GEN-LAST:event_closeButtonActionPerformed + + private void editButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editButtonActionPerformed + Host host = this.hostList.getSelectedValue(); + if (host != null) { + editHost(host); + } + }//GEN-LAST:event_editButtonActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton closeButton; + private javax.swing.JButton deleteButton; + private javax.swing.JButton editButton; + private javax.swing.JTextArea hostDescriptionTextArea; + private javax.swing.JList hostList; + private javax.swing.JTextField hostNameTextField; + private javax.swing.JButton newButton; + // End of variables declaration//GEN-END:variables +} From fd9265ed7f52d72374773ff92e3878a238e93300 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 10 Feb 2021 09:31:13 -0500 Subject: [PATCH 03/42] fixes --- Core/src/org/sleuthkit/autopsy/core/layer.xml | 6 +- .../datamodel/hosts/AddEditHostDialog.form | 20 ++-- .../datamodel/hosts/AddEditHostDialog.java | 16 +-- .../datamodel/hosts/Bundle.properties-MERGED | 2 +- .../datamodel/hosts/ManageHostsDialog.form | 18 ++-- .../datamodel/hosts/ManageHostsDialog.java | 98 ++++++++++++++----- .../datamodel/hosts/OpenHostsAction.java | 22 ++--- 7 files changed, 119 insertions(+), 63 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/core/layer.xml b/Core/src/org/sleuthkit/autopsy/core/layer.xml index d2805c606b..923e8f5c5e 100644 --- a/Core/src/org/sleuthkit/autopsy/core/layer.xml +++ b/Core/src/org/sleuthkit/autopsy/core/layer.xml @@ -165,7 +165,11 @@
- + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.form b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.form index 3ffa0901da..1b4dfdf194 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.form +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.form @@ -33,7 +33,7 @@ - + @@ -50,9 +50,9 @@ - - - + + + @@ -66,14 +66,14 @@ - + - + @@ -83,8 +83,8 @@ - - + + @@ -92,7 +92,7 @@ - + @@ -102,7 +102,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java index 70041e1105..fe7277d562 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.datamodel.hosts; +import java.awt.Color; import org.sleuthkit.datamodel.Host; import java.util.Collection; import java.util.Set; @@ -94,7 +95,8 @@ class AddEditHostDialog extends javax.swing.JDialog { } /** - * @return The current string value for the name in the input field. + * @return The string value for the name in the input field if Ok pressed or + * null if not. */ String getValue() { return inputTextField.getText(); @@ -137,7 +139,7 @@ class AddEditHostDialog extends javax.swing.JDialog { @Messages({ "AddEditHostDialog_getValidationMessage_onEmpty=Please provide some text for the host name.", "AddEditHostDialog_getValidationMessage_sameAsOriginal=Please provide a new name for this host.", - "AddEditHostDialog_getValidationMessage_onDuplicate=Another host already has the same name. Please choose a different name for this host.",}) + "AddEditHostDialog_getValidationMessage_onDuplicate=Another host already has the same name. Please choose a different name.",}) private String getValidationMessage(String name) { if (name == null || name.isEmpty()) { return Bundle.AddEditHostDialog_getValidationMessage_onEmpty(); @@ -171,7 +173,7 @@ class AddEditHostDialog extends javax.swing.JDialog { nameLabel.setText(org.openide.util.NbBundle.getMessage(AddEditHostDialog.class, "AddEditHostDialog.nameLabel.text")); // NOI18N - validationLabel.setForeground(new java.awt.Color(204, 0, 51)); + validationLabel.setForeground(Color.RED); validationLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP); okButton.setText(org.openide.util.NbBundle.getMessage(AddEditHostDialog.class, "AddEditHostDialog.okButton.text")); // NOI18N @@ -201,7 +203,7 @@ class AddEditHostDialog extends javax.swing.JDialog { .addComponent(nameLabel) .addGap(0, 0, Short.MAX_VALUE)) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGap(0, 222, Short.MAX_VALUE) + .addGap(0, 282, Short.MAX_VALUE) .addComponent(cancelButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(okButton))) @@ -214,9 +216,9 @@ class AddEditHostDialog extends javax.swing.JDialog { .addComponent(nameLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(inputTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(validationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 38, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(validationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(okButton) .addComponent(cancelButton)) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED index bc9689aa11..827aa5631d 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED @@ -1,6 +1,6 @@ AddEditHostDialog_addHost_title=Add Host AddEditHostDialog_editHost_title=Edit Host -AddEditHostDialog_getValidationMessage_onDuplicate=Another host already has the same name. Please choose a different name for this host. +AddEditHostDialog_getValidationMessage_onDuplicate=Another host already has the same name. Please choose a different name. AddEditHostDialog_getValidationMessage_onEmpty=Please provide some text for the host name. AddEditHostDialog_getValidationMessage_sameAsOriginal=Please provide a new name for this host. CTL_OpenHosts=Hosts diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.form b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.form index 40ff2c13e5..f01b0cbc8c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.form +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.form @@ -166,7 +166,7 @@ - + @@ -189,7 +189,7 @@ - + @@ -216,7 +216,7 @@ - + @@ -243,7 +243,7 @@ - + @@ -258,7 +258,7 @@ - + @@ -273,7 +273,7 @@ - + @@ -298,7 +298,7 @@ - + @@ -328,7 +328,7 @@ - + @@ -343,7 +343,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java index 3da8f9a303..a837c99539 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java @@ -20,6 +20,8 @@ package org.sleuthkit.autopsy.datamodel.hosts; import java.util.Collections; import java.util.List; +import java.util.Objects; +import java.util.Vector; import java.util.logging.Level; import java.util.stream.Collectors; import javax.swing.JFrame; @@ -38,19 +40,62 @@ import org.sleuthkit.datamodel.TskCoreException; "ManageHostsDialog_title_text=Manage Hosts" }) public class ManageHostsDialog extends javax.swing.JDialog { + private static class HostListItem { + private final Host host; + HostListItem(Host host) { + this.host = host; + } + + Host getHost() { + return host; + } + + @Override + public String toString() { + return host == null ? "" : host.getName(); + } + + @Override + public int hashCode() { + int hash = 5; + hash = 89 * hash + Objects.hashCode(this.host == null ? 0 : this.host.getId()); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final HostListItem other = (HostListItem) obj; + if (this.host == null || other.getHost() == null) { + return this.host == null && other.getHost() == null; + } + + return this.host.getId() == other.getHost().getId(); + } + + + } + private static final Logger logger = Logger.getLogger(ManageHostsDialog.class.getName()); private static final long serialVersionUID = 1L; private List hostListData = Collections.emptyList(); /** - * - * @param parent - * @param modal + * Main constructor. + * @param parent The parent frame. */ - public ManageHostsDialog(java.awt.Frame parent, boolean modal) { - super(parent, modal); + public ManageHostsDialog(java.awt.Frame parent) { + super(parent, Bundle.ManageHostsDialog_title_text(), true); initComponents(); refresh(); @@ -63,7 +108,7 @@ public class ManageHostsDialog extends javax.swing.JDialog { * selected. */ Host getSelectedHost() { - return this.hostList.getSelectedValue(); + return (hostList.getSelectedValue() == null) ? null : hostList.getSelectedValue().getHost(); } /** @@ -77,7 +122,6 @@ public class ManageHostsDialog extends javax.swing.JDialog { } catch (NoCurrentCaseException | TskCoreException e) { logger.log(Level.WARNING, String.format("Unable to add new host '%s' at this time.", newHostName), e); } - System.out.println(String.format("Should create a host of name %s", newHostName)); refresh(); } } @@ -105,7 +149,7 @@ public class ManageHostsDialog extends javax.swing.JDialog { if (newHostName != null) { //TODO logger.log(Level.SEVERE, String.format("This needs to edit host %d to change to %s.", selectedHost.getId(), newHostName)); - //Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().updateHost(selectedHost.getId(), newHostName); + //Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().updateHostName(selectedHost.getId(), newHostName); refresh(); } } @@ -124,8 +168,13 @@ public class ManageHostsDialog extends javax.swing.JDialog { : null; AddEditHostDialog addEditDialog = new AddEditHostDialog(parent, hostListData, origValue); + addEditDialog.setResizable(false); + addEditDialog.setLocationRelativeTo(parent); + addEditDialog.setVisible(true); + addEditDialog.toFront(); + if (addEditDialog.isChanged()) { - String newHostName = addEditDialog.getName(); + String newHostName = addEditDialog.getValue(); return newHostName; } @@ -145,13 +194,18 @@ public class ManageHostsDialog extends javax.swing.JDialog { * hosts. */ private void refreshData() { - Host selectedHost = hostList.getSelectedValue(); - Long selectedId = selectedHost == null ? null : selectedHost.getId(); + HostListItem selectedItem = hostList.getSelectedValue(); + Long selectedId = selectedItem == null || selectedItem.getHost() == null ? null : selectedItem.getHost().getId(); hostListData = getHostListData(); - hostList.setListData(hostListData.toArray(new Host[0])); + + Vector jlistData = hostListData.stream() + .map(HostListItem::new) + .collect(Collectors.toCollection(Vector::new)); + + hostList.setListData(jlistData); if (selectedId != null) { - ListModel model = hostList.getModel(); + ListModel model = hostList.getModel(); for (int i = 0; i < model.getSize(); i++) { Object o = model.getElementAt(i); @@ -199,7 +253,7 @@ public class ManageHostsDialog extends javax.swing.JDialog { * Refreshes component's enabled state and displayed host data. */ private void refreshComponents() { - Host selectedHost = this.hostList.getSelectedValue(); + Host selectedHost = getSelectedHost(); boolean itemSelected = selectedHost != null; this.editButton.setEnabled(itemSelected); this.deleteButton.setEnabled(itemSelected); @@ -365,7 +419,7 @@ public class ManageHostsDialog extends javax.swing.JDialog { .addContainerGap()) ); - java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("com/mycompany/hostsmanagement/Bundle"); // NOI18N + java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("org/sleuthkit/autopsy/datamodel/hosts/Bundle"); // NOI18N newButton.getAccessibleContext().setAccessibleName(bundle.getString("ManageHostsDialog.newButton.text")); // NOI18N deleteButton.getAccessibleContext().setAccessibleName(bundle.getString("ManageHostsDialog.deleteButton.text")); // NOI18N closeButton.getAccessibleContext().setAccessibleName(bundle.getString("ManageHostsDialog.closeButton.text")); // NOI18N @@ -399,9 +453,9 @@ public class ManageHostsDialog extends javax.swing.JDialog { }//GEN-LAST:event_newButtonActionPerformed private void deleteButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteButtonActionPerformed - Host host = this.hostList.getSelectedValue(); - if (host != null) { - deleteHost(host); + HostListItem listItem = this.hostList.getSelectedValue(); + if (listItem != null && listItem.getHost() != null) { + deleteHost(listItem.getHost()); } }//GEN-LAST:event_deleteButtonActionPerformed @@ -410,9 +464,9 @@ public class ManageHostsDialog extends javax.swing.JDialog { }//GEN-LAST:event_closeButtonActionPerformed private void editButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editButtonActionPerformed - Host host = this.hostList.getSelectedValue(); - if (host != null) { - editHost(host); + HostListItem listItem = this.hostList.getSelectedValue(); + if (listItem != null && listItem.getHost() != null) { + editHost(listItem.getHost()); } }//GEN-LAST:event_editButtonActionPerformed @@ -421,7 +475,7 @@ public class ManageHostsDialog extends javax.swing.JDialog { private javax.swing.JButton deleteButton; private javax.swing.JButton editButton; private javax.swing.JTextArea hostDescriptionTextArea; - private javax.swing.JList hostList; + private javax.swing.JList hostList; private javax.swing.JTextField hostNameTextField; private javax.swing.JButton newButton; // End of variables declaration//GEN-END:variables diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/OpenHostsAction.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/OpenHostsAction.java index fbfb14be59..62bf32aeda 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/OpenHostsAction.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/OpenHostsAction.java @@ -23,8 +23,6 @@ import java.beans.PropertyChangeEvent; import java.util.EnumSet; import javax.swing.Action; import org.openide.awt.ActionID; -import org.openide.awt.ActionReference; -import org.openide.awt.ActionReferences; import org.openide.awt.ActionRegistration; import org.openide.util.HelpCtx; import org.openide.util.NbBundle; @@ -32,39 +30,37 @@ import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.coreutils.ThreadConfined; /** * An Action that opens the Host Management window. */ @ActionID(category = "Case", id = "org.sleuthkit.autopsy.datamodel.hosts.OpenHostsAction") @ActionRegistration(displayName = "#CTL_OpenHosts", lazy = false) -@ActionReferences(value = { - @ActionReference(path = "Toolbars/Case", position = 99, separatorBefore = 98) -}) @Messages({ - "CTL_OpenHosts=Hosts" -}) + "CTL_OpenHosts=Hosts",}) public final class OpenHostsAction extends CallableSystemAction { private static final long serialVersionUID = 1L; - public OpenHostsAction() { + /** + * Main constructor. + */ + OpenHostsAction() { putValue(Action.NAME, Bundle.CTL_OpenHosts()); this.setEnabled(false); Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> { setEnabled(null != evt.getNewValue()); }); - -// menuItem = super.getMenuPresenter(); } @Override - @ThreadConfined(type = ThreadConfined.ThreadType.AWT) public void performAction() { Frame parent = WindowManager.getDefault().getMainWindow(); - ManageHostsDialog dialog = new ManageHostsDialog(parent, true); + ManageHostsDialog dialog = new ManageHostsDialog(parent); + dialog.setResizable(false); + dialog.setLocationRelativeTo(parent); dialog.setVisible(true); + dialog.toFront(); } @Override From 9d917af21e6e0c1f09968ad37cbc099b04ef8cfe Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 12 Feb 2021 14:43:13 -0500 Subject: [PATCH 04/42] updates for TSK api --- .../datamodel/hosts/AddEditHostDialog.java | 5 + .../datamodel/hosts/ManageHostsDialog.java | 142 ++++++++++++------ 2 files changed, 101 insertions(+), 46 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java index fe7277d562..cc2bbec5c5 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java @@ -41,6 +41,11 @@ class AddEditHostDialog extends javax.swing.JDialog { private final Set hostNamesUpper; private final Host initialHost; + /** + * Main constructor. + * @param parent The parent frame for this dialog. + * @param currentHosts The current set of hosts in the case. + */ AddEditHostDialog(java.awt.Frame parent, Collection currentHosts) { this(parent, currentHosts, null); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java index a837c99539..fe4e68bc4e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java @@ -18,19 +18,25 @@ */ package org.sleuthkit.autopsy.datamodel.hosts; +import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Vector; import java.util.logging.Level; import java.util.stream.Collectors; import javax.swing.JFrame; import javax.swing.ListModel; +import org.apache.commons.collections4.CollectionUtils; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.Host; +import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; /** @@ -40,16 +46,38 @@ import org.sleuthkit.datamodel.TskCoreException; "ManageHostsDialog_title_text=Manage Hosts" }) public class ManageHostsDialog extends javax.swing.JDialog { - private static class HostListItem { - private final Host host; - HostListItem(Host host) { + /** + * List item to be used with jlist. + */ + private static class HostListItem { + + private final Host host; + private final List dataSources; + + /** + * Main constructor. + * @param host The host. + * @param dataSources The data sources that are children of this host. + */ + HostListItem(Host host, List dataSources) { this.host = host; + this.dataSources = dataSources; } + /** + * @return The host. + */ Host getHost() { return host; } + + /** + * @return The data sources associated with this host. + */ + List getDataSources() { + return dataSources; + } @Override public String toString() { @@ -78,20 +106,20 @@ public class ManageHostsDialog extends javax.swing.JDialog { if (this.host == null || other.getHost() == null) { return this.host == null && other.getHost() == null; } - + return this.host.getId() == other.getHost().getId(); } - - + } - + private static final Logger logger = Logger.getLogger(ManageHostsDialog.class.getName()); private static final long serialVersionUID = 1L; - - private List hostListData = Collections.emptyList(); + + private Map> hostChildrenMap = Collections.emptyMap(); /** * Main constructor. + * * @param parent The parent frame. */ public ManageHostsDialog(java.awt.Frame parent) { @@ -132,8 +160,12 @@ public class ManageHostsDialog extends javax.swing.JDialog { * @param selectedHost */ private void deleteHost(Host selectedHost) { - if (selectedHost != null) { - System.out.println("Deleting: " + selectedHost); + if (selectedHost != null && selectedHost.getName() != null) { + try { + Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().deleteHost(selectedHost.getName()); + } catch (NoCurrentCaseException | TskCoreException e) { + logger.log(Level.WARNING, String.format("Unable to delete host '%s' at this time.", selectedHost.getName()), e); + } refresh(); } } @@ -147,9 +179,12 @@ public class ManageHostsDialog extends javax.swing.JDialog { if (selectedHost != null) { String newHostName = getAddEditDialogName(selectedHost); if (newHostName != null) { - //TODO - logger.log(Level.SEVERE, String.format("This needs to edit host %d to change to %s.", selectedHost.getId(), newHostName)); - //Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().updateHostName(selectedHost.getId(), newHostName); + selectedHost.setName(newHostName); + try { + Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().updateHost(selectedHost); + } catch (NoCurrentCaseException | TskCoreException e) { + logger.log(Level.WARNING, String.format("Unable to update host '%s' with id: %d at this time.", selectedHost.getName(), selectedHost.getId()), e); + } refresh(); } } @@ -167,12 +202,12 @@ public class ManageHostsDialog extends javax.swing.JDialog { ? (JFrame) this.getRootPane().getParent() : null; - AddEditHostDialog addEditDialog = new AddEditHostDialog(parent, hostListData, origValue); + AddEditHostDialog addEditDialog = new AddEditHostDialog(parent, hostChildrenMap.keySet(), origValue); addEditDialog.setResizable(false); addEditDialog.setLocationRelativeTo(parent); addEditDialog.setVisible(true); addEditDialog.toFront(); - + if (addEditDialog.isChanged()) { String newHostName = addEditDialog.getValue(); return newHostName; @@ -196,12 +231,13 @@ public class ManageHostsDialog extends javax.swing.JDialog { private void refreshData() { HostListItem selectedItem = hostList.getSelectedValue(); Long selectedId = selectedItem == null || selectedItem.getHost() == null ? null : selectedItem.getHost().getId(); - hostListData = getHostListData(); - - Vector jlistData = hostListData.stream() - .map(HostListItem::new) + hostChildrenMap = getHostListData(); + + Vector jlistData = hostChildrenMap.entrySet().stream() + .sorted((a, b) -> getNameOrEmpty(a.getKey()).compareTo(getNameOrEmpty(b.getKey()))) + .map(entry -> new HostListItem(entry.getKey(), entry.getValue())) .collect(Collectors.toCollection(Vector::new)); - + hostList.setListData(jlistData); if (selectedId != null) { @@ -217,27 +253,6 @@ public class ManageHostsDialog extends javax.swing.JDialog { } } - /** - * Retrieves the current list of hosts for the case. - * - * @return The list of hosts to be displayed in the list (sorted - * alphabetically). - */ - private List getHostListData() { - List toRet = null; - try { - toRet = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getHosts(); - } catch (TskCoreException | NoCurrentCaseException ex) { - logger.log(Level.WARNING, "There was an error while fetching hosts for current case.", ex); - } - return (toRet == null) - ? Collections.emptyList() - : toRet.stream() - .filter(h -> h != null) - .sorted((a, b) -> getNameOrEmpty(a).compareToIgnoreCase(getNameOrEmpty(b))) - .collect(Collectors.toList()); - } - /** * Returns the name of the host or an empty string if the host or name of * host is null. @@ -249,14 +264,49 @@ public class ManageHostsDialog extends javax.swing.JDialog { return (h == null || h.getName() == null) ? "" : h.getName(); } + /** + * Retrieves the current list of hosts for the case. + * + * @return The list of hosts to be displayed in the list (sorted + * alphabetically). + */ + private Map> getHostListData() { + Map> hostMapping = new HashMap<>(); + try { + SleuthkitCase curCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + List hosts = curCase.getHostManager().getHosts(); + List dataSources = curCase.getDataSources(); + + if (dataSources != null) { + for (DataSource ds : dataSources) { + List hostDataSources = hostMapping.computeIfAbsent(ds.getHost(), (d) -> new ArrayList<>()); + hostDataSources.add(ds); + } + + } + + if (hosts != null) { + for (Host host : hosts) { + hostMapping.putIfAbsent(host, Collections.emptyList()); + } + } + + } catch (TskCoreException | NoCurrentCaseException ex) { + logger.log(Level.WARNING, "There was an error while fetching hosts for current case.", ex); + } + + return hostMapping; + } + /** * Refreshes component's enabled state and displayed host data. */ private void refreshComponents() { - Host selectedHost = getSelectedHost(); - boolean itemSelected = selectedHost != null; - this.editButton.setEnabled(itemSelected); - this.deleteButton.setEnabled(itemSelected); + HostListItem selectedItem = hostList.getSelectedValue(); + Host selectedHost = selectedItem == null ? null : selectedItem.getHost(); + List dataSources = selectedItem == null ? null : selectedItem.getDataSources(); + this.editButton.setEnabled(selectedHost != null); + this.deleteButton.setEnabled(selectedHost != null && CollectionUtils.isEmpty(dataSources)); String nameTextFieldStr = selectedHost != null && selectedHost.getName() != null ? selectedHost.getName() : ""; this.hostNameTextField.setText(nameTextFieldStr); From c8de7002f92243c4052dab52ddb88bafc28ab613 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 12 Feb 2021 15:35:58 -0500 Subject: [PATCH 05/42] bug fixes --- .../autopsy/datamodel/hosts/AddEditHostDialog.form | 12 ++++++------ .../autopsy/datamodel/hosts/AddEditHostDialog.java | 14 +++++++------- .../datamodel/hosts/Bundle.properties-MERGED | 2 +- .../autopsy/datamodel/hosts/ManageHostsDialog.java | 3 ++- .../autopsy/datamodel/hosts/OpenHostsAction.java | 2 +- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.form b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.form index 1b4dfdf194..36ed76d8f5 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.form +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.form @@ -33,10 +33,10 @@ - - - + + + @@ -53,9 +53,9 @@ - - - + + + diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java index cc2bbec5c5..0b704649fd 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java @@ -208,10 +208,10 @@ class AddEditHostDialog extends javax.swing.JDialog { .addComponent(nameLabel) .addGap(0, 0, Short.MAX_VALUE)) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGap(0, 282, Short.MAX_VALUE) - .addComponent(cancelButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(okButton))) + .addGap(0, 288, Short.MAX_VALUE) + .addComponent(okButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cancelButton))) .addContainerGap()) ); layout.setVerticalGroup( @@ -224,9 +224,9 @@ class AddEditHostDialog extends javax.swing.JDialog { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(validationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(okButton) - .addComponent(cancelButton)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cancelButton) + .addComponent(okButton)) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED index 827aa5631d..58182832d1 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED @@ -3,7 +3,7 @@ AddEditHostDialog_editHost_title=Edit Host AddEditHostDialog_getValidationMessage_onDuplicate=Another host already has the same name. Please choose a different name. AddEditHostDialog_getValidationMessage_onEmpty=Please provide some text for the host name. AddEditHostDialog_getValidationMessage_sameAsOriginal=Please provide a new name for this host. -CTL_OpenHosts=Hosts +CTL_OpenHosts=Manage Hosts # To change this license header, choose License Headers in Project Properties. # To change this template file, choose Tools | Templates # and open the template in the editor. diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java index fe4e68bc4e..717a5752d0 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java @@ -57,6 +57,7 @@ public class ManageHostsDialog extends javax.swing.JDialog { /** * Main constructor. + * * @param host The host. * @param dataSources The data sources that are children of this host. */ @@ -71,7 +72,7 @@ public class ManageHostsDialog extends javax.swing.JDialog { Host getHost() { return host; } - + /** * @return The data sources associated with this host. */ diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/OpenHostsAction.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/OpenHostsAction.java index 62bf32aeda..6c0139a908 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/OpenHostsAction.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/OpenHostsAction.java @@ -37,7 +37,7 @@ import org.sleuthkit.autopsy.casemodule.Case; @ActionID(category = "Case", id = "org.sleuthkit.autopsy.datamodel.hosts.OpenHostsAction") @ActionRegistration(displayName = "#CTL_OpenHosts", lazy = false) @Messages({ - "CTL_OpenHosts=Hosts",}) + "CTL_OpenHosts=Manage Hosts",}) public final class OpenHostsAction extends CallableSystemAction { private static final long serialVersionUID = 1L; From b90f3d7b961045d5ac3d7bef525e1c2d1b2d63a6 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 16 Feb 2021 10:25:25 -0500 Subject: [PATCH 06/42] beginnings of wizard select host --- ...AddImageWizardDataSourceSettingsVisual.form | 13 ++----------- ...AddImageWizardDataSourceSettingsVisual.java | 15 ++++----------- .../autopsy/datamodel/hosts/Bundle.properties | 3 +++ .../datamodel/hosts/Bundle.properties-MERGED | 4 ++++ .../datamodel/hosts/ManageHostsDialog.java | 18 ++++++++++++++++++ .../leappanalyzers/Bundle.properties-MERGED | 4 ++-- .../keywordsearch/Bundle.properties-MERGED | 4 ++-- .../netbeans/core/startup/Bundle.properties | 2 +- .../core/windows/view/ui/Bundle.properties | 2 +- 9 files changed, 37 insertions(+), 28 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.form b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.form index d8ab744f34..22de08fe49 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.form @@ -41,17 +41,8 @@ - - - - - - - - - - - + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.java index d44b3ed522..e5186addc7 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.java @@ -33,6 +33,7 @@ import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.hosts.SelectHostPanel; /** * visual component for the first panel of add image wizard. Allows the user to @@ -46,6 +47,7 @@ final class AddImageWizardDataSourceSettingsVisual extends JPanel { private final AddImageWizardDataSourceSettingsPanel wizPanel; private JPanel currentPanel; + private final SelectHostPanel selectHostPanel = new SelectHostPanel(); private final Map datasourceProcessorsMap = new HashMap<>(); @@ -101,6 +103,7 @@ final class AddImageWizardDataSourceSettingsVisual extends JPanel { currentPanel = panel; typePanel.removeAll(); typePanel.add(currentPanel, BorderLayout.CENTER); + typePanel.add(selectHostPanel, BorderLayout.SOUTH); typePanel.validate(); typePanel.repaint(); currentPanel.addPropertyChangeListener(new PropertyChangeListener() { @@ -156,17 +159,7 @@ final class AddImageWizardDataSourceSettingsVisual extends JPanel { typePanel.setMinimumSize(new java.awt.Dimension(0, 65)); typePanel.setPreferredSize(new java.awt.Dimension(521, 65)); - - javax.swing.GroupLayout typePanelLayout = new javax.swing.GroupLayout(typePanel); - typePanel.setLayout(typePanelLayout); - typePanelLayout.setHorizontalGroup( - typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 588, Short.MAX_VALUE) - ); - typePanelLayout.setVerticalGroup( - typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 328, Short.MAX_VALUE) - ); + typePanel.setLayout(new java.awt.BorderLayout(0, 20)); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties index 1c2607cb95..e97e35e77b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties @@ -13,3 +13,6 @@ AddEditHostDialog.nameLabel.text=Name: AddEditHostDialog.okButton.text=OK AddEditHostDialog.cancelButton.text=Cancel AddEditHostDialog.inputTextField.text=jTextField1 +SelectHostPanel.title=Host +SelectHostPanel.lbHostNameLabel.text=Host to which this data source belongs: +SelectHostPanel.bnManageHosts.text=Manage Hosts diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED index 58182832d1..2df759ebfb 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED @@ -21,3 +21,7 @@ AddEditHostDialog.cancelButton.text=Cancel AddEditHostDialog.inputTextField.text=jTextField1 ManageHostsDialog_title_text=Manage Hosts OpenHostsAction_displayName=Hosts +SelectHostPanel.title=Host +SelectHostPanel.lbHostNameLabel.text=Host to which this data source belongs: +SelectHostPanel.bnManageHosts.text=Manage Hosts +SelectHostPanel_HostCbItem_defaultHost=Default diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java index 717a5752d0..1cc95eefda 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.datamodel.hosts; +import java.awt.Dialog; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -125,6 +126,23 @@ public class ManageHostsDialog extends javax.swing.JDialog { */ public ManageHostsDialog(java.awt.Frame parent) { super(parent, Bundle.ManageHostsDialog_title_text(), true); + init(); + } + + /** + * Main constructor. + * + * @param parent The parent dialog. + */ + public ManageHostsDialog(Dialog parent) { + super(parent, Bundle.ManageHostsDialog_title_text(), true); + init(); + } + + /** + * Initializes components, loads host data, and sets up list listener. + */ + private void init() { initComponents(); refresh(); diff --git a/Core/src/org/sleuthkit/autopsy/modules/leappanalyzers/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/leappanalyzers/Bundle.properties-MERGED index 123986b7d6..f62ee3a1b2 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/leappanalyzers/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/leappanalyzers/Bundle.properties-MERGED @@ -22,12 +22,12 @@ ILeappAnalyzerIngestModule.init.exception.msg=Unable to find {0}. ILeappAnalyzerIngestModule.processing.file=Processing file {0} ILeappAnalyzerIngestModule.parsing.file=Parsing file {0} ILeappAnalyzerIngestModule.processing.filesystem=Processing filesystem -IleappAnalyzerIngestModule.not.64.bit.os=iLeapp will not run on 32bit operating system +IleappAnalyzerIngestModule.not.64.bit.os=iLeapp will not run on a 32bit operating system ALeappAnalyzerIngestModule.init.exception.msg=Unable to find {0}. ALeappAnalyzerIngestModule.processing.file=Processing file {0} ALeappAnalyzerIngestModule.parsing.file=Parsing file {0} ALeappAnalyzerIngestModule.processing.filesystem=Processing filesystem -AleappAnalyzerIngestModule.not.64.bit.os=aLeapp will not run on 32bit operating system +AleappAnalyzerIngestModule.not.64.bit.os=aLeapp will not run on a 32bit operating system ILeappAnalyzerIngestModule.report.name=iLeapp Html Report ILeappAnalyzerIngestModule.requires.windows=iLeapp module requires windows. ILeappAnalyzerIngestModule.running.iLeapp=Running iLeapp diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties-MERGED b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties-MERGED index 02244f9477..5d6db8703e 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties-MERGED +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties-MERGED @@ -37,7 +37,7 @@ KeywordSearchResultFactory.createNodeForKey.noResultsFound.text=No results found KeywordSearchResultFactory.query.exception.msg=Could not perform the query OpenIDE-Module-Display-Category=Ingest Module -OpenIDE-Module-Long-Description=Keyword Search ingest module.\n\nThe module indexes files found in the disk image at ingest time.\nIt then periodically runs the search on the indexed files using one or more keyword lists (containing pure words and/or regular expressions) and posts results.\n\nThe module also contains additional tools integrated in the main GUI, such as keyword list configuration, keyword search bar in the top-right corner, extracted text viewer and search results viewer showing highlighted keywords found. +OpenIDE-Module-Long-Description=Keyword Search ingest module.\n\nThe module indexes files found in the disk image at ingest time.\nIt then periodically runs the search on the indexed files using one or more keyword lists (containing pure words and/or regular expressions) and posts results.\n\n\The module also contains additional tools integrated in the main GUI, such as keyword list configuration, keyword search bar in the top-right corner, extracted text viewer and search results viewer showing highlighted keywords found. OpenIDE-Module-Name=KeywordSearch OptionsCategory_Name_KeywordSearchOptions=Keyword Search OptionsCategory_Keywords_KeywordSearchOptions=Keyword Search @@ -232,7 +232,7 @@ Server.query.exception.msg=Error running query: {0} Server.query2.exception.msg=Error running query: {0} Server.queryTerms.exception.msg=Error running terms query: {0} Server.connect.exception.msg=Failed to connect to Solr server: {0} -Server.openCore.exception.msg=Keyword search service not yet running +Server.openCore.exception.msg=Local keyword search service not yet running Server.openCore.exception.cantOpen.msg=Could not create or open index Server.openCore.exception.noIndexDir.msg=Index directory could not be created or is missing Server.request.exception.exception.msg=Could not issue Solr request 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 c2df473fe0..587ebbad92 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 -#Mon, 25 Jan 2021 12:41:22 -0500 +#Tue, 16 Feb 2021 09:38:17 -0500 LBL_splash_window_title=Starting Autopsy SPLASH_HEIGHT=314 SPLASH_WIDTH=538 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 d519362703..6dd32087a9 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 -#Mon, 25 Jan 2021 12:41:22 -0500 +#Tue, 16 Feb 2021 09:38:17 -0500 CTL_MainWindow_Title=Autopsy 4.18.0 CTL_MainWindow_Title_No_Project=Autopsy 4.18.0 From cc629ef1962a44a55b1655b9f8275789d3f9acbd Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 16 Feb 2021 10:25:47 -0500 Subject: [PATCH 07/42] beginnings of wizard select host --- .../datamodel/hosts/SelectHostPanel.form | 119 +++++++++++++ .../datamodel/hosts/SelectHostPanel.java | 159 ++++++++++++++++++ 2 files changed, 278 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form new file mode 100644 index 0000000000..ef94dbc5e2 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form @@ -0,0 +1,119 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java new file mode 100644 index 0000000000..672782ab3c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java @@ -0,0 +1,159 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.datamodel.hosts; + +import java.awt.Dialog; +import javax.swing.SwingUtilities; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.datamodel.Host; + +/** + * + * @author gregd + */ +public class SelectHostPanel extends javax.swing.JPanel { + + @Messages({ + "SelectHostPanel_HostCbItem_defaultHost=Default" + }) + private static class HostCbItem { + + private final Host host; + + public HostCbItem(Host host) { + this.host = host; + } + + public Host getHost() { + return host; + } + + @Override + public String toString() { + if (host == null) { + return Bundle.SelectHostPanel_HostCbItem_defaultHost(); + } else if (host.getName() == null) { + return ""; + } else { + return host.getName(); + } + } + } + + /** + * Creates new form SelectHostPanel + */ + public SelectHostPanel() { + initComponents(); + this.comboBoxHostName.addItem(new HostCbItem(null)); + } + + public Host getSelectedHost() { + return comboBoxHostName.getSelectedItem() instanceof HostCbItem + ? ((HostCbItem) comboBoxHostName.getSelectedItem()).getHost() + : null; + } + + /** + * 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() { + java.awt.GridBagConstraints gridBagConstraints; + + javax.swing.JLabel lbHostNameLabel = new javax.swing.JLabel(); + comboBoxHostName = new javax.swing.JComboBox<>(); + javax.swing.JButton bnManageHosts = new javax.swing.JButton(); + + setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.title"))); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(lbHostNameLabel, org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.lbHostNameLabel.text")); // NOI18N + lbHostNameLabel.setMaximumSize(new java.awt.Dimension(300, 14)); + lbHostNameLabel.setMinimumSize(new java.awt.Dimension(189, 14)); + lbHostNameLabel.setPreferredSize(new java.awt.Dimension(220, 14)); + + comboBoxHostName.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + comboBoxHostNameActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(bnManageHosts, org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.bnManageHosts.text")); // NOI18N + bnManageHosts.setMargin(new java.awt.Insets(2, 6, 2, 6)); + bnManageHosts.setMaximumSize(new java.awt.Dimension(160, 23)); + bnManageHosts.setMinimumSize(new java.awt.Dimension(123, 23)); + bnManageHosts.setPreferredSize(new java.awt.Dimension(140, 23)); + bnManageHosts.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnManageHostsActionPerformed(evt); + } + }); + + 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() + .addComponent(lbHostNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addComponent(comboBoxHostName, 0, 180, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(bnManageHosts, javax.swing.GroupLayout.PREFERRED_SIZE, 123, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(comboBoxHostName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(bnManageHosts, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lbHostNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.title")); // NOI18N + }// //GEN-END:initComponents + + private void comboBoxHostNameActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_comboBoxHostNameActionPerformed +// @SuppressWarnings("unchecked") +// JComboBox cb = (JComboBox) evt.getSource(); +// String orgName = (String) cb.getSelectedItem(); +// if (null == orgName) { +// return; +// } +// if ("".equals(orgName)) { +// clearOrganization(); +// return; +// } +// for (CentralRepoOrganization org : orgs) { +// if (org.getName().equals(orgName)) { +// selectedOrg = org; +// lbPointOfContactNameText.setText(selectedOrg.getPocName()); +// lbPointOfContactEmailText.setText(selectedOrg.getPocEmail()); +// lbPointOfContactPhoneText.setText(selectedOrg.getPocPhone()); +// return; +// } +// } + }//GEN-LAST:event_comboBoxHostNameActionPerformed + + private void bnManageHostsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnManageHostsActionPerformed + ManageHostsDialog dialog = new ManageHostsDialog((Dialog) SwingUtilities.getWindowAncestor(this)); + loadHostData(); + if (dialog.getSelectedHost() != null) { + setSelectedHost(dialog.getSelectedHost()); + } + }//GEN-LAST:event_bnManageHostsActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JComboBox comboBoxHostName; + // End of variables declaration//GEN-END:variables +} From 94d31ceacff9ff673d627e1267d879ba3f3d5e24 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 16 Feb 2021 11:17:27 -0500 Subject: [PATCH 08/42] fix for accidental bundle changes --- .../autopsy/modules/leappanalyzers/Bundle.properties-MERGED | 4 ++-- .../sleuthkit/autopsy/keywordsearch/Bundle.properties-MERGED | 4 ++-- .../core/core.jar/org/netbeans/core/startup/Bundle.properties | 2 +- .../org/netbeans/core/windows/view/ui/Bundle.properties | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/leappanalyzers/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/leappanalyzers/Bundle.properties-MERGED index f62ee3a1b2..123986b7d6 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/leappanalyzers/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/leappanalyzers/Bundle.properties-MERGED @@ -22,12 +22,12 @@ ILeappAnalyzerIngestModule.init.exception.msg=Unable to find {0}. ILeappAnalyzerIngestModule.processing.file=Processing file {0} ILeappAnalyzerIngestModule.parsing.file=Parsing file {0} ILeappAnalyzerIngestModule.processing.filesystem=Processing filesystem -IleappAnalyzerIngestModule.not.64.bit.os=iLeapp will not run on a 32bit operating system +IleappAnalyzerIngestModule.not.64.bit.os=iLeapp will not run on 32bit operating system ALeappAnalyzerIngestModule.init.exception.msg=Unable to find {0}. ALeappAnalyzerIngestModule.processing.file=Processing file {0} ALeappAnalyzerIngestModule.parsing.file=Parsing file {0} ALeappAnalyzerIngestModule.processing.filesystem=Processing filesystem -AleappAnalyzerIngestModule.not.64.bit.os=aLeapp will not run on a 32bit operating system +AleappAnalyzerIngestModule.not.64.bit.os=aLeapp will not run on 32bit operating system ILeappAnalyzerIngestModule.report.name=iLeapp Html Report ILeappAnalyzerIngestModule.requires.windows=iLeapp module requires windows. ILeappAnalyzerIngestModule.running.iLeapp=Running iLeapp diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties-MERGED b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties-MERGED index 5d6db8703e..02244f9477 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties-MERGED +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties-MERGED @@ -37,7 +37,7 @@ KeywordSearchResultFactory.createNodeForKey.noResultsFound.text=No results found KeywordSearchResultFactory.query.exception.msg=Could not perform the query OpenIDE-Module-Display-Category=Ingest Module -OpenIDE-Module-Long-Description=Keyword Search ingest module.\n\nThe module indexes files found in the disk image at ingest time.\nIt then periodically runs the search on the indexed files using one or more keyword lists (containing pure words and/or regular expressions) and posts results.\n\n\The module also contains additional tools integrated in the main GUI, such as keyword list configuration, keyword search bar in the top-right corner, extracted text viewer and search results viewer showing highlighted keywords found. +OpenIDE-Module-Long-Description=Keyword Search ingest module.\n\nThe module indexes files found in the disk image at ingest time.\nIt then periodically runs the search on the indexed files using one or more keyword lists (containing pure words and/or regular expressions) and posts results.\n\nThe module also contains additional tools integrated in the main GUI, such as keyword list configuration, keyword search bar in the top-right corner, extracted text viewer and search results viewer showing highlighted keywords found. OpenIDE-Module-Name=KeywordSearch OptionsCategory_Name_KeywordSearchOptions=Keyword Search OptionsCategory_Keywords_KeywordSearchOptions=Keyword Search @@ -232,7 +232,7 @@ Server.query.exception.msg=Error running query: {0} Server.query2.exception.msg=Error running query: {0} Server.queryTerms.exception.msg=Error running terms query: {0} Server.connect.exception.msg=Failed to connect to Solr server: {0} -Server.openCore.exception.msg=Local keyword search service not yet running +Server.openCore.exception.msg=Keyword search service not yet running Server.openCore.exception.cantOpen.msg=Could not create or open index Server.openCore.exception.noIndexDir.msg=Index directory could not be created or is missing Server.request.exception.exception.msg=Could not issue Solr request 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 587ebbad92..c2df473fe0 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 -#Tue, 16 Feb 2021 09:38:17 -0500 +#Mon, 25 Jan 2021 12:41:22 -0500 LBL_splash_window_title=Starting Autopsy SPLASH_HEIGHT=314 SPLASH_WIDTH=538 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 6dd32087a9..d519362703 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 -#Tue, 16 Feb 2021 09:38:17 -0500 +#Mon, 25 Jan 2021 12:41:22 -0500 CTL_MainWindow_Title=Autopsy 4.18.0 CTL_MainWindow_Title_No_Project=Autopsy 4.18.0 From ecd9c1082ba226244cfda7210057701cfcd0d3f3 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 16 Feb 2021 12:52:10 -0500 Subject: [PATCH 09/42] commenting and select host panel --- .../datamodel/hosts/AddEditHostDialog.java | 2 +- .../datamodel/hosts/ManageHostsDialog.java | 52 ++++-- .../datamodel/hosts/SelectHostPanel.form | 3 - .../datamodel/hosts/SelectHostPanel.java | 168 ++++++++++++++---- 4 files changed, 168 insertions(+), 57 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java index 0b704649fd..b37797de49 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java @@ -1,5 +1,5 @@ /* - * Central Repository + * Autopsy Forensic Browser * * Copyright 2021 Basis Technology Corp. * Contact: carrier sleuthkit org diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java index 1cc95eefda..e1e1224dbb 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java @@ -1,5 +1,5 @@ /* - * Central Repository + * Autopsy Forensic Browser * * Copyright 2021 Basis Technology Corp. * Contact: carrier sleuthkit org @@ -164,12 +164,15 @@ public class ManageHostsDialog extends javax.swing.JDialog { private void addHost() { String newHostName = getAddEditDialogName(null); if (newHostName != null) { + Long selectedId = null; try { - Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().createHost(newHostName); + Host newHost = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().createHost(newHostName); + selectedId = newHost == null ? null : newHost.getId(); } catch (NoCurrentCaseException | TskCoreException e) { logger.log(Level.WARNING, String.format("Unable to add new host '%s' at this time.", newHostName), e); } refresh(); + setSelectedHostById(selectedId); } } @@ -189,12 +192,36 @@ public class ManageHostsDialog extends javax.swing.JDialog { } } + /** + * Selects the host with the given id. If no matching id found in list. + * + * @param selectedId The id of the host to select. + */ + private void setSelectedHostById(Long selectedId) { + ListModel model = hostList.getModel(); + + if (selectedId == null) { + hostList.clearSelection(); + } + + for (int i = 0; i < model.getSize(); i++) { + Object o = model.getElementAt(i); + if (o instanceof Host && ((Host) o).getId() == selectedId) { + hostList.setSelectedIndex(i); + return; + } + } + + hostList.clearSelection(); + } + /** * Shows add/edit dialog, and if a value is returned, creates a new Host. * * @param selectedHost The selected host. */ private void editHost(Host selectedHost) { + if (selectedHost != null) { String newHostName = getAddEditDialogName(selectedHost); if (newHostName != null) { @@ -204,7 +231,13 @@ public class ManageHostsDialog extends javax.swing.JDialog { } catch (NoCurrentCaseException | TskCoreException e) { logger.log(Level.WARNING, String.format("Unable to update host '%s' with id: %d at this time.", selectedHost.getName(), selectedHost.getId()), e); } + + HostListItem selectedItem = hostList.getSelectedValue(); + Long selectedId = selectedItem == null || selectedItem.getHost() == null ? null : selectedItem.getHost().getId(); + refresh(); + + setSelectedHostById(selectedId); } } } @@ -248,8 +281,7 @@ public class ManageHostsDialog extends javax.swing.JDialog { * hosts. */ private void refreshData() { - HostListItem selectedItem = hostList.getSelectedValue(); - Long selectedId = selectedItem == null || selectedItem.getHost() == null ? null : selectedItem.getHost().getId(); + hostChildrenMap = getHostListData(); Vector jlistData = hostChildrenMap.entrySet().stream() @@ -258,18 +290,6 @@ public class ManageHostsDialog extends javax.swing.JDialog { .collect(Collectors.toCollection(Vector::new)); hostList.setListData(jlistData); - - if (selectedId != null) { - ListModel model = hostList.getModel(); - - for (int i = 0; i < model.getSize(); i++) { - Object o = model.getElementAt(i); - if (o instanceof Host && ((Host) o).getId() == selectedId) { - hostList.setSelectedIndex(i); - break; - } - } - } } /** diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form index ef94dbc5e2..66ec0b44c9 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form @@ -82,9 +82,6 @@ - - - diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java index 672782ab3c..0388efe696 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java @@ -1,21 +1,46 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2021 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.datamodel.hosts; import java.awt.Dialog; +import java.util.Objects; +import java.util.Vector; +import java.util.logging.Level; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.swing.DefaultComboBoxModel; import javax.swing.SwingUtilities; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.Host; /** - * - * @author gregd + * Panel to be displayed as a part of the add datasource wizard. Provides the + * ability to select current host. */ public class SelectHostPanel extends javax.swing.JPanel { + /** + * A combo box item for a host (or null for default). + */ @Messages({ "SelectHostPanel_HostCbItem_defaultHost=Default" }) @@ -23,11 +48,19 @@ public class SelectHostPanel extends javax.swing.JPanel { private final Host host; - public HostCbItem(Host host) { + /** + * Main constructor. + * + * @param host The host. + */ + HostCbItem(Host host) { this.host = host; } - public Host getHost() { + /** + * @return The host. + */ + Host getHost() { return host; } @@ -41,22 +74,112 @@ public class SelectHostPanel extends javax.swing.JPanel { return host.getName(); } } + + @Override + public int hashCode() { + int hash = 7; + hash = 41 * hash + Objects.hashCode(this.host == null ? 0 : this.host.getId()); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final HostCbItem other = (HostCbItem) obj; + if (!Objects.equals(this.host.getId(), other.host == null ? 0 : other.host.getId())) { + return false; + } + return true; + } + } + private static final Logger logger = Logger.getLogger(SelectHostPanel.class.getName()); + /** * Creates new form SelectHostPanel */ public SelectHostPanel() { initComponents(); + loadHostData(); this.comboBoxHostName.addItem(new HostCbItem(null)); } + /** + * @return The currently selected host or null if no selection. + */ public Host getSelectedHost() { return comboBoxHostName.getSelectedItem() instanceof HostCbItem ? ((HostCbItem) comboBoxHostName.getSelectedItem()).getHost() : null; } + /** + * Loads hosts from database and displays in combo box. + */ + private void loadHostData() { + Stream itemsStream; + try { + itemsStream = Case.getCurrentCaseThrows().getHostManager().getHosts().stream() + .filter(h -> h != null) + .sorted((a, b) -> getNameOrEmpty(a).compareToIgnoreCase(getNameOrEmpty(b))) + .map((h) -> new HostCbItem(h)); + + Vector hosts = Stream.concat(Stream.of(new HostCbItem(null)), itemsStream) + .collect(Collectors.toCollection(Vector::new)); + + comboBoxHostName.setModel(new DefaultComboBoxModel<>(hosts)); + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Unable to display host items with no current case.", ex); + } + + } + + /** + * Returns the name of the host or an empty string if the host or host name + * is null. + * + * @param host The host. + * @return The host name or empty string. + */ + private String getNameOrEmpty(Host host) { + return host == null || host.getName() == null ? "" : host.getName(); + } + + /** + * Sets the selected host in the combo box with the specified host id. If + * host id is null or host id is not found in list, 'default' will be + * selected. + * + * @param hostId The host id. + */ + private void setSelectedHostById(Long hostId) { + int itemCount = comboBoxHostName.getItemCount(); + for (int i = 0; i < itemCount; i++) { + HostCbItem curItem = comboBoxHostName.getItemAt(i); + if (curItem == null) { + continue; + } + + Long curId = curItem.getHost() == null ? null : curItem.getHost().getId(); + if (curId == hostId) { + comboBoxHostName.setSelectedIndex(i); + return; + } + } + + // set to first item which should be 'Default' + comboBoxHostName.setSelectedIndex(0); + } + /** * 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 @@ -65,7 +188,6 @@ public class SelectHostPanel extends javax.swing.JPanel { @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { - java.awt.GridBagConstraints gridBagConstraints; javax.swing.JLabel lbHostNameLabel = new javax.swing.JLabel(); comboBoxHostName = new javax.swing.JComboBox<>(); @@ -78,12 +200,6 @@ public class SelectHostPanel extends javax.swing.JPanel { lbHostNameLabel.setMinimumSize(new java.awt.Dimension(189, 14)); lbHostNameLabel.setPreferredSize(new java.awt.Dimension(220, 14)); - comboBoxHostName.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - comboBoxHostNameActionPerformed(evt); - } - }); - org.openide.awt.Mnemonics.setLocalizedText(bnManageHosts, org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.bnManageHosts.text")); // NOI18N bnManageHosts.setMargin(new java.awt.Insets(2, 6, 2, 6)); bnManageHosts.setMaximumSize(new java.awt.Dimension(160, 23)); @@ -122,33 +238,11 @@ public class SelectHostPanel extends javax.swing.JPanel { getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.title")); // NOI18N }// //GEN-END:initComponents - private void comboBoxHostNameActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_comboBoxHostNameActionPerformed -// @SuppressWarnings("unchecked") -// JComboBox cb = (JComboBox) evt.getSource(); -// String orgName = (String) cb.getSelectedItem(); -// if (null == orgName) { -// return; -// } -// if ("".equals(orgName)) { -// clearOrganization(); -// return; -// } -// for (CentralRepoOrganization org : orgs) { -// if (org.getName().equals(orgName)) { -// selectedOrg = org; -// lbPointOfContactNameText.setText(selectedOrg.getPocName()); -// lbPointOfContactEmailText.setText(selectedOrg.getPocEmail()); -// lbPointOfContactPhoneText.setText(selectedOrg.getPocPhone()); -// return; -// } -// } - }//GEN-LAST:event_comboBoxHostNameActionPerformed - private void bnManageHostsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnManageHostsActionPerformed ManageHostsDialog dialog = new ManageHostsDialog((Dialog) SwingUtilities.getWindowAncestor(this)); loadHostData(); if (dialog.getSelectedHost() != null) { - setSelectedHost(dialog.getSelectedHost()); + setSelectedHostById(dialog.getSelectedHost().getId()); } }//GEN-LAST:event_bnManageHostsActionPerformed From 2de18a035586eb9617fbd6f1ee67b106a1684438 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 16 Feb 2021 19:42:41 -0500 Subject: [PATCH 10/42] updates for adding data source --- .../AddImageWizardAddingProgressPanel.java | 18 +++-- ...ddImageWizardDataSourceSettingsVisual.java | 9 +++ .../casemodule/AddImageWizardIterator.java | 5 +- .../autopsy/casemodule/ImageDSProcessor.java | 8 --- .../casemodule/LocalDiskDSProcessor.java | 7 -- .../casemodule/LocalFilesDSProcessor.java | 8 --- .../autopsy/datamodel/hosts/Bundle.properties | 1 - .../datamodel/hosts/Bundle.properties-MERGED | 1 - .../datamodel/hosts/SelectHostPanel.form | 71 ++++--------------- .../datamodel/hosts/SelectHostPanel.java | 46 +++--------- .../datasourceprocessors/RawDSProcessor.java | 9 --- .../xry/XRYDataSourceProcessor.java | 11 +-- .../dsp/LogicalImagerDSProcessor.java | 12 +--- .../volatilityDSP/MemoryDSProcessor.java | 9 --- 14 files changed, 50 insertions(+), 165 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java index b9ea8f1ae0..4baabfe733 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java @@ -48,6 +48,7 @@ import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.ShortcutWizardDescriptorPanel; import org.sleuthkit.datamodel.Content; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.Host; /** * The final panel of the add image wizard. It displays a progress bar and @@ -115,7 +116,7 @@ class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel { } }); } - + @Override public void setProgressMax(final int max) { // update the progress bar asynchronously @@ -289,7 +290,7 @@ class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel { * * * @param errorString the error string to be displayed - * @param critical true if this is a critical error + * @param critical true if this is a critical error */ void addErrors(String errorString, boolean critical) { getComponent().showErrors(errorString, critical); @@ -302,7 +303,7 @@ class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel { private void startIngest() { if (!newContents.isEmpty() && readyToIngest && !ingested) { ingested = true; - if (dsProcessor != null && ! dsProcessor.supportsIngestStream()) { + if (dsProcessor != null && !dsProcessor.supportsIngestStream()) { IngestManager.getInstance().queueIngestJob(newContents, ingestJobSettings); } setStateFinished(); @@ -323,8 +324,13 @@ class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel { /** * Starts the Data source processing by kicking off the selected * DataSourceProcessor + * + * @param dsp The data source processor providing configuration for how to + * process the specific data source type. + * @param selectedHost The host to which this data source belongs or null + * for a default host. */ - void startDataSourceProcessing(DataSourceProcessor dsp) { + void startDataSourceProcessing(DataSourceProcessor dsp, Host selectedHost) { if (dsProcessor == null) { //this can only be run once final UUID dataSourceId = UUID.randomUUID(); newContents.clear(); @@ -349,7 +355,7 @@ class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel { try { Case.getCurrentCaseThrows().notifyAddingDataSource(dataSourceId); } catch (NoCurrentCaseException ex) { - Logger.getLogger(AddImageWizardAddingProgressVisual.class.getName()).log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + Logger.getLogger(AddImageWizardAddingProgressVisual.class.getName()).log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS } }).start(); DataSourceProcessorCallback cbObj = new DataSourceProcessorCallback() { @@ -367,7 +373,7 @@ class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel { readyToIngest = false; dsProcessor.runWithIngestStream(ingestJobSettings, getDSPProgressMonitorImpl(), cbObj); } else { - dsProcessor.run(getDSPProgressMonitorImpl(), cbObj); + dsProcessor.run(selectedHost, getDSPProgressMonitorImpl(), cbObj); } } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.java index e5186addc7..4914bc8e29 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.java @@ -34,6 +34,7 @@ import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.hosts.SelectHostPanel; +import org.sleuthkit.datamodel.Host; /** * visual component for the first panel of add image wizard. Allows the user to @@ -133,6 +134,14 @@ final class AddImageWizardDataSourceSettingsVisual extends JPanel { return dsProcessor; } + + /** + * Returns the currently selected host or null if 'default' is selected. + * @return The currently selected host. + */ + Host getSelectedHost() { + return selectHostPanel.getSelectedHost(); + } /** * Returns the name of the this panel. This name will be shown on the left diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java index 045bf775b2..d6bfc3cf14 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java @@ -180,8 +180,9 @@ class AddImageWizardIterator implements WizardDescriptor.Iterator
- - - - - - - - - @@ -27,60 +18,24 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + @@ -95,10 +50,10 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java index 0388efe696..41a0ac6852 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java @@ -31,6 +31,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.Host; +import org.sleuthkit.datamodel.TskCoreException; /** * Panel to be displayed as a part of the add datasource wizard. Provides the @@ -128,7 +129,7 @@ public class SelectHostPanel extends javax.swing.JPanel { private void loadHostData() { Stream itemsStream; try { - itemsStream = Case.getCurrentCaseThrows().getHostManager().getHosts().stream() + itemsStream = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getHosts().stream() .filter(h -> h != null) .sorted((a, b) -> getNameOrEmpty(a).compareToIgnoreCase(getNameOrEmpty(b))) .map((h) -> new HostCbItem(h)); @@ -137,10 +138,9 @@ public class SelectHostPanel extends javax.swing.JPanel { .collect(Collectors.toCollection(Vector::new)); comboBoxHostName.setModel(new DefaultComboBoxModel<>(hosts)); - } catch (NoCurrentCaseException ex) { + } catch (NoCurrentCaseException | TskCoreException ex) { logger.log(Level.WARNING, "Unable to display host items with no current case.", ex); } - } /** @@ -189,51 +189,27 @@ public class SelectHostPanel extends javax.swing.JPanel { // //GEN-BEGIN:initComponents private void initComponents() { - javax.swing.JLabel lbHostNameLabel = new javax.swing.JLabel(); comboBoxHostName = new javax.swing.JComboBox<>(); javax.swing.JButton bnManageHosts = new javax.swing.JButton(); - setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.title"))); // NOI18N + setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEADING)); - org.openide.awt.Mnemonics.setLocalizedText(lbHostNameLabel, org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.lbHostNameLabel.text")); // NOI18N - lbHostNameLabel.setMaximumSize(new java.awt.Dimension(300, 14)); - lbHostNameLabel.setMinimumSize(new java.awt.Dimension(189, 14)); - lbHostNameLabel.setPreferredSize(new java.awt.Dimension(220, 14)); + comboBoxHostName.setMaximumSize(new java.awt.Dimension(32767, 22)); + comboBoxHostName.setMinimumSize(new java.awt.Dimension(200, 22)); + comboBoxHostName.setPreferredSize(new java.awt.Dimension(200, 22)); + add(comboBoxHostName); org.openide.awt.Mnemonics.setLocalizedText(bnManageHosts, org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.bnManageHosts.text")); // NOI18N bnManageHosts.setMargin(new java.awt.Insets(2, 6, 2, 6)); - bnManageHosts.setMaximumSize(new java.awt.Dimension(160, 23)); - bnManageHosts.setMinimumSize(new java.awt.Dimension(123, 23)); + bnManageHosts.setMaximumSize(new java.awt.Dimension(140, 23)); + bnManageHosts.setMinimumSize(new java.awt.Dimension(140, 23)); bnManageHosts.setPreferredSize(new java.awt.Dimension(140, 23)); bnManageHosts.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnManageHostsActionPerformed(evt); } }); - - 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() - .addComponent(lbHostNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addComponent(comboBoxHostName, 0, 180, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(bnManageHosts, javax.swing.GroupLayout.PREFERRED_SIZE, 123, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(comboBoxHostName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(bnManageHosts, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lbHostNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); + add(bnManageHosts); getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.title")); // NOI18N }// //GEN-END:initComponents diff --git a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSProcessor.java b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSProcessor.java index 8760ac8da5..964da5b377 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSProcessor.java @@ -159,15 +159,6 @@ public class RawDSProcessor implements DataSourceProcessor, AutoIngestDataSource @Override public void run(Host host, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { configPanel.storeSettings(); - - // HOSTTODO - use passed in value - try { - host = Case.getCurrentCase().getSleuthkitCase().getHostManager().getOrCreateHost("RawDSProcessor Host"); - } catch (TskCoreException ex) { - // It's not worth adding a logger for temporary code - //logger.log(Level.SEVERE, "Error creating/loading host", ex); - host = null; - } run(UUID.randomUUID().toString(), configPanel.getImageFilePath(), configPanel.getTimeZone(), configPanel.getChunkSize(), host, progressMonitor, callback); } diff --git a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/xry/XRYDataSourceProcessor.java b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/xry/XRYDataSourceProcessor.java index a764e9f5f6..a0daacfcc3 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/xry/XRYDataSourceProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/xry/XRYDataSourceProcessor.java @@ -218,16 +218,7 @@ public class XRYDataSourceProcessor implements DataSourceProcessor, AutoIngestDa "XRYDataSourceProcessor.noCurrentCase=No case is open." }) public void run(Host host, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { - progressMonitor.setIndeterminate(true); - - // HOSTTODO - use passed in value - try { - host = Case.getCurrentCase().getSleuthkitCase().getHostManager().getOrCreateHost("XRYDSProcessor Host"); - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error creating/loading host", ex); - host = null; - } - + progressMonitor.setIndeterminate(true); String selectedFilePath = configPanel.getSelectedFilePath(); File selectedFile = new File(selectedFilePath); Path selectedPath = selectedFile.toPath(); diff --git a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerDSProcessor.java b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerDSProcessor.java index 67498064f0..9d9054cb80 100644 --- a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerDSProcessor.java @@ -160,17 +160,7 @@ public final class LogicalImagerDSProcessor implements DataSourceProcessor { }) @Override public void run(Host host, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { - configPanel.storeSettings(); - - // HOSTTODO - set to value from config panel - try { - host = Case.getCurrentCase().getSleuthkitCase().getHostManager().getOrCreateHost("LogicalImagerDSProcessor Host"); - } catch (TskCoreException ex) { - // It's not worth adding a logger for temporary code - //logger.log(Level.SEVERE, "Error creating/loading host", ex); - host = null; - } - + configPanel.storeSettings(); Path imageDirPath = configPanel.getImageDirPath(); List errorList = new ArrayList<>(); List emptyDataSources = new ArrayList<>(); diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/volatilityDSP/MemoryDSProcessor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/volatilityDSP/MemoryDSProcessor.java index a0ca322fac..ea8a45fda9 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/volatilityDSP/MemoryDSProcessor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/volatilityDSP/MemoryDSProcessor.java @@ -140,15 +140,6 @@ public class MemoryDSProcessor implements DataSourceProcessor { @Override public void run(Host host, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { configPanel.storeSettings(); - - // HOSTTODO - replace with a call to configPanel().getHost() - try { - host = Case.getCurrentCase().getSleuthkitCase().getHostManager().getOrCreateHost("MemoryDSProcessor Host"); - } catch (TskCoreException ex) { - // It's not worth adding a logger for temporary code - //logger.log(Level.SEVERE, "Error creating/loading host", ex); - host = null; - } run(UUID.randomUUID().toString(), configPanel.getImageFilePath(), configPanel.getProfile(), configPanel.getPluginsToRun(), configPanel.getTimeZone(), host, progressMonitor, callback); } From 480d2ad1ac92f5580a8e4a2b1b542880156fd253 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 16 Feb 2021 20:14:52 -0500 Subject: [PATCH 11/42] bug fixes --- .../AddImageWizardAddingProgressPanel.java | 2 +- .../autopsy/datamodel/hosts/ManageHostsDialog.java | 13 +++++++++++-- .../autopsy/datamodel/hosts/SelectHostPanel.java | 11 ++++++++++- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java index 4baabfe733..6106914e5b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java @@ -371,7 +371,7 @@ class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel { if (dsProcessor.supportsIngestStream()) { // Set readyToIngest to false to prevent the wizard from starting ingest a second time. readyToIngest = false; - dsProcessor.runWithIngestStream(ingestJobSettings, getDSPProgressMonitorImpl(), cbObj); + dsProcessor.runWithIngestStream(selectedHost, ingestJobSettings, getDSPProgressMonitorImpl(), cbObj); } else { dsProcessor.run(selectedHost, getDSPProgressMonitorImpl(), cbObj); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java index e1e1224dbb..6d27cd53a1 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java @@ -203,10 +203,19 @@ public class ManageHostsDialog extends javax.swing.JDialog { if (selectedId == null) { hostList.clearSelection(); } - + for (int i = 0; i < model.getSize(); i++) { Object o = model.getElementAt(i); - if (o instanceof Host && ((Host) o).getId() == selectedId) { + if (!(o instanceof HostListItem)) { + continue; + } + + Host host = ((HostListItem) o).getHost(); + if (host == null) { + continue; + } + + if (host.getId() == selectedId) { hostList.setSelectedIndex(i); return; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java index 41a0ac6852..02dcf94931 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java @@ -95,7 +95,10 @@ public class SelectHostPanel extends javax.swing.JPanel { return false; } final HostCbItem other = (HostCbItem) obj; - if (!Objects.equals(this.host.getId(), other.host == null ? 0 : other.host.getId())) { + if (!Objects.equals( + this.host == null ? 0 : this.host.getId(), + other.host == null ? 0 : other.host.getId())) { + return false; } return true; @@ -216,6 +219,12 @@ public class SelectHostPanel extends javax.swing.JPanel { private void bnManageHostsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnManageHostsActionPerformed ManageHostsDialog dialog = new ManageHostsDialog((Dialog) SwingUtilities.getWindowAncestor(this)); + dialog.setResizable(false); + if (this.getParent() != null) { + dialog.setLocationRelativeTo(this.getParent()); + } + dialog.setVisible(true); + dialog.toFront(); loadHostData(); if (dialog.getSelectedHost() != null) { setSelectedHostById(dialog.getSelectedHost().getId()); From ca80f93bd4c6343a37e83ea4e788a3b24f57f318 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Thu, 18 Feb 2021 11:19:30 -0500 Subject: [PATCH 12/42] Inital commit --- .../recentactivity/ExtractRegistry.java | 389 ++++++++++++++++-- 1 file changed, 345 insertions(+), 44 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java index e230bfda5a..e1ac95b2aa 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java @@ -67,7 +67,9 @@ import java.util.Scanner; import java.util.Set; import java.util.HashSet; import static java.util.Locale.US; +import java.util.Optional; import static java.util.TimeZone.getTimeZone; +import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -93,10 +95,19 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAM import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_ID; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_NAME; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_HOME_DIR; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.Host; +import org.sleuthkit.datamodel.HostManager; +import org.sleuthkit.datamodel.OsAccount; +import org.sleuthkit.datamodel.OsAccountAttribute; +import org.sleuthkit.datamodel.OsAccountManager; +import org.sleuthkit.datamodel.OsAccountRealm; import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException; import org.sleuthkit.datamodel.Report; +import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskDataException; /** * Extract windows registry data using regripper. Runs two versions of @@ -172,10 +183,16 @@ class ExtractRegistry extends Extract { private static final String SHELLBAG_ARTIFACT_NAME = "RA_SHELL_BAG"; //NON-NLS private static final String SHELLBAG_ATTRIBUTE_LAST_WRITE = "RA_SHELL_BAG_LAST_WRITE"; //NON-NLS private static final String SHELLBAG_ATTRIBUTE_KEY = "RA_SHELL_BAG_KEY"; //NON-NLS - + + private static final SimpleDateFormat REG_RIPPER_TIME_FORMAT = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy 'Z'", US); + BlackboardArtifact.Type shellBagArtifactType = null; BlackboardAttribute.Type shellBagKeyAttributeType = null; BlackboardAttribute.Type shellBagLastWriteAttributeType = null; + + static { + REG_RIPPER_TIME_FORMAT.setTimeZone(getTimeZone("GMT")); + } ExtractRegistry() throws IngestModuleException { moduleName = NbBundle.getMessage(ExtractIE.class, "ExtractRegistry.moduleName.text"); @@ -849,56 +866,66 @@ class ExtractRegistry extends Extract { case "ProfileList": //NON-NLS try { - String homeDir = value; - String sid = artnode.getAttribute("sid"); //NON-NLS - String username = artnode.getAttribute("username"); //NON-NLS - BlackboardArtifact bbart = null; - try { - //check if any of the existing artifacts match this username - ArrayList existingArtifacts = currentCase.getSleuthkitCase().getBlackboardArtifacts(ARTIFACT_TYPE.TSK_OS_ACCOUNT); - for (BlackboardArtifact artifact : existingArtifacts) { - if (artifact.getDataSource().getId() == regFile.getDataSourceObjectId()) { - BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_USER_ID)); - if (attribute != null && attribute.getValueString().equals(sid)) { - bbart = artifact; - break; + String homeDir = value; + String sid = artnode.getAttribute("sid"); //NON-NLS + String username = artnode.getAttribute("username"); //NON-NLS + + // For now both an OsAccount and the + // TSK_OS_ACCOUNT artifact will be created. + try{ + updateOsAccount(regFile, sid, username, homeDir); + + } catch(TskCoreException | TskDataException ex) { + logger.log(Level.SEVERE, String.format("Failed to create OsAccount for file: %s, sid: %s", regFile.getId(), sid)); + } + + BlackboardArtifact bbart = null; + try { + //check if any of the existing artifacts match this username + ArrayList existingArtifacts = currentCase.getSleuthkitCase().getBlackboardArtifacts(ARTIFACT_TYPE.TSK_OS_ACCOUNT); + for (BlackboardArtifact artifact : existingArtifacts) { + if (artifact.getDataSource().getId() == regFile.getDataSourceObjectId()) { + BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_USER_ID)); + if (attribute != null && attribute.getValueString().equals(sid)) { + bbart = artifact; + break; + } } } + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Error getting existing os account artifact", ex); } - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error getting existing os account artifact", ex); - } - if (bbart == null) { - //create new artifact - bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_OS_ACCOUNT); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME, - parentModuleName, username)); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_ID, - parentModuleName, sid)); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH, - parentModuleName, homeDir)); - - newArtifacts.add(bbart); - } else { - //add attributes to existing artifact - BlackboardAttribute bbattr = bbart.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_USER_NAME)); - - if (bbattr == null) { + if (bbart == null) { + //create new artifact + bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_OS_ACCOUNT); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME, parentModuleName, username)); - } - bbattr = bbart.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH)); - if (bbattr == null) { + bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_ID, + parentModuleName, sid)); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH, parentModuleName, homeDir)); - } - } - bbart.addAttributes(bbattributes); + + newArtifacts.add(bbart); + } else { + //add attributes to existing artifact + BlackboardAttribute bbattr = bbart.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_USER_NAME)); + + if (bbattr == null) { + bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME, + parentModuleName, username)); + } + bbattr = bbart.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH)); + if (bbattr == null) { + bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH, + parentModuleName, homeDir)); + } + } + bbart.addAttributes(bbattributes); - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error adding account artifact to blackboard.", ex); //NON-NLS - } - break; + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Error adding account artifact to blackboard.", ex); //NON-NLS + } + break; case "NtuserNetwork": // NON-NLS try { @@ -1166,7 +1193,7 @@ class ExtractRegistry extends Extract { } return false; } - + /** * Creates the attribute list for the given user information and group list. * @@ -2138,4 +2165,278 @@ class ExtractRegistry extends Extract { public String autopsyPlugins = ""; public String fullPlugins = ""; } + + /** + * Updates an existing or creates a new OsAccount with the given attributes. + * + * @param file Registry file + * @param sid Account sid + * @param userName Login name + * @param homeDir Account home Directory + * @throws TskCoreException + * @throws TskDataException + */ + private void updateOsAccount(AbstractFile file, String sid, String userName, String homeDir) throws TskCoreException, TskDataException { + SleuthkitCase skCase = currentCase.getSleuthkitCase(); + + OsAccountManager accountMgr = skCase.getOsAccountManager(); + HostManager hostMrg = skCase.getHostManager(); + Host host = hostMrg.getHost(skCase.getDataSource(file.getDataSourceObjectId())); + + Optional optional = accountMgr.getWindowsAccount(sid, null, null, host); + OsAccount osAccount; + if(!optional.isPresent()) { + osAccount = accountMgr.createWindowsAccount(sid, userName != null && userName.isEmpty() ? null : userName, null, host, OsAccountRealm.RealmScope.UNKNOWN); + } else { + osAccount = optional.get(); + if(userName != null && !userName.isEmpty()) { + osAccount.setLoginName(userName); + } + } + + if(homeDir != null && !homeDir.isEmpty()) { + Set attSet = new HashSet<>(); + attSet.add(createOsAccountAttribute(TSK_HOME_DIR, homeDir, osAccount, host, file)); + osAccount.addAttributes(attSet); + } + + osAccount.update(); + } + + /** + * Create an account for the found email address. + * + * @param regFile File the account was found in + * @param emailAddress The emailAddress + */ + private void addEmailAccount(AbstractFile regFile, String emailAddress) { + try { + currentCase.getSleuthkitCase() + .getCommunicationsManager() + .createAccountFileInstance(Account.Type.EMAIL, + emailAddress, getRAModuleName(), regFile); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, + String.format("Error adding email account with value " + + "%s, to the case database for file %s [objId=%d]", + emailAddress, regFile.getName(), regFile.getId()), ex); + } + } + + /** + * Parse the data time string found in the SAM file. + * + * @param value Date time string in the REG_RIPPER_TIME_FORMAT + * + * @return Java epoch time in seconds or null if the value could not be + * parsed. + */ + private Long parseRegRipTime(String value) { + try { + return REG_RIPPER_TIME_FORMAT.parse(value).getTime() / MS_IN_SEC; + } catch (ParseException ex) { + logger.log(Level.SEVERE, String.format("Failed to parse reg rip time: %s", value)); + } + return null; + } + + /** + * Parse the data from the userInfo map created by parsing the SAM file. + * + * @param osAccount + * @param userInfo + * @param groupList + * @param regFile + * @throws TskDataException + * @throws TskCoreException + */ + private void updateOsAccount(OsAccount osAccount, Map userInfo, List groupList, AbstractFile regFile) throws TskDataException, TskCoreException { + SleuthkitCase skCase = currentCase.getSleuthkitCase(); + + OsAccountManager accountMgr = skCase.getOsAccountManager(); + HostManager hostMrg = skCase.getHostManager(); + Host host = hostMrg.getHost(skCase.getDataSource(regFile.getDataSourceObjectId())); + + SimpleDateFormat regRipperTimeFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy 'Z'", US); + regRipperTimeFormat.setTimeZone(getTimeZone("GMT")); + + Set attributeSet = new HashSet<>(); + + String value = userInfo.get(ACCOUNT_CREATED_KEY); + if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) { + Long time = parseRegRipTime(value); + if(time != null) { + osAccount.setCreationTime(time); + } + } + + value = userInfo.get(LAST_LOGIN_KEY); + if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) { + Long time = parseRegRipTime(value); + if(time != null) { + attributeSet.add(createOsAccountAttribute(TSK_DATETIME_ACCESSED, + parseRegRipTime(value), + osAccount, host, regFile)); + } + } + + value = userInfo.get(LOGIN_COUNT_KEY); + if (value != null && !value.isEmpty()) { + attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_COUNT, + Integer.parseInt(value), + osAccount, host, regFile)); + } + + value = userInfo.get(ACCOUNT_TYPE_KEY); + if (value != null && !value.isEmpty()) { + // Need to figure out what the account type value could be and + // how it translates to OsAccountType + } else { + osAccount.setOsAccountType(OsAccount.OsAccountType.UNKNOWN); + } + + value = userInfo.get(USER_COMMENT_KEY); + if (value != null && !value.isEmpty()) { + attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_DESCRIPTION, + value, osAccount, host, regFile)); + } + + value = userInfo.get(INTERNET_NAME_KEY); + if (value != null && !value.isEmpty()) { + addEmailAccount(regFile, value); + + attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_EMAIL, + value, osAccount, host, regFile)); + } + + value = userInfo.get(FULL_NAME_KEY); + if (value != null && !value.isEmpty()) { + osAccount.setFullName(value); + } else { + value = userInfo.get(NAME_KEY); + if (value != null && !value.isEmpty()) { + osAccount.setFullName(value); + } + } + + value = userInfo.get(PWD_RESET_KEY); + if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) { + Long time = parseRegRipTime(value); + if(time != null) { + attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_PASSWORD_RESET, + time, osAccount, host, regFile)); + } + } + + value = userInfo.get(PASSWORD_HINT); + if (value != null && !value.isEmpty()) { + attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_PASSWORD_HINT, + value, osAccount, host, regFile)); + } + + value = userInfo.get(PWD_FAILE_KEY); + if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) { + Long time = parseRegRipTime(value); + if(time != null) { + attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_PASSWORD_FAIL, + time, osAccount, host, regFile)); + } + } + + String settingString = ""; + for (String setting : PASSWORD_SETTINGS_FLAGS) { + if (userInfo.containsKey(setting)) { + settingString += setting + ", "; + } + } + + if (!settingString.isEmpty()) { + attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_PASSWORD_SETTINGS, + settingString, osAccount, host, regFile)); + } + + settingString = ""; + for (String setting : ACCOUNT_SETTINGS_FLAGS) { + if (userInfo.containsKey(setting)) { + settingString += setting + ", "; + } + } + + if (!settingString.isEmpty()) { + settingString = settingString.substring(0, settingString.length() - 2); + attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_ACCOUNT_SETTINGS, + settingString, osAccount, host, regFile)); + } + + settingString = ""; + for (String setting : ACCOUNT_TYPE_FLAGS) { + if (userInfo.containsKey(setting)) { + settingString += setting + ", "; + } + } + + if (!settingString.isEmpty()) { + settingString = settingString.substring(0, settingString.length() - 2); + attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_FLAG, + settingString, osAccount, host, regFile)); + } + + if (groupList != null && groupList.isEmpty()) { + String groups = ""; + for (String group : groupList) { + groups += group + ", "; + } + + attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_FLAG, + groups.substring(0, groups.length() - 2), osAccount, host, regFile)); + } + + osAccount.addAttributes(attributeSet); + osAccount.update(); + } + + /** + * Helper for constructing a new OsAccountAttribute + * + * @param type Attribute type + * @param value The value to store + * @param osAccount The OsAccount this attribute belongs to + * @param host The Host related to the OsAccount + * @param file The source where the attribute was found. + * + * @return Newly created OsACcountAttribute + */ + private OsAccountAttribute createOsAccountAttribute(BlackboardAttribute.ATTRIBUTE_TYPE type, String value, OsAccount osAccount, Host host, AbstractFile file) { + return new OsAccountAttribute(new BlackboardAttribute.Type(type), value, osAccount, host, file); + } + + /** + * Helper for constructing a new OsAccountAttribute + * + * @param type Attribute type + * @param value The value to store + * @param osAccount The OsAccount this attribute belongs to + * @param host The Host related to the OsAccount + * @param file The source where the attribute was found. + * + * @return Newly created OsACcountAttribute + */ + private OsAccountAttribute createOsAccountAttribute(BlackboardAttribute.ATTRIBUTE_TYPE type, Long value, OsAccount osAccount, Host host, AbstractFile file) { + return new OsAccountAttribute(new BlackboardAttribute.Type(type), value, osAccount, host, file); + } + + /** + * Helper for constructing a new OsAccountAttribute + * + * @param type Attribute type + * @param value The value to store + * @param osAccount The OsAccount this attribute belongs to + * @param host The Host related to the OsAccount + * @param file The source where the attribute was found. + * + * @return Newly created OsACcountAttribute + */ + private OsAccountAttribute createOsAccountAttribute(BlackboardAttribute.ATTRIBUTE_TYPE type, Integer value, OsAccount osAccount, Host host, AbstractFile file) { + return new OsAccountAttribute(new BlackboardAttribute.Type(type), value, osAccount, host, file); + } } From d98bf6a39902d3e3128a1011002719c3f7c249fc Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Thu, 18 Feb 2021 15:16:34 -0500 Subject: [PATCH 13/42] Updated RA code to create and updated OsAccounts --- .../recentactivity/ExtractRegistry.java | 194 ++++++++++-------- 1 file changed, 110 insertions(+), 84 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java index e1ac95b2aa..4f86b49bd9 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java @@ -69,7 +69,6 @@ import java.util.HashSet; import static java.util.Locale.US; import java.util.Optional; import static java.util.TimeZone.getTimeZone; -import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -371,7 +370,7 @@ class ExtractRegistry extends Extract { if (regFileNameLocal.toLowerCase().contains("sam") && parseSamPluginOutput(regOutputFiles.fullPlugins, regFile) == false) { this.addErrorMessage( NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.failedParsingResults", - this.getName(), regFileName)); + this.getName(), regFileName)); } else if (regFileNameLocal.toLowerCase().contains("ntuser") || regFileNameLocal.toLowerCase().contains("usrclass")) { try { List shellbags = ShellBagParser.parseShellbagOutput(regOutputFiles.fullPlugins); @@ -1143,6 +1142,34 @@ class ExtractRegistry extends Extract { for (Map userInfo : userSet) { userInfoMap.put(userInfo.get(SID_KEY), userInfo); } + + // New OsAccount Code + OsAccountManager accountMgr = tskCase.getOsAccountManager(); + HostManager hostMrg = tskCase.getHostManager(); + Host host = hostMrg.getHost(tskCase.getDataSource(regAbstractFile.getDataSourceObjectId())); + + Set existingAccounts = accountMgr.getAccounts(host); + for(OsAccount osAccount: existingAccounts) { + Optional optional = osAccount.getUniqueIdWithinRealm(); + if(!optional.isPresent()) { + continue; + } + + String sid = optional.get(); + Map userInfo = userInfoMap.remove(sid); + if(userInfo != null) { + updateOsAccount(osAccount, userInfo, groupMap.get(sid), regAbstractFile); + } + } + + //add remaining userinfos as accounts; + for (Map userInfo : userInfoMap.values()) { + OsAccount osAccount = accountMgr.createWindowsAccount(userInfo.get(SID_KEY), null, null, host, OsAccountRealm.RealmScope.UNKNOWN); + updateOsAccount(osAccount, userInfo, groupMap.get(userInfo.get(SID_KEY)), regAbstractFile); + } + + // Existing TSK_OS_ACCOUNT code. + //get all existing OS account artifacts List existingOsAccounts = tskCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_OS_ACCOUNT); for (BlackboardArtifact osAccount : existingOsAccounts) { @@ -1184,7 +1211,7 @@ class ExtractRegistry extends Extract { logger.log(Level.WARNING, "Error building the document parser: {0}", ex); //NON-NLS } catch (ParseException ex) { logger.log(Level.WARNING, "Error parsing the the date from the registry file", ex); //NON-NLS - } catch (TskCoreException ex) { + } catch (TskDataException | TskCoreException ex) { logger.log(Level.WARNING, "Error updating TSK_OS_ACCOUNT artifacts to include newly parsed data.", ex); //NON-NLS } finally { if (!context.dataSourceIngestIsCancelled()) { @@ -2167,46 +2194,45 @@ class ExtractRegistry extends Extract { } /** - * Updates an existing or creates a new OsAccount with the given attributes. - * - * @param file Registry file - * @param sid Account sid + * Updates an existing or creates a new OsAccount with the given attributes. + * + * @param file Registry file + * @param sid Account sid * @param userName Login name - * @param homeDir Account home Directory + * @param homeDir Account home Directory + * * @throws TskCoreException - * @throws TskDataException + * @throws TskDataException */ private void updateOsAccount(AbstractFile file, String sid, String userName, String homeDir) throws TskCoreException, TskDataException { - SleuthkitCase skCase = currentCase.getSleuthkitCase(); - - OsAccountManager accountMgr = skCase.getOsAccountManager(); - HostManager hostMrg = skCase.getHostManager(); - Host host = hostMrg.getHost(skCase.getDataSource(file.getDataSourceObjectId())); - + OsAccountManager accountMgr = tskCase.getOsAccountManager(); + HostManager hostMrg = tskCase.getHostManager(); + Host host = hostMrg.getHost(tskCase.getDataSource(file.getDataSourceObjectId())); + Optional optional = accountMgr.getWindowsAccount(sid, null, null, host); OsAccount osAccount; - if(!optional.isPresent()) { + if (!optional.isPresent()) { osAccount = accountMgr.createWindowsAccount(sid, userName != null && userName.isEmpty() ? null : userName, null, host, OsAccountRealm.RealmScope.UNKNOWN); } else { - osAccount = optional.get(); - if(userName != null && !userName.isEmpty()) { + osAccount = optional.get(); + if (userName != null && !userName.isEmpty()) { osAccount.setLoginName(userName); - } + } } - - if(homeDir != null && !homeDir.isEmpty()) { + + if (homeDir != null && !homeDir.isEmpty()) { Set attSet = new HashSet<>(); attSet.add(createOsAccountAttribute(TSK_HOME_DIR, homeDir, osAccount, host, file)); osAccount.addAttributes(attSet); } - - osAccount.update(); + + osAccount.update(); } - + /** * Create an account for the found email address. - * - * @param regFile File the account was found in + * + * @param regFile File the account was found in * @param emailAddress The emailAddress */ private void addEmailAccount(AbstractFile regFile, String emailAddress) { @@ -2222,14 +2248,14 @@ class ExtractRegistry extends Extract { emailAddress, regFile.getName(), regFile.getId()), ex); } } - + /** * Parse the data time string found in the SAM file. - * + * * @param value Date time string in the REG_RIPPER_TIME_FORMAT - * - * @return Java epoch time in seconds or null if the value could not be - * parsed. + * + * @return Java epoch time in seconds or null if the value could not be + * parsed. */ private Long parseRegRipTime(String value) { try { @@ -2239,65 +2265,63 @@ class ExtractRegistry extends Extract { } return null; } - + /** * Parse the data from the userInfo map created by parsing the SAM file. - * - * @param osAccount - * @param userInfo - * @param groupList - * @param regFile + * + * @param osAccount Account to update. + * @param userInfo userInfo map from SAM file parsing. + * @param groupList Group list from the SAM file parsing. + * @param regFile Source file. + * * @throws TskDataException - * @throws TskCoreException + * @throws TskCoreException */ private void updateOsAccount(OsAccount osAccount, Map userInfo, List groupList, AbstractFile regFile) throws TskDataException, TskCoreException { - SleuthkitCase skCase = currentCase.getSleuthkitCase(); - - OsAccountManager accountMgr = skCase.getOsAccountManager(); - HostManager hostMrg = skCase.getHostManager(); - Host host = hostMrg.getHost(skCase.getDataSource(regFile.getDataSourceObjectId())); - + HostManager hostMrg = tskCase.getHostManager(); + Host host = hostMrg.getHost(tskCase.getDataSource(regFile.getDataSourceObjectId())); + SimpleDateFormat regRipperTimeFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy 'Z'", US); regRipperTimeFormat.setTimeZone(getTimeZone("GMT")); - + Set attributeSet = new HashSet<>(); - + String value = userInfo.get(ACCOUNT_CREATED_KEY); if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) { Long time = parseRegRipTime(value); - if(time != null) { + if (time != null) { osAccount.setCreationTime(time); } } - + value = userInfo.get(LAST_LOGIN_KEY); if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) { Long time = parseRegRipTime(value); - if(time != null) { - attributeSet.add(createOsAccountAttribute(TSK_DATETIME_ACCESSED, - parseRegRipTime(value), + if (time != null) { + attributeSet.add(createOsAccountAttribute(TSK_DATETIME_ACCESSED, + parseRegRipTime(value), osAccount, host, regFile)); } } - + value = userInfo.get(LOGIN_COUNT_KEY); if (value != null && !value.isEmpty()) { - attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_COUNT, - Integer.parseInt(value), + attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_COUNT, + Integer.parseInt(value), osAccount, host, regFile)); } + // From regripper the possible values for this key are + // "Default Admin User", "Custom Limited Acct" + // and "Default Guest Acct" value = userInfo.get(ACCOUNT_TYPE_KEY); if (value != null && !value.isEmpty()) { - // Need to figure out what the account type value could be and - // how it translates to OsAccountType - } else { - osAccount.setOsAccountType(OsAccount.OsAccountType.UNKNOWN); + osAccount.setIsAdmin(value.toLowerCase().contains("Admin")); } value = userInfo.get(USER_COMMENT_KEY); if (value != null && !value.isEmpty()) { - attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_DESCRIPTION, + attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_DESCRIPTION, value, osAccount, host, regFile)); } @@ -2305,10 +2329,11 @@ class ExtractRegistry extends Extract { if (value != null && !value.isEmpty()) { addEmailAccount(regFile, value); - attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_EMAIL, + attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_EMAIL, value, osAccount, host, regFile)); } + // FULL_NAME_KEY and NAME_KEY appear to be the same value. value = userInfo.get(FULL_NAME_KEY); if (value != null && !value.isEmpty()) { osAccount.setFullName(value); @@ -2322,23 +2347,23 @@ class ExtractRegistry extends Extract { value = userInfo.get(PWD_RESET_KEY); if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) { Long time = parseRegRipTime(value); - if(time != null) { - attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_PASSWORD_RESET, + if (time != null) { + attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_PASSWORD_RESET, time, osAccount, host, regFile)); } } value = userInfo.get(PASSWORD_HINT); if (value != null && !value.isEmpty()) { - attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_PASSWORD_HINT, + attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_PASSWORD_HINT, value, osAccount, host, regFile)); } value = userInfo.get(PWD_FAILE_KEY); if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) { Long time = parseRegRipTime(value); - if(time != null) { - attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_PASSWORD_FAIL, + if (time != null) { + attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_PASSWORD_FAIL, time, osAccount, host, regFile)); } } @@ -2350,8 +2375,9 @@ class ExtractRegistry extends Extract { } } - if (!settingString.isEmpty()) { - attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_PASSWORD_SETTINGS, + if (!settingString.isEmpty()) { + settingString = settingString.substring(0, settingString.length() - 2); + attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_PASSWORD_SETTINGS, settingString, osAccount, host, regFile)); } @@ -2364,7 +2390,7 @@ class ExtractRegistry extends Extract { if (!settingString.isEmpty()) { settingString = settingString.substring(0, settingString.length() - 2); - attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_ACCOUNT_SETTINGS, + attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_ACCOUNT_SETTINGS, settingString, osAccount, host, regFile)); } @@ -2377,7 +2403,7 @@ class ExtractRegistry extends Extract { if (!settingString.isEmpty()) { settingString = settingString.substring(0, settingString.length() - 2); - attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_FLAG, + attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_FLAG, settingString, osAccount, host, regFile)); } @@ -2386,55 +2412,55 @@ class ExtractRegistry extends Extract { for (String group : groupList) { groups += group + ", "; } - - attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_FLAG, + + attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_GROUPS, groups.substring(0, groups.length() - 2), osAccount, host, regFile)); } - + osAccount.addAttributes(attributeSet); osAccount.update(); } - + /** * Helper for constructing a new OsAccountAttribute - * + * * @param type Attribute type * @param value The value to store * @param osAccount The OsAccount this attribute belongs to * @param host The Host related to the OsAccount * @param file The source where the attribute was found. - * - * @return Newly created OsACcountAttribute + * + * @return Newly created OsACcountAttribute */ private OsAccountAttribute createOsAccountAttribute(BlackboardAttribute.ATTRIBUTE_TYPE type, String value, OsAccount osAccount, Host host, AbstractFile file) { return new OsAccountAttribute(new BlackboardAttribute.Type(type), value, osAccount, host, file); } - + /** * Helper for constructing a new OsAccountAttribute - * + * * @param type Attribute type * @param value The value to store * @param osAccount The OsAccount this attribute belongs to * @param host The Host related to the OsAccount * @param file The source where the attribute was found. - * - * @return Newly created OsACcountAttribute + * + * @return Newly created OsACcountAttribute */ private OsAccountAttribute createOsAccountAttribute(BlackboardAttribute.ATTRIBUTE_TYPE type, Long value, OsAccount osAccount, Host host, AbstractFile file) { return new OsAccountAttribute(new BlackboardAttribute.Type(type), value, osAccount, host, file); } - + /** * Helper for constructing a new OsAccountAttribute - * + * * @param type Attribute type * @param value The value to store * @param osAccount The OsAccount this attribute belongs to * @param host The Host related to the OsAccount * @param file The source where the attribute was found. - * - * @return Newly created OsACcountAttribute + * + * @return Newly created OsACcountAttribute */ private OsAccountAttribute createOsAccountAttribute(BlackboardAttribute.ATTRIBUTE_TYPE type, Integer value, OsAccount osAccount, Host host, AbstractFile file) { return new OsAccountAttribute(new BlackboardAttribute.Type(type), value, osAccount, host, file); From 270e3484b039e003d26f11b280b4dbf31abfc715 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 18 Feb 2021 19:20:58 -0500 Subject: [PATCH 14/42] wizard page beginnings --- .../autopsy/datamodel/hosts/Bundle.properties | 5 +- .../datamodel/hosts/SelectHostPanel.form | 131 +++++++++++++----- .../datamodel/hosts/SelectHostPanel.java | 91 +++++++----- 3 files changed, 160 insertions(+), 67 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties index c04ed82b28..9e6c0760a1 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties @@ -14,4 +14,7 @@ AddEditHostDialog.okButton.text=OK AddEditHostDialog.cancelButton.text=Cancel AddEditHostDialog.inputTextField.text=jTextField1 SelectHostPanel.title=Host -SelectHostPanel.bnManageHosts.text=Manage Hosts +SelectHostPanel.generateNewRadio.text=Generate new based on based on data source name +SelectHostPanel.specifyNewHostRadio.text=Specify new host name +SelectHostPanel.specifyNewHostTextField.text=jTextField1 +SelectHostPanel.useExistingHostRadio.text=Use existing host diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form index 2c3b584183..37c9ce8a0d 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form @@ -1,6 +1,14 @@ + + + + + + + + @@ -16,56 +24,111 @@ + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + - - - - - - - - + + + - - - - + + + + + + + + + + + - - - - - - - - - - - - - + - - - + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java index 02dcf94931..11e0bc6623 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java @@ -192,47 +192,74 @@ public class SelectHostPanel extends javax.swing.JPanel { // //GEN-BEGIN:initComponents private void initComponents() { - comboBoxHostName = new javax.swing.JComboBox<>(); - javax.swing.JButton bnManageHosts = new javax.swing.JButton(); + javax.swing.ButtonGroup radioButtonGroup = new javax.swing.ButtonGroup(); + generateNewRadio = new javax.swing.JRadioButton(); + specifyNewHostRadio = new javax.swing.JRadioButton(); + specifyNewHostTextField = new javax.swing.JTextField(); + useExistingHostRadio = new javax.swing.JRadioButton(); + javax.swing.JScrollPane jScrollPane1 = new javax.swing.JScrollPane(); + existingHostList = new javax.swing.JList<>(); - setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEADING)); + radioButtonGroup.add(generateNewRadio); + generateNewRadio.setSelected(true); + org.openide.awt.Mnemonics.setLocalizedText(generateNewRadio, org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.generateNewRadio.text")); // NOI18N - comboBoxHostName.setMaximumSize(new java.awt.Dimension(32767, 22)); - comboBoxHostName.setMinimumSize(new java.awt.Dimension(200, 22)); - comboBoxHostName.setPreferredSize(new java.awt.Dimension(200, 22)); - add(comboBoxHostName); + radioButtonGroup.add(specifyNewHostRadio); + org.openide.awt.Mnemonics.setLocalizedText(specifyNewHostRadio, org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.specifyNewHostRadio.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(bnManageHosts, org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.bnManageHosts.text")); // NOI18N - bnManageHosts.setMargin(new java.awt.Insets(2, 6, 2, 6)); - bnManageHosts.setMaximumSize(new java.awt.Dimension(140, 23)); - bnManageHosts.setMinimumSize(new java.awt.Dimension(140, 23)); - bnManageHosts.setPreferredSize(new java.awt.Dimension(140, 23)); - bnManageHosts.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnManageHostsActionPerformed(evt); - } + specifyNewHostTextField.setText(org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.specifyNewHostTextField.text")); // NOI18N + + radioButtonGroup.add(useExistingHostRadio); + org.openide.awt.Mnemonics.setLocalizedText(useExistingHostRadio, org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.useExistingHostRadio.text")); // NOI18N + + existingHostList.setModel(new javax.swing.AbstractListModel() { + String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" }; + public int getSize() { return strings.length; } + public String getElementAt(int i) { return strings[i]; } }); - add(bnManageHosts); + jScrollPane1.setViewportView(existingHostList); + + 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) + .addComponent(generateNewRadio) + .addGroup(layout.createSequentialGroup() + .addComponent(specifyNewHostRadio) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(specifyNewHostTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 210, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(useExistingHostRadio) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 272, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(33, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(generateNewRadio) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(specifyNewHostRadio) + .addComponent(specifyNewHostTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(useExistingHostRadio) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(56, Short.MAX_VALUE)) + ); getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.title")); // NOI18N }// //GEN-END:initComponents - private void bnManageHostsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnManageHostsActionPerformed - ManageHostsDialog dialog = new ManageHostsDialog((Dialog) SwingUtilities.getWindowAncestor(this)); - dialog.setResizable(false); - if (this.getParent() != null) { - dialog.setLocationRelativeTo(this.getParent()); - } - dialog.setVisible(true); - dialog.toFront(); - loadHostData(); - if (dialog.getSelectedHost() != null) { - setSelectedHostById(dialog.getSelectedHost().getId()); - } - }//GEN-LAST:event_bnManageHostsActionPerformed - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JComboBox comboBoxHostName; + private javax.swing.JList existingHostList; + private javax.swing.JRadioButton generateNewRadio; + private javax.swing.JRadioButton specifyNewHostRadio; + private javax.swing.JTextField specifyNewHostTextField; + private javax.swing.JRadioButton useExistingHostRadio; // End of variables declaration//GEN-END:variables } From b7cbc3b8a76d9c397202d3b3a3ea3f884701454b Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 18 Feb 2021 19:22:16 -0500 Subject: [PATCH 15/42] wizard page beginnings --- .../org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties | 2 +- .../sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form | 2 +- .../sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties index 9e6c0760a1..28ff581471 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties @@ -16,5 +16,5 @@ AddEditHostDialog.inputTextField.text=jTextField1 SelectHostPanel.title=Host SelectHostPanel.generateNewRadio.text=Generate new based on based on data source name SelectHostPanel.specifyNewHostRadio.text=Specify new host name -SelectHostPanel.specifyNewHostTextField.text=jTextField1 +SelectHostPanel.specifyNewHostTextField.text= SelectHostPanel.useExistingHostRadio.text=Use existing host diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form index 37c9ce8a0d..f789e6469d 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form @@ -125,7 +125,7 @@ - +
diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java index 11e0bc6623..e6844c76f7 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java @@ -212,10 +212,10 @@ public class SelectHostPanel extends javax.swing.JPanel { radioButtonGroup.add(useExistingHostRadio); org.openide.awt.Mnemonics.setLocalizedText(useExistingHostRadio, org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.useExistingHostRadio.text")); // NOI18N - existingHostList.setModel(new javax.swing.AbstractListModel() { + existingHostList.setModel(new javax.swing.AbstractListModel() { String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" }; public int getSize() { return strings.length; } - public String getElementAt(int i) { return strings[i]; } + public Object getElementAt(int i) { return strings[i]; } }); jScrollPane1.setViewportView(existingHostList); @@ -256,7 +256,7 @@ public class SelectHostPanel extends javax.swing.JPanel { // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JList existingHostList; + private javax.swing.JList existingHostList; private javax.swing.JRadioButton generateNewRadio; private javax.swing.JRadioButton specifyNewHostRadio; private javax.swing.JTextField specifyNewHostTextField; From 7765991530ab2730ddbec29693eacb6d2b79898f Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 18 Feb 2021 20:25:29 -0500 Subject: [PATCH 16/42] wizard panel --- ...ddImageWizardDataSourceSettingsVisual.form | 13 +- ...ddImageWizardDataSourceSettingsVisual.java | 24 ++-- .../casemodule/AddImageWizardIterator.java | 8 +- .../AddImageWizardSelectHostPanel.java | 88 +++++++++++++ .../casemodule/Bundle.properties-MERGED | 1 + .../autopsy/datamodel/hosts/Bundle.properties | 1 + .../datamodel/hosts/Bundle.properties-MERGED | 7 +- .../datamodel/hosts/SelectHostPanel.form | 33 +++-- .../datamodel/hosts/SelectHostPanel.java | 120 +++++++++++------- 9 files changed, 222 insertions(+), 73 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostPanel.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.form b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.form index 22de08fe49..d8ab744f34 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.form @@ -41,8 +41,17 @@ - - + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.java index 4914bc8e29..d44b3ed522 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardDataSourceSettingsVisual.java @@ -33,8 +33,6 @@ import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.hosts.SelectHostPanel; -import org.sleuthkit.datamodel.Host; /** * visual component for the first panel of add image wizard. Allows the user to @@ -48,7 +46,6 @@ final class AddImageWizardDataSourceSettingsVisual extends JPanel { private final AddImageWizardDataSourceSettingsPanel wizPanel; private JPanel currentPanel; - private final SelectHostPanel selectHostPanel = new SelectHostPanel(); private final Map datasourceProcessorsMap = new HashMap<>(); @@ -104,7 +101,6 @@ final class AddImageWizardDataSourceSettingsVisual extends JPanel { currentPanel = panel; typePanel.removeAll(); typePanel.add(currentPanel, BorderLayout.CENTER); - typePanel.add(selectHostPanel, BorderLayout.SOUTH); typePanel.validate(); typePanel.repaint(); currentPanel.addPropertyChangeListener(new PropertyChangeListener() { @@ -134,14 +130,6 @@ final class AddImageWizardDataSourceSettingsVisual extends JPanel { return dsProcessor; } - - /** - * Returns the currently selected host or null if 'default' is selected. - * @return The currently selected host. - */ - Host getSelectedHost() { - return selectHostPanel.getSelectedHost(); - } /** * Returns the name of the this panel. This name will be shown on the left @@ -168,7 +156,17 @@ final class AddImageWizardDataSourceSettingsVisual extends JPanel { typePanel.setMinimumSize(new java.awt.Dimension(0, 65)); typePanel.setPreferredSize(new java.awt.Dimension(521, 65)); - typePanel.setLayout(new java.awt.BorderLayout(0, 20)); + + javax.swing.GroupLayout typePanelLayout = new javax.swing.GroupLayout(typePanel); + typePanel.setLayout(typePanelLayout); + typePanelLayout.setHorizontalGroup( + typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 588, Short.MAX_VALUE) + ); + typePanelLayout.setVerticalGroup( + typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 328, Short.MAX_VALUE) + ); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java index d6bfc3cf14..574d304f27 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java @@ -29,6 +29,7 @@ import org.openide.util.NbBundle; import org.sleuthkit.autopsy.ingest.IngestProfiles; import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.IngestProfileSelectionWizardPanel; import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.ShortcutWizardDescriptorPanel; +import org.sleuthkit.datamodel.Host; /** * The iterator class for the "Add Image" wizard panel. This class is used to @@ -43,6 +44,7 @@ class AddImageWizardIterator implements WizardDescriptor.Iterator(); AddImageWizardSelectDspPanel dspSelection = new AddImageWizardSelectDspPanel(); panels.add(dspSelection); + hostPanel = new AddImageWizardSelectHostPanel(); + panels.add(hostPanel); AddImageWizardAddingProgressPanel progressPanel = new AddImageWizardAddingProgressPanel(action); - AddImageWizardDataSourceSettingsPanel dsPanel = new AddImageWizardDataSourceSettingsPanel(); AddImageWizardIngestConfigPanel ingestConfigPanel = new AddImageWizardIngestConfigPanel(progressPanel); panels.add(dsPanel); @@ -182,7 +185,8 @@ class AddImageWizardIterator implements WizardDescriptor.Iterator 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.Component; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import javax.swing.event.ChangeListener; +import org.openide.WizardDescriptor; +import org.openide.util.HelpCtx; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.datamodel.hosts.SelectHostPanel; +import org.sleuthkit.datamodel.Host; +import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.ShortcutWizardDescriptorPanel; + +/** + * Create a wizard panel which contains a panel allowing the selection of a host + * for a data source. + */ +@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives +@Messages("AddImageWizardSelectHostPanel_title=Select Host To Add The Data Source To") +final class AddImageWizardSelectHostPanel extends ShortcutWizardDescriptorPanel implements PropertyChangeListener { + + private final SelectHostPanel component = new SelectHostPanel(); + + @Override + public Component getComponent() { + return component; + } + + @Override + public HelpCtx getHelp() { + return HelpCtx.DEFAULT_HELP; + } + + @Override + public void readSettings(WizardDescriptor data) { + } + + /** + * Returns or generates the selected host. If user specifies 'generate + * new...', then null will be returned. + * + * @return The selected host or null if to be auto generated. + */ + Host getSelectedHost() { + return component.getSelectedHost(); + } + + @Override + public void storeSettings(WizardDescriptor data) { + } + + @Override + public boolean isValid() { + return true; + } + + @Override + public void addChangeListener(ChangeListener cl) { + } + + @Override + public void removeChangeListener(ChangeListener cl) { + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + } + + +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED index 30f782983e..b16e332aa1 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED @@ -1,5 +1,6 @@ AddImageWizardIngestConfigPanel.name.text=Configure Ingest Modules AddImageWizardSelectDspVisual.multiUserWarning.text=This type of Data Source Processor is not available in multi-user mode +AddImageWizardSelectHostPanel_title=Select Host To Add The Data Source To # {0} - exception message Case.closeException.couldNotCloseCase=Error closing case: {0} Case.creationException.couldNotAcquireResourcesLock=Failed to get lock on case resources diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties index 28ff581471..b564aae718 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties @@ -18,3 +18,4 @@ SelectHostPanel.generateNewRadio.text=Generate new based on based on data source SelectHostPanel.specifyNewHostRadio.text=Specify new host name SelectHostPanel.specifyNewHostTextField.text= SelectHostPanel.useExistingHostRadio.text=Use existing host +SelectHostPanel.hostDescription.text=Hosts are used to organize data sources and other data. diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED index dcc2e1763e..e21baa09d2 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED @@ -22,5 +22,10 @@ AddEditHostDialog.inputTextField.text=jTextField1 ManageHostsDialog_title_text=Manage Hosts OpenHostsAction_displayName=Hosts SelectHostPanel.title=Host -SelectHostPanel.bnManageHosts.text=Manage Hosts +SelectHostPanel.generateNewRadio.text=Generate new based on based on data source name +SelectHostPanel.specifyNewHostRadio.text=Specify new host name +SelectHostPanel.specifyNewHostTextField.text= +SelectHostPanel.useExistingHostRadio.text=Use existing host +SelectHostPanel.hostDescription.text=Hosts are used to organize data sources and other data. SelectHostPanel_HostCbItem_defaultHost=Default +SelectHostPanel_title=Select Host to Add the Data Source to diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form index f789e6469d..365bfd5121 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form @@ -24,7 +24,6 @@ - @@ -41,6 +40,7 @@ + @@ -60,7 +60,9 @@ - + + + @@ -76,6 +78,9 @@ + + + @@ -86,6 +91,9 @@ + + + @@ -103,6 +111,9 @@ + + + @@ -115,20 +126,22 @@ - - - - - - - + + - + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java index e6844c76f7..569b056a9c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java @@ -25,7 +25,9 @@ import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.swing.DefaultComboBoxModel; +import javax.swing.DefaultListModel; import javax.swing.SwingUtilities; +import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -37,6 +39,9 @@ import org.sleuthkit.datamodel.TskCoreException; * Panel to be displayed as a part of the add datasource wizard. Provides the * ability to select current host. */ +@Messages({ + "SelectHostPanel_title=Select Host to Add the Data Source to" +}) public class SelectHostPanel extends javax.swing.JPanel { /** @@ -45,7 +50,7 @@ public class SelectHostPanel extends javax.swing.JPanel { @Messages({ "SelectHostPanel_HostCbItem_defaultHost=Default" }) - private static class HostCbItem { + private static class HostListItem { private final Host host; @@ -54,7 +59,7 @@ public class SelectHostPanel extends javax.swing.JPanel { * * @param host The host. */ - HostCbItem(Host host) { + HostListItem(Host host) { this.host = host; } @@ -94,7 +99,7 @@ public class SelectHostPanel extends javax.swing.JPanel { if (getClass() != obj.getClass()) { return false; } - final HostCbItem other = (HostCbItem) obj; + final HostListItem other = (HostListItem) obj; if (!Objects.equals( this.host == null ? 0 : this.host.getId(), other.host == null ? 0 : other.host.getId())) { @@ -114,33 +119,44 @@ public class SelectHostPanel extends javax.swing.JPanel { public SelectHostPanel() { initComponents(); loadHostData(); - this.comboBoxHostName.addItem(new HostCbItem(null)); + refresh(); } /** - * @return The currently selected host or null if no selection. + * @return The currently selected host or null if no selection. This will + * generate a new host if 'Specify New Host Name' */ public Host getSelectedHost() { - return comboBoxHostName.getSelectedItem() instanceof HostCbItem - ? ((HostCbItem) comboBoxHostName.getSelectedItem()).getHost() - : null; + if (specifyNewHostRadio.isSelected() && StringUtils.isNotEmpty(specifyNewHostTextField.getText())) { + String newHostName = specifyNewHostTextField.getText(); + try { + return Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().createHost(newHostName); + } catch (NoCurrentCaseException | TskCoreException ex) { + logger.log(Level.WARNING, String.format("Unable to create host '%s'.", newHostName), ex); + return null; + } + } else if (useExistingHostRadio.isSelected() + && existingHostList.getSelectedValue() != null + && existingHostList.getSelectedValue().getHost() != null) { + + return existingHostList.getSelectedValue().getHost(); + } else { + return null; + } } /** * Loads hosts from database and displays in combo box. */ private void loadHostData() { - Stream itemsStream; try { - itemsStream = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getHosts().stream() + Vector hosts = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getHosts().stream() .filter(h -> h != null) .sorted((a, b) -> getNameOrEmpty(a).compareToIgnoreCase(getNameOrEmpty(b))) - .map((h) -> new HostCbItem(h)); - - Vector hosts = Stream.concat(Stream.of(new HostCbItem(null)), itemsStream) + .map((h) -> new HostListItem(h)) .collect(Collectors.toCollection(Vector::new)); - comboBoxHostName.setModel(new DefaultComboBoxModel<>(hosts)); + existingHostList.setListData(hosts); } catch (NoCurrentCaseException | TskCoreException ex) { logger.log(Level.WARNING, "Unable to display host items with no current case.", ex); } @@ -157,30 +173,14 @@ public class SelectHostPanel extends javax.swing.JPanel { return host == null || host.getName() == null ? "" : host.getName(); } - /** - * Sets the selected host in the combo box with the specified host id. If - * host id is null or host id is not found in list, 'default' will be - * selected. - * - * @param hostId The host id. - */ - private void setSelectedHostById(Long hostId) { - int itemCount = comboBoxHostName.getItemCount(); - for (int i = 0; i < itemCount; i++) { - HostCbItem curItem = comboBoxHostName.getItemAt(i); - if (curItem == null) { - continue; - } + private void refresh() { + specifyNewHostTextField.setEnabled(specifyNewHostRadio.isSelected()); + existingHostList.setEnabled(useExistingHostRadio.isSelected()); + } - Long curId = curItem.getHost() == null ? null : curItem.getHost().getId(); - if (curId == hostId) { - comboBoxHostName.setSelectedIndex(i); - return; - } - } - - // set to first item which should be 'Default' - comboBoxHostName.setSelectedIndex(0); + @Override + public String getName() { + return Bundle.SelectHostPanel_title(); } /** @@ -199,26 +199,40 @@ public class SelectHostPanel extends javax.swing.JPanel { useExistingHostRadio = new javax.swing.JRadioButton(); javax.swing.JScrollPane jScrollPane1 = new javax.swing.JScrollPane(); existingHostList = new javax.swing.JList<>(); + hostDescription = new javax.swing.JLabel(); radioButtonGroup.add(generateNewRadio); generateNewRadio.setSelected(true); org.openide.awt.Mnemonics.setLocalizedText(generateNewRadio, org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.generateNewRadio.text")); // NOI18N + generateNewRadio.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + generateNewRadioActionPerformed(evt); + } + }); radioButtonGroup.add(specifyNewHostRadio); org.openide.awt.Mnemonics.setLocalizedText(specifyNewHostRadio, org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.specifyNewHostRadio.text")); // NOI18N + specifyNewHostRadio.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + specifyNewHostRadioActionPerformed(evt); + } + }); specifyNewHostTextField.setText(org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.specifyNewHostTextField.text")); // NOI18N radioButtonGroup.add(useExistingHostRadio); org.openide.awt.Mnemonics.setLocalizedText(useExistingHostRadio, org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.useExistingHostRadio.text")); // NOI18N - - existingHostList.setModel(new javax.swing.AbstractListModel() { - String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" }; - public int getSize() { return strings.length; } - public Object getElementAt(int i) { return strings[i]; } + useExistingHostRadio.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + useExistingHostRadioActionPerformed(evt); + } }); + + existingHostList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); jScrollPane1.setViewportView(existingHostList); + org.openide.awt.Mnemonics.setLocalizedText(hostDescription, org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.hostDescription.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -232,7 +246,8 @@ public class SelectHostPanel extends javax.swing.JPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(specifyNewHostTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 210, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(useExistingHostRadio) - .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 272, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 272, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(hostDescription)) .addContainerGap(33, Short.MAX_VALUE)) ); layout.setVerticalGroup( @@ -248,16 +263,31 @@ public class SelectHostPanel extends javax.swing.JPanel { .addComponent(useExistingHostRadio) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(56, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(hostDescription) + .addContainerGap(44, Short.MAX_VALUE)) ); getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.title")); // NOI18N }// //GEN-END:initComponents + private void generateNewRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_generateNewRadioActionPerformed + refresh(); + }//GEN-LAST:event_generateNewRadioActionPerformed + + private void specifyNewHostRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_specifyNewHostRadioActionPerformed + refresh(); + }//GEN-LAST:event_specifyNewHostRadioActionPerformed + + private void useExistingHostRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useExistingHostRadioActionPerformed + refresh(); + }//GEN-LAST:event_useExistingHostRadioActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JList existingHostList; + private javax.swing.JList existingHostList; private javax.swing.JRadioButton generateNewRadio; + private javax.swing.JLabel hostDescription; private javax.swing.JRadioButton specifyNewHostRadio; private javax.swing.JTextField specifyNewHostTextField; private javax.swing.JRadioButton useExistingHostRadio; From d7e2819fb5bf6e047cc36037a1de8c03600dc57f Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 19 Feb 2021 11:14:30 -0500 Subject: [PATCH 17/42] validation --- .../AddImageWizardSelectHostPanel.java | 18 ++- .../AddImageWizardSelectHostVisual.form} | 34 ++-- .../AddImageWizardSelectHostVisual.java} | 150 ++++++++++++++---- .../autopsy/casemodule/Bundle.properties | 6 + .../autopsy/datamodel/hosts/Bundle.properties | 6 - 5 files changed, 163 insertions(+), 51 deletions(-) rename Core/src/org/sleuthkit/autopsy/{datamodel/hosts/SelectHostPanel.form => casemodule/AddImageWizardSelectHostVisual.form} (74%) rename Core/src/org/sleuthkit/autopsy/{datamodel/hosts/SelectHostPanel.java => casemodule/AddImageWizardSelectHostVisual.java} (63%) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostPanel.java index e9883e7fc0..738ea66494 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2018 Basis Technology Corp. + * Copyright 2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,9 +23,9 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.event.ChangeListener; import org.openide.WizardDescriptor; +import org.openide.util.ChangeSupport; import org.openide.util.HelpCtx; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.datamodel.hosts.SelectHostPanel; import org.sleuthkit.datamodel.Host; import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.ShortcutWizardDescriptorPanel; @@ -37,8 +37,13 @@ import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.ShortcutWizardDescript @Messages("AddImageWizardSelectHostPanel_title=Select Host To Add The Data Source To") final class AddImageWizardSelectHostPanel extends ShortcutWizardDescriptorPanel implements PropertyChangeListener { - private final SelectHostPanel component = new SelectHostPanel(); - + private final AddImageWizardSelectHostVisual component = new AddImageWizardSelectHostVisual(); + private final ChangeSupport changeSupport = new ChangeSupport(this); + + AddImageWizardSelectHostPanel() { + component.addListener(this); + } + @Override public Component getComponent() { return component; @@ -69,19 +74,22 @@ final class AddImageWizardSelectHostPanel extends ShortcutWizardDescriptorPanel @Override public boolean isValid() { - return true; + return component.hasValidData(); } @Override public void addChangeListener(ChangeListener cl) { + changeSupport.addChangeListener(cl); } @Override public void removeChangeListener(ChangeListener cl) { + changeSupport.removeChangeListener(cl); } @Override public void propertyChange(PropertyChangeEvent evt) { + changeSupport.fireChange(); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.form similarity index 74% rename from Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form rename to Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.form index 365bfd5121..87313f3de1 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.form @@ -31,7 +31,7 @@ - + @@ -39,8 +39,12 @@ - + + + + + @@ -60,9 +64,11 @@ - + - + + + @@ -75,7 +81,7 @@ - + @@ -88,7 +94,7 @@ - + @@ -98,7 +104,7 @@ - + @@ -108,7 +114,7 @@ - + @@ -139,7 +145,17 @@ - + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.java similarity index 63% rename from Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java rename to Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.java index 569b056a9c..076b513fb2 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/SelectHostPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.java @@ -16,21 +16,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datamodel.hosts; +package org.sleuthkit.autopsy.casemodule; -import java.awt.Dialog; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; import java.util.Objects; import java.util.Vector; import java.util.logging.Level; import java.util.stream.Collectors; -import java.util.stream.Stream; -import javax.swing.DefaultComboBoxModel; -import javax.swing.DefaultListModel; -import javax.swing.SwingUtilities; +import java.util.stream.IntStream; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.Host; import org.sleuthkit.datamodel.TskCoreException; @@ -40,16 +38,13 @@ import org.sleuthkit.datamodel.TskCoreException; * ability to select current host. */ @Messages({ - "SelectHostPanel_title=Select Host to Add the Data Source to" + "AddImageWizardSelectHostVisual_title=Select Host" }) -public class SelectHostPanel extends javax.swing.JPanel { +class AddImageWizardSelectHostVisual extends javax.swing.JPanel { /** * A combo box item for a host (or null for default). */ - @Messages({ - "SelectHostPanel_HostCbItem_defaultHost=Default" - }) private static class HostListItem { private final Host host; @@ -72,9 +67,7 @@ public class SelectHostPanel extends javax.swing.JPanel { @Override public String toString() { - if (host == null) { - return Bundle.SelectHostPanel_HostCbItem_defaultHost(); - } else if (host.getName() == null) { + if (host == null || host.getName() == null) { return ""; } else { return host.getName(); @@ -111,22 +104,62 @@ public class SelectHostPanel extends javax.swing.JPanel { } - private static final Logger logger = Logger.getLogger(SelectHostPanel.class.getName()); + private static final Logger logger = Logger.getLogger(AddImageWizardSelectHostVisual.class.getName()); + + private final PropertyChangeSupport changeSupport = new PropertyChangeSupport(this); /** * Creates new form SelectHostPanel */ - public SelectHostPanel() { + AddImageWizardSelectHostVisual() { initComponents(); + + specifyNewHostTextField.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void changedUpdate(DocumentEvent e) { + refresh(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + refresh(); + } + + @Override + public void insertUpdate(DocumentEvent e) { + refresh(); + } + }); + + existingHostList.addListSelectionListener((evt) -> refresh()); + loadHostData(); refresh(); } + /** + * Add listener for validation change events. + * + * @param pcl The property change listener. + */ + void addListener(PropertyChangeListener pcl) { + changeSupport.addPropertyChangeListener(pcl); + } + + /** + * Remove listener from validation change events. + * + * @param pcl The property change listener. + */ + void removeListener(PropertyChangeListener pcl) { + changeSupport.removePropertyChangeListener(pcl); + } + /** * @return The currently selected host or null if no selection. This will * generate a new host if 'Specify New Host Name' */ - public Host getSelectedHost() { + Host getSelectedHost() { if (specifyNewHostRadio.isSelected() && StringUtils.isNotEmpty(specifyNewHostTextField.getText())) { String newHostName = specifyNewHostTextField.getText(); try { @@ -176,11 +209,56 @@ public class SelectHostPanel extends javax.swing.JPanel { private void refresh() { specifyNewHostTextField.setEnabled(specifyNewHostRadio.isSelected()); existingHostList.setEnabled(useExistingHostRadio.isSelected()); + + String prevValidationMessage = validationMessage.getText(); + String newValidationMessage = getValidationMessage(); + validationMessage.setText(newValidationMessage); + // if validation message changed (empty to non-empty or vice-versa) fire validation update + if (StringUtils.isBlank(prevValidationMessage) != StringUtils.isBlank(newValidationMessage)) { + changeSupport.firePropertyChange("validation", prevValidationMessage, newValidationMessage); + } + } + + @Messages({ + "AddImageWizardSelectHostVisual_getValidationMessage_isEmpty=Please provide a name for the host.", + "AddImageWizardSelectHostVisual_getValidationMessage_isDuplicate=Host '{0}' already exists. Please provide a unique name.", + "AddImageWizardSelectHostVisual_getValidationMessage_noHostSelected=Please select an existing host.",}) + private String getValidationMessage() { + if (specifyNewHostRadio.isSelected()) { + // if specify new host and host name is empty + final String newHostName = specifyNewHostTextField.getText(); + if (StringUtils.isBlank(newHostName)) { + return Bundle.AddImageWizardSelectHostVisual_getValidationMessage_isEmpty(); + } + + // or specify new host and the host already exists + boolean hasHostName = IntStream.range(0, existingHostList.getModel().getSize()) + .mapToObj(idx -> existingHostList.getModel().getElementAt(idx)) + .filter(hItem -> hItem != null && hItem.getHost() != null && hItem.getHost().getName() != null) + .map(hItem -> hItem.getHost().getName()) + .anyMatch(hName -> newHostName.trim().equalsIgnoreCase(hName.trim())); + + if (hasHostName) { + return Bundle.AddImageWizardSelectHostVisual_getValidationMessage_isDuplicate(newHostName.trim()); + } + + // or use existing host and no host is selected + } else if (useExistingHostRadio.isSelected() + && (existingHostList.getSelectedValue() == null + || existingHostList.getSelectedValue().getHost() == null)) { + return Bundle.AddImageWizardSelectHostVisual_getValidationMessage_noHostSelected(); + } + + return ""; } @Override public String getName() { - return Bundle.SelectHostPanel_title(); + return Bundle.AddImageWizardSelectHostVisual_title(); + } + + boolean hasValidData() { + return StringUtils.isBlank(validationMessage.getText()); } /** @@ -200,10 +278,11 @@ public class SelectHostPanel extends javax.swing.JPanel { javax.swing.JScrollPane jScrollPane1 = new javax.swing.JScrollPane(); existingHostList = new javax.swing.JList<>(); hostDescription = new javax.swing.JLabel(); + validationMessage = new javax.swing.JLabel(); radioButtonGroup.add(generateNewRadio); generateNewRadio.setSelected(true); - org.openide.awt.Mnemonics.setLocalizedText(generateNewRadio, org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.generateNewRadio.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(generateNewRadio, org.openide.util.NbBundle.getMessage(AddImageWizardSelectHostVisual.class, "AddImageWizardSelectHostVisual.generateNewRadio.text")); // NOI18N generateNewRadio.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { generateNewRadioActionPerformed(evt); @@ -211,17 +290,17 @@ public class SelectHostPanel extends javax.swing.JPanel { }); radioButtonGroup.add(specifyNewHostRadio); - org.openide.awt.Mnemonics.setLocalizedText(specifyNewHostRadio, org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.specifyNewHostRadio.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(specifyNewHostRadio, org.openide.util.NbBundle.getMessage(AddImageWizardSelectHostVisual.class, "AddImageWizardSelectHostVisual.specifyNewHostRadio.text")); // NOI18N specifyNewHostRadio.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { specifyNewHostRadioActionPerformed(evt); } }); - specifyNewHostTextField.setText(org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.specifyNewHostTextField.text")); // NOI18N + specifyNewHostTextField.setText(org.openide.util.NbBundle.getMessage(AddImageWizardSelectHostVisual.class, "AddImageWizardSelectHostVisual.specifyNewHostTextField.text")); // NOI18N radioButtonGroup.add(useExistingHostRadio); - org.openide.awt.Mnemonics.setLocalizedText(useExistingHostRadio, org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.useExistingHostRadio.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(useExistingHostRadio, org.openide.util.NbBundle.getMessage(AddImageWizardSelectHostVisual.class, "AddImageWizardSelectHostVisual.useExistingHostRadio.text")); // NOI18N useExistingHostRadio.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { useExistingHostRadioActionPerformed(evt); @@ -231,7 +310,10 @@ public class SelectHostPanel extends javax.swing.JPanel { existingHostList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); jScrollPane1.setViewportView(existingHostList); - org.openide.awt.Mnemonics.setLocalizedText(hostDescription, org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.hostDescription.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hostDescription, org.openide.util.NbBundle.getMessage(AddImageWizardSelectHostVisual.class, "AddImageWizardSelectHostVisual.hostDescription.text")); // NOI18N + + validationMessage.setForeground(java.awt.Color.RED); + org.openide.awt.Mnemonics.setLocalizedText(validationMessage, org.openide.util.NbBundle.getMessage(AddImageWizardSelectHostVisual.class, "AddImageWizardSelectHostVisual.validationMessage.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -239,15 +321,18 @@ public class SelectHostPanel extends javax.swing.JPanel { layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addComponent(generateNewRadio) .addGroup(layout.createSequentialGroup() .addComponent(specifyNewHostRadio) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(specifyNewHostTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 210, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(useExistingHostRadio) - .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 272, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(hostDescription)) + .addComponent(hostDescription) + .addComponent(validationMessage, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addGap(21, 21, 21) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 272, javax.swing.GroupLayout.PREFERRED_SIZE))) .addContainerGap(33, Short.MAX_VALUE)) ); layout.setVerticalGroup( @@ -263,12 +348,14 @@ public class SelectHostPanel extends javax.swing.JPanel { .addComponent(useExistingHostRadio) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(hostDescription) - .addContainerGap(44, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(validationMessage) + .addContainerGap(22, Short.MAX_VALUE)) ); - getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(SelectHostPanel.class, "SelectHostPanel.title")); // NOI18N + getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(AddImageWizardSelectHostVisual.class, "SelectHostPanel.title")); // NOI18N }// //GEN-END:initComponents private void generateNewRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_generateNewRadioActionPerformed @@ -291,5 +378,6 @@ public class SelectHostPanel extends javax.swing.JPanel { private javax.swing.JRadioButton specifyNewHostRadio; private javax.swing.JTextField specifyNewHostTextField; private javax.swing.JRadioButton useExistingHostRadio; + private javax.swing.JLabel validationMessage; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 9019887a68..390c32a378 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -258,3 +258,9 @@ SolrNotConfiguredDialog.okButton.text=OK SolrNotConfiguredDialog.title=Solr 8 Server Not Configured SolrNotConfiguredDialog.EmptyKeywordSearchHostName=Solr 8 connection parameters are not configured. Please go to Tools->Options->Multi User. SolrNotConfiguredDialog.messageLabel.text=Multi-User cases are enabled but Solr 8 server has not been configured.
\nNew cases can only be created with Solr 8. Please go to Tools->Options->Multi User.\n +AddImageWizardSelectHostVisual.hostDescription.text=Hosts are used to organize data sources and other data. +AddImageWizardSelectHostVisual.useExistingHostRadio.text=Use existing host +AddImageWizardSelectHostVisual.specifyNewHostTextField.text= +AddImageWizardSelectHostVisual.specifyNewHostRadio.text=Specify new host name +AddImageWizardSelectHostVisual.generateNewRadio.text=Generate new based on based on data source name +AddImageWizardSelectHostVisual.validationMessage.text=\ diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties index b564aae718..1c2607cb95 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties @@ -13,9 +13,3 @@ AddEditHostDialog.nameLabel.text=Name: AddEditHostDialog.okButton.text=OK AddEditHostDialog.cancelButton.text=Cancel AddEditHostDialog.inputTextField.text=jTextField1 -SelectHostPanel.title=Host -SelectHostPanel.generateNewRadio.text=Generate new based on based on data source name -SelectHostPanel.specifyNewHostRadio.text=Specify new host name -SelectHostPanel.specifyNewHostTextField.text= -SelectHostPanel.useExistingHostRadio.text=Use existing host -SelectHostPanel.hostDescription.text=Hosts are used to organize data sources and other data. From 20e9c5a5ddbf94cb14e333a05f5a8683df73407e Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 19 Feb 2021 11:45:39 -0500 Subject: [PATCH 18/42] fixes --- .../AddImageWizardIngestConfigPanel.java | 2 +- .../casemodule/AddImageWizardIterator.java | 4 +- .../AddImageWizardSelectHostVisual.form | 5 --- .../AddImageWizardSelectHostVisual.java | 7 ++-- .../autopsy/casemodule/Bundle.properties | 2 +- .../casemodule/Bundle.properties-MERGED | 40 ++++++++++--------- .../datamodel/hosts/Bundle.properties-MERGED | 8 ---- 7 files changed, 28 insertions(+), 40 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java index cfcbdd015c..065a847760 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java @@ -43,7 +43,7 @@ import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.ShortcutWizardDescript @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives class AddImageWizardIngestConfigPanel extends ShortcutWizardDescriptorPanel { - @Messages("AddImageWizardIngestConfigPanel.name.text=Configure Ingest Modules") + @Messages("AddImageWizardIngestConfigPanel.name.text=Configure Ingest") private final IngestJobSettingsPanel ingestJobSettingsPanel; /** * The visual component that displays this panel. If you need to access the diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java index 574d304f27..4a99006997 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java @@ -57,10 +57,10 @@ class AddImageWizardIterator implements WizardDescriptor.Iterator getPanels() { if (panels == null) { panels = new ArrayList<>(); - AddImageWizardSelectDspPanel dspSelection = new AddImageWizardSelectDspPanel(); - panels.add(dspSelection); hostPanel = new AddImageWizardSelectHostPanel(); panels.add(hostPanel); + AddImageWizardSelectDspPanel dspSelection = new AddImageWizardSelectDspPanel(); + panels.add(dspSelection); AddImageWizardAddingProgressPanel progressPanel = new AddImageWizardAddingProgressPanel(action); AddImageWizardDataSourceSettingsPanel dsPanel = new AddImageWizardDataSourceSettingsPanel(); AddImageWizardIngestConfigPanel ingestConfigPanel = new AddImageWizardIngestConfigPanel(progressPanel); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.form b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.form index 87313f3de1..a457affa80 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.form @@ -9,11 +9,6 @@ - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.java index 076b513fb2..35f16f0223 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.java @@ -132,7 +132,7 @@ class AddImageWizardSelectHostVisual extends javax.swing.JPanel { }); existingHostList.addListSelectionListener((evt) -> refresh()); - + loadHostData(); refresh(); } @@ -221,7 +221,8 @@ class AddImageWizardSelectHostVisual extends javax.swing.JPanel { @Messages({ "AddImageWizardSelectHostVisual_getValidationMessage_isEmpty=Please provide a name for the host.", - "AddImageWizardSelectHostVisual_getValidationMessage_isDuplicate=Host '{0}' already exists. Please provide a unique name.", + "# {0} - hostName", + "AddImageWizardSelectHostVisual_getValidationMessage_isDuplicate=Host: {0} already exists. Please provide a unique name.", "AddImageWizardSelectHostVisual_getValidationMessage_noHostSelected=Please select an existing host.",}) private String getValidationMessage() { if (specifyNewHostRadio.isSelected()) { @@ -354,8 +355,6 @@ class AddImageWizardSelectHostVisual extends javax.swing.JPanel { .addComponent(validationMessage) .addContainerGap(22, Short.MAX_VALUE)) ); - - getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(AddImageWizardSelectHostVisual.class, "SelectHostPanel.title")); // NOI18N }// //GEN-END:initComponents private void generateNewRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_generateNewRadioActionPerformed diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 390c32a378..8206f18798 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -59,7 +59,7 @@ AddImageWizardChooseDataSourcePanel.moveFocusNext=Next > AddImageWizardChooseDataSourceVisual.getName.text=Select Data Source AddImageWizardIngestConfigPanel.dsProcDone.noErrs.text=*Data Source added. AddImageWizardIngestConfigPanel.dsProcDone.errs.text=*Errors encountered in adding Data Source. -AddImageWizardIngestConfigVisual.getName.text=Configure Ingest Modules +AddImageWizardIngestConfigVisual.getName.text=Configure Ingest AddImageWizardIterator.stepXofN=Step {0} of {1} AddLocalFilesTask.localFileAdd.progress.text=Adding: {0}/{1} Case.getCurCase.exception.noneOpen=Cannot get the current case; there is no case open\! diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED index b16e332aa1..03eb0e7b7c 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED @@ -1,6 +1,11 @@ -AddImageWizardIngestConfigPanel.name.text=Configure Ingest Modules +AddImageWizardIngestConfigPanel.name.text=Configure Ingest AddImageWizardSelectDspVisual.multiUserWarning.text=This type of Data Source Processor is not available in multi-user mode AddImageWizardSelectHostPanel_title=Select Host To Add The Data Source To +# {0} - hostName +AddImageWizardSelectHostVisual_getValidationMessage_isDuplicate=Host: {0} already exists. Please provide a unique name. +AddImageWizardSelectHostVisual_getValidationMessage_isEmpty=Please provide a name for the host. +AddImageWizardSelectHostVisual_getValidationMessage_noHostSelected=Please select an existing host. +AddImageWizardSelectHostVisual_title=Select Host # {0} - exception message Case.closeException.couldNotCloseCase=Error closing case: {0} Case.creationException.couldNotAcquireResourcesLock=Failed to get lock on case resources @@ -243,18 +248,13 @@ AddImageWizardChooseDataSourcePanel.moveFocusNext=Next > AddImageWizardChooseDataSourceVisual.getName.text=Select Data Source AddImageWizardIngestConfigPanel.dsProcDone.noErrs.text=*Data Source added. AddImageWizardIngestConfigPanel.dsProcDone.errs.text=*Errors encountered in adding Data Source. -AddImageWizardIngestConfigVisual.getName.text=Configure Ingest Modules +AddImageWizardIngestConfigVisual.getName.text=Configure Ingest AddImageWizardIterator.stepXofN=Step {0} of {1} AddLocalFilesTask.localFileAdd.progress.text=Adding: {0}/{1} -Case.getCurCase.exception.noneOpen=Cannot get the current case; there is no case open\! +Case.getCurCase.exception.noneOpen=Cannot get the current case; there is no case open! Case.open.msgDlg.updated.msg=Updated case database schema.\nA backup copy of the database with the following path has been made:\n {0} Case.open.msgDlg.updated.title=Case Database Schema Update -Case.checkImgExist.confDlg.doesntExist.msg=One of the images associated with \n\ -this case are missing. Would you like to search for them now?\n\ -Previously, the image was located at:\n\ -{0}\n\ -Please note that you will still be able to browse directories and generate reports\n\ -if you choose No, but you will not be able to view file content or run the ingest process. +Case.checkImgExist.confDlg.doesntExist.msg=One of the images associated with \nthis case are missing. Would you like to search for them now?\nPreviously, the image was located at:\n{0}\nPlease note that you will still be able to browse directories and generate reports\nif you choose No, but you will not be able to view file content or run the ingest process. Case.checkImgExist.confDlg.doesntExist.title=Missing Image Case.addImg.exception.msg=Error adding image to the case Case.updateCaseName.exception.msg=Error while trying to update the case name. @@ -273,12 +273,9 @@ Case.GetCaseTypeGivenPath.Failure=Unable to get case type Case.metaDataFileCorrupt.exception.msg=The case metadata file (.aut) is corrupted. Case.deleteReports.deleteFromDiskException.log.msg=Unable to delete the report from the disk. Case.deleteReports.deleteFromDiskException.msg=Unable to delete the report {0} from the disk.\nYou may manually delete it from {1} -CaseDeleteAction.closeConfMsg.text=Are you sure want to close and delete this case? \n\ - Case Name: {0}\n\ - Case Directory: {1} +CaseDeleteAction.closeConfMsg.text=Are you sure want to close and delete this case? \nCase Name: {0}\nCase Directory: {1} CaseDeleteAction.closeConfMsg.title=Warning: Closing the Current Case -CaseDeleteAction.msgDlg.fileInUse.msg=The delete action cannot be fully completed because the folder or file in it is open by another program.\n\n\ -Close the folder and file and try again or you can delete the case manually. +CaseDeleteAction.msgDlg.fileInUse.msg=The delete action cannot be fully completed because the folder or file in it is open by another program.\n\nClose the folder and file and try again or you can delete the case manually. CaseDeleteAction.msgDlg.fileInUse.title=Error: Folder In Use CaseDeleteAction.msgDlg.caseDelete.msg=Case {0} has been deleted. CaseOpenAction.autFilter.title={0} Case File ( {1}) @@ -310,8 +307,7 @@ NewCaseWizardAction.databaseProblem1.text=Cannot open database. Cancelling case NewCaseWizardAction.databaseProblem2.text=Error NewCaseWizardPanel1.validate.errMsg.invalidSymbols=The Case Name cannot contain any of the following symbols: \\ / : * ? " < > | NewCaseWizardPanel1.validate.errMsg.dirExists=Case directory ''{0}'' already exists. -NewCaseWizardPanel1.validate.confMsg.createDir.msg=The base directory "{0}" does not exist. \n\n\ - Do you want to create that directory? +NewCaseWizardPanel1.validate.confMsg.createDir.msg=The base directory "{0}" does not exist. \n\nDo you want to create that directory? NewCaseWizardPanel1.validate.confMsg.createDir.title=Create directory NewCaseWizardPanel1.validate.errMsg.cantCreateParDir.msg=Error: Could not create case parent directory {0} NewCaseWizardPanel1.validate.errMsg.prevCreateBaseDir.msg=Prevented from creating base directory {0} @@ -362,8 +358,8 @@ UnpackageWorker.doInBackground.previouslySeenCase=Case has been previously opene UpdateRecentCases.menuItem.clearRecentCases.text=Clear Recent Cases UpdateRecentCases.menuItem.empty=-Empty- AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text=Cancel -NewCaseVisualPanel1.CaseFolderOnCDriveError.text=Warning: Path to multi-user case folder is on \"C:\" drive -NewCaseVisualPanel1.CaseFolderOnInternalDriveWindowsError.text=Warning: Path to case folder is on \"C:\" drive. Case folder is created on the target system +NewCaseVisualPanel1.CaseFolderOnCDriveError.text=Warning: Path to multi-user case folder is on "C:" drive +NewCaseVisualPanel1.CaseFolderOnInternalDriveWindowsError.text=Warning: Path to case folder is on "C:" drive. Case folder is created on the target system NewCaseVisualPanel1.CaseFolderOnInternalDriveLinuxError.text=Warning: Path to case folder is on the target system. Create case folder in mounted drive. NewCaseVisualPanel1.uncPath.error=Error: UNC paths are not allowed for Single-User cases CollaborationMonitor.addingDataSourceStatus.msg={0} adding data source @@ -371,7 +367,7 @@ CollaborationMonitor.analyzingDataSourceStatus.msg={0} analyzing {1} MissingImageDialog.lbWarning.text= MissingImageDialog.lbWarning.toolTipText= NewCaseVisualPanel1.caseParentDirWarningLabel.text= -NewCaseVisualPanel1.multiUserCaseRadioButton.text=Multi-User +NewCaseVisualPanel1.multiUserCaseRadioButton.text=Multi-User\t\t NewCaseVisualPanel1.singleUserCaseRadioButton.text=Single-User NewCaseVisualPanel1.caseTypeLabel.text=Case Type: SingleUserCaseConverter.BadDatabaseFileName=Database file does not exist! @@ -477,3 +473,9 @@ SolrNotConfiguredDialog.okButton.text=OK SolrNotConfiguredDialog.title=Solr 8 Server Not Configured SolrNotConfiguredDialog.EmptyKeywordSearchHostName=Solr 8 connection parameters are not configured. Please go to Tools->Options->Multi User. SolrNotConfiguredDialog.messageLabel.text=Multi-User cases are enabled but Solr 8 server has not been configured.
\nNew cases can only be created with Solr 8. Please go to Tools->Options->Multi User.\n +AddImageWizardSelectHostVisual.hostDescription.text=Hosts are used to organize data sources and other data. +AddImageWizardSelectHostVisual.useExistingHostRadio.text=Use existing host +AddImageWizardSelectHostVisual.specifyNewHostTextField.text= +AddImageWizardSelectHostVisual.specifyNewHostRadio.text=Specify new host name +AddImageWizardSelectHostVisual.generateNewRadio.text=Generate new based on based on data source name +AddImageWizardSelectHostVisual.validationMessage.text=\ diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED index e21baa09d2..58182832d1 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED @@ -21,11 +21,3 @@ AddEditHostDialog.cancelButton.text=Cancel AddEditHostDialog.inputTextField.text=jTextField1 ManageHostsDialog_title_text=Manage Hosts OpenHostsAction_displayName=Hosts -SelectHostPanel.title=Host -SelectHostPanel.generateNewRadio.text=Generate new based on based on data source name -SelectHostPanel.specifyNewHostRadio.text=Specify new host name -SelectHostPanel.specifyNewHostTextField.text= -SelectHostPanel.useExistingHostRadio.text=Use existing host -SelectHostPanel.hostDescription.text=Hosts are used to organize data sources and other data. -SelectHostPanel_HostCbItem_defaultHost=Default -SelectHostPanel_title=Select Host to Add the Data Source to From e9eaa0edc15d6ff30724ec8a9a5d3095ea3cf491 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 19 Feb 2021 13:37:08 -0500 Subject: [PATCH 19/42] bug fixes and updates based on comments --- .../casemodule/AddImageWizardIterator.java | 4 +- .../AddImageWizardSelectDspPanel.java | 2 +- .../AddImageWizardSelectHostVisual.form | 41 +++++----- .../AddImageWizardSelectHostVisual.java | 72 ++++++++--------- .../casemodule/Bundle.properties-MERGED | 30 ++++--- .../datamodel/hosts/AddEditHostDialog.java | 37 ++------- .../datamodel/hosts/Bundle.properties-MERGED | 6 +- .../datamodel/hosts/HostNameValidator.java | 81 +++++++++++++++++++ 8 files changed, 168 insertions(+), 105 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/hosts/HostNameValidator.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java index 4a99006997..9ed66765d3 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java @@ -42,6 +42,7 @@ class AddImageWizardIterator implements WizardDescriptor.Iterator(); hostPanel = new AddImageWizardSelectHostPanel(); panels.add(hostPanel); + hostPanelIndex = panels.indexOf(hostPanel); AddImageWizardSelectDspPanel dspSelection = new AddImageWizardSelectDspPanel(); panels.add(dspSelection); AddImageWizardAddingProgressPanel progressPanel = new AddImageWizardAddingProgressPanel(action); @@ -167,7 +169,7 @@ class AddImageWizardIterator implements WizardDescriptor.Iterator 0); //Users should be able to back up to select a different DSP } /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectDspPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectDspPanel.java index 5db401fd0f..64f2ce67cc 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectDspPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectDspPanel.java @@ -39,7 +39,7 @@ import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.ShortcutWizardDescript @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives final class AddImageWizardSelectDspPanel extends ShortcutWizardDescriptorPanel implements PropertyChangeListener { - @NbBundle.Messages("SelectDataSourceProcessorPanel.name.text=Select Type of Data Source To Add") + @NbBundle.Messages("SelectDataSourceProcessorPanel.name.text=Select Data Source Type") private AddImageWizardSelectDspVisual component; private static final String LAST_DSP_PROPERTIES_FILE = "LastDspUsed"; //NON-NLS private static final String LAST_DSP_USED_KEY = "Last_Dsp_Used"; //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.form b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.form index a457affa80..bdb977932a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.form @@ -24,24 +24,29 @@ - + - - - - - - - - - - + + - - + + + + + + + + + + + + + + + - + @@ -49,6 +54,8 @@ + + @@ -59,11 +66,9 @@ - - - + - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.java index 35f16f0223..9197b2fb42 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.java @@ -20,16 +20,18 @@ package org.sleuthkit.autopsy.casemodule; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; +import java.util.Collection; import java.util.Objects; +import java.util.Set; import java.util.Vector; import java.util.logging.Level; import java.util.stream.Collectors; -import java.util.stream.IntStream; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.hosts.HostNameValidator; import org.sleuthkit.datamodel.Host; import org.sleuthkit.datamodel.TskCoreException; @@ -107,7 +109,8 @@ class AddImageWizardSelectHostVisual extends javax.swing.JPanel { private static final Logger logger = Logger.getLogger(AddImageWizardSelectHostVisual.class.getName()); private final PropertyChangeSupport changeSupport = new PropertyChangeSupport(this); - + private Set sanitizedHostSet = null; + /** * Creates new form SelectHostPanel */ @@ -183,13 +186,16 @@ class AddImageWizardSelectHostVisual extends javax.swing.JPanel { */ private void loadHostData() { try { - Vector hosts = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getHosts().stream() + Collection hosts = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getHosts(); + sanitizedHostSet = HostNameValidator.getSanitizedHostNames(hosts); + + Vector hostListItems = hosts.stream() .filter(h -> h != null) .sorted((a, b) -> getNameOrEmpty(a).compareToIgnoreCase(getNameOrEmpty(b))) .map((h) -> new HostListItem(h)) .collect(Collectors.toCollection(Vector::new)); - existingHostList.setListData(hosts); + existingHostList.setListData(hostListItems); } catch (NoCurrentCaseException | TskCoreException ex) { logger.log(Level.WARNING, "Unable to display host items with no current case.", ex); } @@ -220,29 +226,12 @@ class AddImageWizardSelectHostVisual extends javax.swing.JPanel { } @Messages({ - "AddImageWizardSelectHostVisual_getValidationMessage_isEmpty=Please provide a name for the host.", - "# {0} - hostName", - "AddImageWizardSelectHostVisual_getValidationMessage_isDuplicate=Host: {0} already exists. Please provide a unique name.", "AddImageWizardSelectHostVisual_getValidationMessage_noHostSelected=Please select an existing host.",}) private String getValidationMessage() { if (specifyNewHostRadio.isSelected()) { - // if specify new host and host name is empty - final String newHostName = specifyNewHostTextField.getText(); - if (StringUtils.isBlank(newHostName)) { - return Bundle.AddImageWizardSelectHostVisual_getValidationMessage_isEmpty(); - } - - // or specify new host and the host already exists - boolean hasHostName = IntStream.range(0, existingHostList.getModel().getSize()) - .mapToObj(idx -> existingHostList.getModel().getElementAt(idx)) - .filter(hItem -> hItem != null && hItem.getHost() != null && hItem.getHost().getName() != null) - .map(hItem -> hItem.getHost().getName()) - .anyMatch(hName -> newHostName.trim().equalsIgnoreCase(hName.trim())); - - if (hasHostName) { - return Bundle.AddImageWizardSelectHostVisual_getValidationMessage_isDuplicate(newHostName.trim()); - } - + // if problematic new name for host + return HostNameValidator.getValidationMessage(specifyNewHostTextField.getText(), null, sanitizedHostSet); + // or use existing host and no host is selected } else if (useExistingHostRadio.isSelected() && (existingHostList.getSelectedValue() == null @@ -250,7 +239,7 @@ class AddImageWizardSelectHostVisual extends javax.swing.JPanel { return Bundle.AddImageWizardSelectHostVisual_getValidationMessage_noHostSelected(); } - return ""; + return null; } @Override @@ -322,24 +311,29 @@ class AddImageWizardSelectHostVisual extends javax.swing.JPanel { layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(generateNewRadio) - .addGroup(layout.createSequentialGroup() - .addComponent(specifyNewHostRadio) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(specifyNewHostTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 210, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(useExistingHostRadio) - .addComponent(hostDescription) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(validationMessage, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() - .addGap(21, 21, 21) - .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 272, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addContainerGap(33, Short.MAX_VALUE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(generateNewRadio) + .addComponent(useExistingHostRadio) + .addComponent(hostDescription) + .addGroup(layout.createSequentialGroup() + .addGap(21, 21, 21) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 270, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(specifyNewHostRadio) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(specifyNewHostTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 270, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGap(0, 13, Short.MAX_VALUE))) + .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() + .addComponent(hostDescription) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(generateNewRadio) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) @@ -349,11 +343,9 @@ class AddImageWizardSelectHostVisual extends javax.swing.JPanel { .addComponent(useExistingHostRadio) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(hostDescription) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGap(10, 10, 10) .addComponent(validationMessage) - .addContainerGap(22, Short.MAX_VALUE)) + .addContainerGap(18, Short.MAX_VALUE)) ); }// //GEN-END:initComponents diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED index 03eb0e7b7c..2a22f05c7f 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED @@ -1,9 +1,6 @@ AddImageWizardIngestConfigPanel.name.text=Configure Ingest AddImageWizardSelectDspVisual.multiUserWarning.text=This type of Data Source Processor is not available in multi-user mode AddImageWizardSelectHostPanel_title=Select Host To Add The Data Source To -# {0} - hostName -AddImageWizardSelectHostVisual_getValidationMessage_isDuplicate=Host: {0} already exists. Please provide a unique name. -AddImageWizardSelectHostVisual_getValidationMessage_isEmpty=Please provide a name for the host. AddImageWizardSelectHostVisual_getValidationMessage_noHostSelected=Please select an existing host. AddImageWizardSelectHostVisual_title=Select Host # {0} - exception message @@ -251,10 +248,15 @@ AddImageWizardIngestConfigPanel.dsProcDone.errs.text=*Errors encountered in addi AddImageWizardIngestConfigVisual.getName.text=Configure Ingest AddImageWizardIterator.stepXofN=Step {0} of {1} AddLocalFilesTask.localFileAdd.progress.text=Adding: {0}/{1} -Case.getCurCase.exception.noneOpen=Cannot get the current case; there is no case open! +Case.getCurCase.exception.noneOpen=Cannot get the current case; there is no case open\! Case.open.msgDlg.updated.msg=Updated case database schema.\nA backup copy of the database with the following path has been made:\n {0} Case.open.msgDlg.updated.title=Case Database Schema Update -Case.checkImgExist.confDlg.doesntExist.msg=One of the images associated with \nthis case are missing. Would you like to search for them now?\nPreviously, the image was located at:\n{0}\nPlease note that you will still be able to browse directories and generate reports\nif you choose No, but you will not be able to view file content or run the ingest process. +Case.checkImgExist.confDlg.doesntExist.msg=One of the images associated with \n\ +this case are missing. Would you like to search for them now?\n\ +Previously, the image was located at:\n\ +{0}\n\ +Please note that you will still be able to browse directories and generate reports\n\ +if you choose No, but you will not be able to view file content or run the ingest process. Case.checkImgExist.confDlg.doesntExist.title=Missing Image Case.addImg.exception.msg=Error adding image to the case Case.updateCaseName.exception.msg=Error while trying to update the case name. @@ -273,9 +275,12 @@ Case.GetCaseTypeGivenPath.Failure=Unable to get case type Case.metaDataFileCorrupt.exception.msg=The case metadata file (.aut) is corrupted. Case.deleteReports.deleteFromDiskException.log.msg=Unable to delete the report from the disk. Case.deleteReports.deleteFromDiskException.msg=Unable to delete the report {0} from the disk.\nYou may manually delete it from {1} -CaseDeleteAction.closeConfMsg.text=Are you sure want to close and delete this case? \nCase Name: {0}\nCase Directory: {1} +CaseDeleteAction.closeConfMsg.text=Are you sure want to close and delete this case? \n\ + Case Name: {0}\n\ + Case Directory: {1} CaseDeleteAction.closeConfMsg.title=Warning: Closing the Current Case -CaseDeleteAction.msgDlg.fileInUse.msg=The delete action cannot be fully completed because the folder or file in it is open by another program.\n\nClose the folder and file and try again or you can delete the case manually. +CaseDeleteAction.msgDlg.fileInUse.msg=The delete action cannot be fully completed because the folder or file in it is open by another program.\n\n\ +Close the folder and file and try again or you can delete the case manually. CaseDeleteAction.msgDlg.fileInUse.title=Error: Folder In Use CaseDeleteAction.msgDlg.caseDelete.msg=Case {0} has been deleted. CaseOpenAction.autFilter.title={0} Case File ( {1}) @@ -307,7 +312,8 @@ NewCaseWizardAction.databaseProblem1.text=Cannot open database. Cancelling case NewCaseWizardAction.databaseProblem2.text=Error NewCaseWizardPanel1.validate.errMsg.invalidSymbols=The Case Name cannot contain any of the following symbols: \\ / : * ? " < > | NewCaseWizardPanel1.validate.errMsg.dirExists=Case directory ''{0}'' already exists. -NewCaseWizardPanel1.validate.confMsg.createDir.msg=The base directory "{0}" does not exist. \n\nDo you want to create that directory? +NewCaseWizardPanel1.validate.confMsg.createDir.msg=The base directory "{0}" does not exist. \n\n\ + Do you want to create that directory? NewCaseWizardPanel1.validate.confMsg.createDir.title=Create directory NewCaseWizardPanel1.validate.errMsg.cantCreateParDir.msg=Error: Could not create case parent directory {0} NewCaseWizardPanel1.validate.errMsg.prevCreateBaseDir.msg=Prevented from creating base directory {0} @@ -338,7 +344,7 @@ RecentCases.exception.caseIdxOutOfRange.msg=Recent case index {0} is out of rang RecentCases.getName.text=Clear Recent Cases # {0} - case name RecentItems.openRecentCase.msgDlg.text=Case {0} no longer exists. -SelectDataSourceProcessorPanel.name.text=Select Type of Data Source To Add +SelectDataSourceProcessorPanel.name.text=Select Data Source Type StartupWindow.title.text=Welcome UnpackagePortableCaseDialog.title.text=Unpackage Portable Case UnpackagePortableCaseDialog.UnpackagePortableCaseDialog.extensions=Portable case package (.zip, .zip.001) @@ -358,8 +364,8 @@ UnpackageWorker.doInBackground.previouslySeenCase=Case has been previously opene UpdateRecentCases.menuItem.clearRecentCases.text=Clear Recent Cases UpdateRecentCases.menuItem.empty=-Empty- AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text=Cancel -NewCaseVisualPanel1.CaseFolderOnCDriveError.text=Warning: Path to multi-user case folder is on "C:" drive -NewCaseVisualPanel1.CaseFolderOnInternalDriveWindowsError.text=Warning: Path to case folder is on "C:" drive. Case folder is created on the target system +NewCaseVisualPanel1.CaseFolderOnCDriveError.text=Warning: Path to multi-user case folder is on \"C:\" drive +NewCaseVisualPanel1.CaseFolderOnInternalDriveWindowsError.text=Warning: Path to case folder is on \"C:\" drive. Case folder is created on the target system NewCaseVisualPanel1.CaseFolderOnInternalDriveLinuxError.text=Warning: Path to case folder is on the target system. Create case folder in mounted drive. NewCaseVisualPanel1.uncPath.error=Error: UNC paths are not allowed for Single-User cases CollaborationMonitor.addingDataSourceStatus.msg={0} adding data source @@ -367,7 +373,7 @@ CollaborationMonitor.analyzingDataSourceStatus.msg={0} analyzing {1} MissingImageDialog.lbWarning.text= MissingImageDialog.lbWarning.toolTipText= NewCaseVisualPanel1.caseParentDirWarningLabel.text= -NewCaseVisualPanel1.multiUserCaseRadioButton.text=Multi-User\t\t +NewCaseVisualPanel1.multiUserCaseRadioButton.text=Multi-User NewCaseVisualPanel1.singleUserCaseRadioButton.text=Single-User NewCaseVisualPanel1.caseTypeLabel.text=Case Type: SingleUserCaseConverter.BadDatabaseFileName=Database file does not exist! diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java index b37797de49..4a02edc69a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AddEditHostDialog.java @@ -38,11 +38,13 @@ class AddEditHostDialog extends javax.swing.JDialog { private boolean changed = false; - private final Set hostNamesUpper; + // host names to upper and trimmed + private final Set hostNamesSanitized; private final Host initialHost; /** * Main constructor. + * * @param parent The parent frame for this dialog. * @param currentHosts The current set of hosts in the case. */ @@ -68,11 +70,7 @@ class AddEditHostDialog extends javax.swing.JDialog { this.initialHost = initialHost; setTitle(initialHost == null ? Bundle.AddEditHostDialog_addHost_title() : Bundle.AddEditHostDialog_editHost_title()); - Stream curHostStream = (currentHosts == null) ? Stream.empty() : currentHosts.stream(); - hostNamesUpper = curHostStream - .filter(h -> h != null && h.getName() != null) - .map(h -> h.getName().toUpperCase()) - .collect(Collectors.toSet()); + hostNamesSanitized = HostNameValidator.getSanitizedHostNames(currentHosts); initComponents(); onNameUpdate(initialHost == null ? null : initialHost.getName()); @@ -129,34 +127,13 @@ class AddEditHostDialog extends javax.swing.JDialog { // validate text input against invariants setting validation // message and whether or not okay button is enabled accordingly. - String validationMessage = getValidationMessage(newNameValue); + String validationMessage = HostNameValidator.getValidationMessage( + newNameValue, initialHost == null ? null : initialHost.getName(), hostNamesSanitized); + okButton.setEnabled(validationMessage == null); validationLabel.setText(validationMessage == null ? "" : validationMessage); } - /** - * Gets the validation message based on the current text checked against the - * host names. - * - * @param name The current name in the text field. - * @return The validation message if the name is not valid or null. - */ - @Messages({ - "AddEditHostDialog_getValidationMessage_onEmpty=Please provide some text for the host name.", - "AddEditHostDialog_getValidationMessage_sameAsOriginal=Please provide a new name for this host.", - "AddEditHostDialog_getValidationMessage_onDuplicate=Another host already has the same name. Please choose a different name.",}) - private String getValidationMessage(String name) { - if (name == null || name.isEmpty()) { - return Bundle.AddEditHostDialog_getValidationMessage_onEmpty(); - } else if (initialHost != null && name.equalsIgnoreCase(initialHost.getName())) { - return Bundle.AddEditHostDialog_getValidationMessage_sameAsOriginal(); - } else if (hostNamesUpper.contains(name.toUpperCase())) { - return Bundle.AddEditHostDialog_getValidationMessage_onDuplicate(); - } else { - return null; - } - } - /** * 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 diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED index 58182832d1..22dc1165b3 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/Bundle.properties-MERGED @@ -1,9 +1,9 @@ AddEditHostDialog_addHost_title=Add Host AddEditHostDialog_editHost_title=Edit Host -AddEditHostDialog_getValidationMessage_onDuplicate=Another host already has the same name. Please choose a different name. -AddEditHostDialog_getValidationMessage_onEmpty=Please provide some text for the host name. -AddEditHostDialog_getValidationMessage_sameAsOriginal=Please provide a new name for this host. CTL_OpenHosts=Manage Hosts +HostNameValidator_getValidationMessage_onDuplicate=Another host already has the same name. Please choose a different name. +HostNameValidator_getValidationMessage_onEmpty=Please provide some text for the host name. +HostNameValidator_getValidationMessage_sameAsOriginal=Please provide a new name for this host. # To change this license header, choose License Headers in Project Properties. # To change this template file, choose Tools | Templates # and open the template in the editor. diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/HostNameValidator.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/HostNameValidator.java new file mode 100644 index 0000000000..a5790af6e7 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/HostNameValidator.java @@ -0,0 +1,81 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.datamodel.hosts; + +import java.util.Collection; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.commons.lang3.StringUtils; +import org.openide.util.NbBundle; +import org.sleuthkit.datamodel.Host; + +/** + * Provides methods for validating host names. + */ +public class HostNameValidator { + + /** + * Gets the validation message based on the current text checked against the + * host names. + * + * @param curName The current name in the text field. + * @param initialName If editing a name, the initial name of the host. + * Otherwise, null can be provided for this parameter. + * @param currentHostsTrimmedUpper The current host names. This set should + * be sanitized to upper case and trimmed. + * @return The validation message if the name is not valid or null. + */ + @NbBundle.Messages({ + "HostNameValidator_getValidationMessage_onEmpty=Please provide some text for the host name.", + "HostNameValidator_getValidationMessage_sameAsOriginal=Please provide a new name for this host.", + "HostNameValidator_getValidationMessage_onDuplicate=Another host already has the same name. Please choose a different name.",}) + public static String getValidationMessage(String curName, String initialName, Set currentHostsTrimmedUpper) { + + if (StringUtils.isBlank(curName)) { + return Bundle.HostNameValidator_getValidationMessage_onEmpty(); + } + + if (StringUtils.equalsIgnoreCase(initialName, curName)) { + return Bundle.HostNameValidator_getValidationMessage_sameAsOriginal(); + } + + if (currentHostsTrimmedUpper.contains(curName.trim().toUpperCase())) { + return Bundle.HostNameValidator_getValidationMessage_onDuplicate(); + } + + return null; + } + + /** + * Generates a list of host names trimmed and to upper case that can be used + * with getValidationMessage. + * + * @param hosts The hosts. + * @return The set of host names trimmed and to upper case. + */ + public static Set getSanitizedHostNames(Collection hosts) { + Stream hostsStream = hosts != null ? hosts.stream() : Stream.empty(); + return hostsStream + .map(h -> h == null ? null : h.getName()) + .filter(hName -> StringUtils.isNotBlank(hName)) + .map(hName -> hName.trim().toUpperCase()) + .collect(Collectors.toSet()); + } +} From edcf43ef8a0aa1d8b4a101b40d3b19bab7ab7ade Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Fri, 19 Feb 2021 14:30:32 -0500 Subject: [PATCH 20/42] Updated based on review comments --- .../autopsy/recentactivity/ExtractRegistry.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java index 4f86b49bd9..bebb543a9a 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java @@ -96,6 +96,7 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USE import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_NAME; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_HOME_DIR; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.Host; import org.sleuthkit.datamodel.HostManager; import org.sleuthkit.datamodel.OsAccount; @@ -104,7 +105,6 @@ import org.sleuthkit.datamodel.OsAccountManager; import org.sleuthkit.datamodel.OsAccountRealm; import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException; import org.sleuthkit.datamodel.Report; -import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskDataException; @@ -1158,14 +1158,14 @@ class ExtractRegistry extends Extract { String sid = optional.get(); Map userInfo = userInfoMap.remove(sid); if(userInfo != null) { - updateOsAccount(osAccount, userInfo, groupMap.get(sid), regAbstractFile); + createOrUpdateOsAccount(osAccount, userInfo, groupMap.get(sid), regAbstractFile); } } //add remaining userinfos as accounts; for (Map userInfo : userInfoMap.values()) { OsAccount osAccount = accountMgr.createWindowsAccount(userInfo.get(SID_KEY), null, null, host, OsAccountRealm.RealmScope.UNKNOWN); - updateOsAccount(osAccount, userInfo, groupMap.get(userInfo.get(SID_KEY)), regAbstractFile); + createOrUpdateOsAccount(osAccount, userInfo, groupMap.get(userInfo.get(SID_KEY)), regAbstractFile); } // Existing TSK_OS_ACCOUNT code. @@ -2207,7 +2207,7 @@ class ExtractRegistry extends Extract { private void updateOsAccount(AbstractFile file, String sid, String userName, String homeDir) throws TskCoreException, TskDataException { OsAccountManager accountMgr = tskCase.getOsAccountManager(); HostManager hostMrg = tskCase.getHostManager(); - Host host = hostMrg.getHost(tskCase.getDataSource(file.getDataSourceObjectId())); + Host host = hostMrg.getHost((DataSource)dataSource); Optional optional = accountMgr.getWindowsAccount(sid, null, null, host); OsAccount osAccount; @@ -2226,7 +2226,7 @@ class ExtractRegistry extends Extract { osAccount.addAttributes(attSet); } - osAccount.update(); + accountMgr.updateAccount(osAccount); } /** @@ -2277,9 +2277,8 @@ class ExtractRegistry extends Extract { * @throws TskDataException * @throws TskCoreException */ - private void updateOsAccount(OsAccount osAccount, Map userInfo, List groupList, AbstractFile regFile) throws TskDataException, TskCoreException { - HostManager hostMrg = tskCase.getHostManager(); - Host host = hostMrg.getHost(tskCase.getDataSource(regFile.getDataSourceObjectId())); + private void createOrUpdateOsAccount(OsAccount osAccount, Map userInfo, List groupList, AbstractFile regFile) throws TskDataException, TskCoreException { + Host host = ((DataSource)dataSource).getHost(); SimpleDateFormat regRipperTimeFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy 'Z'", US); regRipperTimeFormat.setTimeZone(getTimeZone("GMT")); @@ -2418,7 +2417,7 @@ class ExtractRegistry extends Extract { } osAccount.addAttributes(attributeSet); - osAccount.update(); + tskCase.getOsAccountManager().updateAccount(osAccount); } /** From adf56dad3cd3e8fe8d4bccef26c3a64013cb341d Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 19 Feb 2021 16:12:42 -0500 Subject: [PATCH 21/42] 7303 only run workers when tabbed pane state changes and domains exist --- .../sleuthkit/autopsy/discovery/ui/DomainDetailsPanel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainDetailsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainDetailsPanel.java index c50ab50020..42ccf485c6 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainDetailsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainDetailsPanel.java @@ -80,9 +80,9 @@ final class DomainDetailsPanel extends JPanel { if (selectedTabName == null || !selectedTabName.equals(newTabTitle)) { selectedTabName = newTabTitle; Component selectedComponent = jTabbedPane1.getSelectedComponent(); - if (selectedComponent instanceof DomainArtifactsTabPanel) { + if (!StringUtils.isBlank(domain) && selectedComponent instanceof DomainArtifactsTabPanel) { runDomainWorker((DomainArtifactsTabPanel) selectedComponent, true); - } else if (selectedComponent instanceof MiniTimelinePanel) { + } else if (!StringUtils.isBlank(domain) && selectedComponent instanceof MiniTimelinePanel) { runMiniTimelineWorker((MiniTimelinePanel) selectedComponent, true); } } From e150ba1fb93b658f049d02558d8c950cac5546c0 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 19 Feb 2021 16:42:40 -0500 Subject: [PATCH 22/42] 7303 make reseting of empty artifact type tabs more consistant --- .../sleuthkit/autopsy/discovery/ui/ArtifactsListPanel.java | 3 +-- .../sleuthkit/autopsy/discovery/ui/DomainDetailsPanel.java | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactsListPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactsListPanel.java index d1328ef68c..cbf38d7453 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactsListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ArtifactsListPanel.java @@ -162,8 +162,7 @@ final class ArtifactsListPanel extends AbstractArtifactListPanel { @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @Override void clearList() { - tableModel.setContents(new ArrayList<>()); - tableModel.fireTableDataChanged(); + addArtifacts(new ArrayList<>()); } /** diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainDetailsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainDetailsPanel.java index 42ccf485c6..496141b091 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainDetailsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainDetailsPanel.java @@ -170,13 +170,13 @@ final class DomainDetailsPanel extends JPanel { @Subscribe void handlePopulateDomainTabsEvent(DiscoveryEventUtils.PopulateDomainTabsEvent populateEvent) { SwingUtilities.invokeLater(() -> { - if (StringUtils.isBlank(populateEvent.getDomain())) { + domain = populateEvent.getDomain(); + if (StringUtils.isBlank(domain)) { resetTabsStatus(); //send fade out event DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.DetailsVisibleEvent(false)); } else { resetTabsStatus(); - domain = populateEvent.getDomain(); Component selectedComponent = jTabbedPane1.getSelectedComponent(); if (selectedComponent instanceof DomainArtifactsTabPanel) { runDomainWorker((DomainArtifactsTabPanel) selectedComponent, false); From 78ff688d2788b72c266631f2728840f9e0eb2ffe Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 22 Feb 2021 16:02:59 -0500 Subject: [PATCH 23/42] 7332 Refactor ingest task pipelines for extensibility --- .../ingest/DataSourceIngestModuleAdapter.java | 5 + .../ingest/DataSourceIngestPipeline.java | 195 ++++---------- .../autopsy/ingest/FileIngestModule.java | 11 +- .../ingest/FileIngestModuleAdapter.java | 5 + .../autopsy/ingest/FileIngestPipeline.java | 250 +++++------------- .../sleuthkit/autopsy/ingest/IngestJob.java | 6 +- .../autopsy/ingest/IngestJobPipeline.java | 22 +- .../autopsy/ingest/IngestManager.java | 4 +- .../autopsy/ingest/IngestModule.java | 86 +++--- .../sleuthkit/autopsy/ingest/Snapshot.java | 6 +- 10 files changed, 199 insertions(+), 391 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestModuleAdapter.java b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestModuleAdapter.java index 6f79817782..a866c278b6 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestModuleAdapter.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestModuleAdapter.java @@ -23,7 +23,12 @@ import org.sleuthkit.datamodel.Content; /** * An adapter that provides a no-op implementation of the startUp() method for * data source ingest modules. + * + * @deprecated As of Java 8, interfaces can have default methods. + * DataSourceIngestModule now provides default no-op versions of startUp() + * and shutDown(). */ +@Deprecated public abstract class DataSourceIngestModuleAdapter implements DataSourceIngestModule { @Override diff --git a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestPipeline.java b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestPipeline.java index c22d63348c..0ad1a3e60a 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestPipeline.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestPipeline.java @@ -1,15 +1,15 @@ /* * Autopsy Forensic Browser - * - * Copyright 2011-2016 Basis Technology Corp. + * + * Copyright 2012-2021 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. @@ -18,184 +18,83 @@ */ package org.sleuthkit.autopsy.ingest; -import java.util.ArrayList; -import java.util.Date; import java.util.List; +import java.util.Optional; import java.util.logging.Level; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.Content; /** - * This class manages a sequence of data source level ingest modules for an - * ingestJobPipeline. It starts the modules, runs data sources through them, and - * shuts them down when data source level ingest is complete. - *

- * This class is thread-safe. + * A pipeline of data source level ingest modules for performing data source + * level ingest tasks for an ingest job. */ -final class DataSourceIngestPipeline { +final class DataSourceIngestPipeline extends IngestTaskPipeline { - private static final IngestManager ingestManager = IngestManager.getInstance(); private static final Logger logger = Logger.getLogger(DataSourceIngestPipeline.class.getName()); - private final IngestJobPipeline ingestJobPipeline; - private final List modules = new ArrayList<>(); - private volatile PipelineModule currentModule; + private static final IngestManager ingestManager = IngestManager.getInstance(); /** - * Constructs an object that manages a sequence of data source level ingest - * modules. It starts the modules, runs data sources through them, and shuts - * them down when data source level ingest is complete. + * Constructs a pipeline of data source level ingest modules for performing + * data source level ingest tasks for an ingest job. * - * @param ingestJobPipeline The ingestJobPipeline that owns this pipeline. - * @param moduleTemplates Templates for the creating the ingest modules that - * make up this pipeline. + * @param ingestJobPipeline The ingest job pipeline that owns this pipeline. + * @param moduleTemplates The ingest module templates that define this + * pipeline. */ DataSourceIngestPipeline(IngestJobPipeline ingestJobPipeline, List moduleTemplates) { - this.ingestJobPipeline = ingestJobPipeline; - for (IngestModuleTemplate template : moduleTemplates) { - if (template.isDataSourceIngestModuleTemplate()) { - PipelineModule module = new PipelineModule(template.createDataSourceIngestModule(), template.getModuleName()); - modules.add(module); - } - } + super(ingestJobPipeline, moduleTemplates); } - /** - * Indicates whether or not there are any ingest modules in this pipeline. - * - * @return True or false. - */ - boolean isEmpty() { - return modules.isEmpty(); + @Override + Optional> acceptModuleTemplate(IngestModuleTemplate template) { + Optional> module = Optional.empty(); + if (template.isDataSourceIngestModuleTemplate()) { + DataSourceIngestModule ingestModule = template.createDataSourceIngestModule(); + module = Optional.of(new DataSourcePipelineModule(ingestModule, template.getModuleName())); + } + return module; } - /** - * Starts up the ingest modules in this pipeline. - * - * @return A list of ingest module startup errors, possibly empty. - */ - synchronized List startUp() { - List errors = new ArrayList<>(); - for (PipelineModule module : modules) { - try { - module.startUp(new IngestJobContext(this.ingestJobPipeline)); - } catch (Throwable ex) { // Catch-all exception firewall - errors.add(new IngestModuleError(module.getDisplayName(), ex)); - } - } - return errors; + @Override + void prepareTask(DataSourceIngestTask task) { } - /** - * Runs a data source through the ingest modules in sequential order. - * - * @param task A data source level ingest task containing a data source to - * be processed. - * - * @return A list of processing errors, possible empty. - */ - synchronized List process(DataSourceIngestTask task) { - List errors = new ArrayList<>(); - if (!this.ingestJobPipeline.isCancelled()) { - Content dataSource = task.getDataSource(); - for (PipelineModule module : modules) { - try { - this.currentModule = module; - String displayName = NbBundle.getMessage(this.getClass(), - "IngestJob.progress.dataSourceIngest.displayName", - module.getDisplayName(), dataSource.getName()); - this.ingestJobPipeline.updateDataSourceIngestProgressBarDisplayName(displayName); - this.ingestJobPipeline.switchDataSourceIngestProgressBarToIndeterminate(); - DataSourceIngestPipeline.ingestManager.setIngestTaskProgress(task, module.getDisplayName()); - logger.log(Level.INFO, "{0} analysis of {1} (pipeline={2}) starting", new Object[]{module.getDisplayName(), ingestJobPipeline.getDataSource().getName(), ingestJobPipeline.getId()}); //NON-NLS - module.process(dataSource, new DataSourceIngestModuleProgress(this.ingestJobPipeline)); - logger.log(Level.INFO, "{0} analysis of {1} (pipeline={2}) finished", new Object[]{module.getDisplayName(), ingestJobPipeline.getDataSource().getName(), ingestJobPipeline.getId()}); //NON-NLS - } catch (Throwable ex) { // Catch-all exception firewall - errors.add(new IngestModuleError(module.getDisplayName(), ex)); - } - if (this.ingestJobPipeline.isCancelled()) { - break; - } else if (this.ingestJobPipeline.currentDataSourceIngestModuleIsCancelled()) { - this.ingestJobPipeline.currentDataSourceIngestModuleCancellationCompleted(currentModule.getDisplayName()); - } - } - } - this.currentModule = null; + @Override + void completeTask(DataSourceIngestTask task) { ingestManager.setIngestTaskProgressCompleted(task); - return errors; } /** - * Gets the currently running module. - * - * @return The module, possibly null if no module is currently running. + * A wrapper that adds ingest infrastructure operations to a data source + * level ingest module. */ - PipelineModule getCurrentlyRunningModule() { - return this.currentModule; - } - - /** - * This class decorates a data source level ingest module with a display - * name and a processing start time. - */ - static class PipelineModule implements DataSourceIngestModule { + static final class DataSourcePipelineModule extends IngestTaskPipeline.PipelineModule { private final DataSourceIngestModule module; - private final String displayName; - private volatile Date processingStartTime; /** - * Constructs an object that decorates a data source level ingest module - * with a display name and a processing start time. - * - * @param module The data source level ingest module to be - * decorated. - * @param displayName The display name. + * Constructs a wrapper that adds ingest infrastructure operations to a + * data source level ingest module. */ - PipelineModule(DataSourceIngestModule module, String displayName) { + DataSourcePipelineModule(DataSourceIngestModule module, String displayName) { + super(module, displayName); this.module = module; - this.displayName = displayName; - this.processingStartTime = new Date(); - } - - /** - * Gets the class name of the decorated ingest module. - * - * @return The class name. - */ - String getClassName() { - return this.module.getClass().getCanonicalName(); - } - - /** - * Gets the display of the decorated ingest module. - * - * @return The display name. - */ - String getDisplayName() { - return this.displayName; - } - - /** - * Gets the time the decorated ingest module started processing the data - * source. - * - * @return The start time, will be null if the module has not started - * processing the data source yet. - */ - Date getProcessingStartTime() { - return this.processingStartTime; } @Override - public void startUp(IngestJobContext context) throws IngestModuleException { - this.module.startUp(context); - } - - @Override - public IngestModule.ProcessResult process(Content dataSource, DataSourceIngestModuleProgress statusHelper) { - this.processingStartTime = new Date(); - return this.module.process(dataSource, statusHelper); + void performTask(IngestJobPipeline ingestJobPipeline, DataSourceIngestTask task) throws IngestModuleException { + Content dataSource = task.getDataSource(); + String progressBarDisplayName = NbBundle.getMessage(this.getClass(), "IngestJob.progress.dataSourceIngest.displayName", getDisplayName(), dataSource.getName()); + ingestJobPipeline.updateDataSourceIngestProgressBarDisplayName(progressBarDisplayName); + ingestJobPipeline.switchDataSourceIngestProgressBarToIndeterminate(); + ingestManager.setIngestTaskProgress(task, getDisplayName()); + logger.log(Level.INFO, "{0} analysis of {1} starting", new Object[]{getDisplayName(), dataSource.getName()}); //NON-NLS + module.process(dataSource, new DataSourceIngestModuleProgress(ingestJobPipeline)); + logger.log(Level.INFO, "{0} analysis of {1} finished", new Object[]{getDisplayName(), dataSource.getName()}); //NON-NLS + if (ingestJobPipeline.currentDataSourceIngestModuleIsCancelled()) { + ingestJobPipeline.currentDataSourceIngestModuleCancellationCompleted(getDisplayName()); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/FileIngestModule.java b/Core/src/org/sleuthkit/autopsy/ingest/FileIngestModule.java index 215c9e0bcb..60355e10f8 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/FileIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/FileIngestModule.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2014-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -36,13 +36,4 @@ public interface FileIngestModule extends IngestModule { */ ProcessResult process(AbstractFile file); - /** - * Invoked by Autopsy when an ingest job is completed (either because the - * data has been analyzed or because the job was canceled - check - * IngestJobContext.fileIngestIsCancelled()), before the ingest module - * instance is discarded. The module should respond by doing things like - * releasing private resources, submitting final results, and posting a - * final ingest message. - */ - void shutDown(); } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/FileIngestModuleAdapter.java b/Core/src/org/sleuthkit/autopsy/ingest/FileIngestModuleAdapter.java index 13811e6eb4..6fbdf529fd 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/FileIngestModuleAdapter.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/FileIngestModuleAdapter.java @@ -23,7 +23,12 @@ import org.sleuthkit.datamodel.AbstractFile; /** * An adapter that provides no-op implementations of the startUp() and * shutDown() methods for file ingest modules. + * + * @deprecated As of Java 8, interfaces can have default methods. + * FileIngestModule now provides default no-op versions of startUp() and + * shutDown(). */ +@Deprecated public abstract class FileIngestModuleAdapter implements FileIngestModule { @Override diff --git a/Core/src/org/sleuthkit/autopsy/ingest/FileIngestPipeline.java b/Core/src/org/sleuthkit/autopsy/ingest/FileIngestPipeline.java index 2f6604e415..12dc2e28b2 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/FileIngestPipeline.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/FileIngestPipeline.java @@ -1,15 +1,15 @@ /* * Autopsy Forensic Browser - * - * Copyright 2014-2015 Basis Technology Corp. + * + * Copyright 2014-2021 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. @@ -18,223 +18,109 @@ */ package org.sleuthkit.autopsy.ingest; -import java.util.ArrayList; -import java.util.Date; import java.util.List; -import java.util.logging.Level; - -import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import java.util.Optional; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; /** - * This class manages a sequence of file level ingest modules for an - * ingest job pipeline. It starts the modules, runs files through them, and shuts them - * down when file level ingest is complete. - *

- * This class is thread-safe. + * A pipeline of file ingest modules for performing file ingest tasks for an + * ingest job. */ -final class FileIngestPipeline { +final class FileIngestPipeline extends IngestTaskPipeline { private static final IngestManager ingestManager = IngestManager.getInstance(); private final IngestJobPipeline ingestJobPipeline; - private final List modules = new ArrayList<>(); - private Date startTime; - private volatile boolean running; /** - * Constructs an object that manages a sequence of file level ingest - * modules. It starts the modules, runs files through them, and shuts them - * down when file level ingest is complete. + * Constructs a pipeline of file ingest modules for performing file ingest + * tasks for an ingest job. * - * @param ingestJobPipeline The ingestJobPipeline that owns the pipeline. - * @param moduleTemplates The ingest module templates that define the - * pipeline. + * @param ingestJobPipeline The ingest job pipeline that owns this pipeline. + * @param moduleTemplates The ingest module templates that define this + * pipeline. */ FileIngestPipeline(IngestJobPipeline ingestJobPipeline, List moduleTemplates) { + super(ingestJobPipeline, moduleTemplates); this.ingestJobPipeline = ingestJobPipeline; - for (IngestModuleTemplate template : moduleTemplates) { - if (template.isFileIngestModuleTemplate()) { - PipelineModule module = new PipelineModule(template.createFileIngestModule(), template.getModuleName()); - modules.add(module); - } + } + + @Override + Optional> acceptModuleTemplate(IngestModuleTemplate template) { + Optional> module = Optional.empty(); + if (template.isFileIngestModuleTemplate()) { + FileIngestModule ingestModule = template.createFileIngestModule(); + module = Optional.of(new FileIngestPipelineModule(ingestModule, template.getModuleName())); } + return module; } - /** - * Queries whether or not there are any ingest modules in this pipeline. - * - * @return True or false. - */ - boolean isEmpty() { - return this.modules.isEmpty(); + @Override + void prepareTask(FileIngestTask task) throws IngestTaskPipelineException { } - /** - * Queries whether or not this pipeline is running. - * - * @return True or false. - */ - boolean isRunning() { - return this.running; - } - - /** - * Returns the start up time of this pipeline. - * - * @return The file processing start time, may be null if this pipeline has - * not been started yet. - */ - Date getStartTime() { - return this.startTime; - } - - /** - * Starts up all of the ingest modules in the pipeline. - * - * @return List of start up errors, possibly empty. - */ - synchronized List startUp() { - this.startTime = new Date(); - this.running = true; - List errors = new ArrayList<>(); - for (PipelineModule module : this.modules) { - try { - module.startUp(new IngestJobContext(this.ingestJobPipeline)); - } catch (Throwable ex) { // Catch-all exception firewall - errors.add(new IngestModuleError(module.getDisplayName(), ex)); - } + @Override + void completeTask(FileIngestTask task) throws IngestTaskPipelineException { + AbstractFile file = null; + try { + file = task.getFile(); + } catch (TskCoreException ex) { + throw new IngestTaskPipelineException(String.format("Failed to get file (file objId = %d)", task.getFileId()), ex); //NON-NLS } - return errors; - } - - /** - * Runs a file through the ingest modules in sequential order. - * - * @param task A file level ingest task containing a file to be processed. - * - * @return A list of processing errors, possible empty. - */ - synchronized List process(FileIngestTask task) { - List errors = new ArrayList<>(); - if (!this.ingestJobPipeline.isCancelled()) { - AbstractFile file; - try { - file = task.getFile(); - } catch (TskCoreException ex) { - // In practice, this task would never have been enqueued since the file - // lookup would have failed there. - errors.add(new IngestModuleError("File Ingest Pipeline", ex)); // NON-NLS - FileIngestPipeline.ingestManager.setIngestTaskProgressCompleted(task); - return errors; + try { + if (!ingestJobPipeline.isCancelled()) { + /* + * Save any updates from the ingest modules to the case + * database. + */ + file.save(); } - for (PipelineModule module : this.modules) { - try { - FileIngestPipeline.ingestManager.setIngestTaskProgress(task, module.getDisplayName()); - this.ingestJobPipeline.setCurrentFileIngestModule(module.getDisplayName(), task.getFile().getName()); - module.process(file); - } catch (Throwable ex) { // Catch-all exception firewall - errors.add(new IngestModuleError(module.getDisplayName(), ex)); - } - if (this.ingestJobPipeline.isCancelled()) { - break; - } - } - - if (!this.ingestJobPipeline.isCancelled()) { - // Save any properties that have not already been saved to the database - try{ - file.save(); - } catch (TskCoreException ex){ - Logger.getLogger(FileIngestPipeline.class.getName()).log(Level.SEVERE, "Failed to save data for file " + file.getId(), ex); //NON-NLS - } + } catch (TskCoreException ex) { + throw new IngestTaskPipelineException(String.format("Failed to save updated data for file (file objId = %d)", task.getFileId()), ex); //NON-NLS + } finally { + if (!ingestJobPipeline.isCancelled()) { IngestManager.getInstance().fireFileIngestDone(file); } file.close(); + ingestManager.setIngestTaskProgressCompleted(task); } - FileIngestPipeline.ingestManager.setIngestTaskProgressCompleted(task); - return errors; } /** - * Shuts down all of the modules in the pipeline. - * - * @return A list of shut down errors, possibly empty. + * A wrapper that adds ingest infrastructure operations to a file ingest + * module. */ - synchronized List shutDown() { - List errors = new ArrayList<>(); - if (this.running == true) { // Don't shut down pipelines that never started - for (PipelineModule module : this.modules) { - try { - module.shutDown(); - } catch (Throwable ex) { // Catch-all exception firewall - errors.add(new IngestModuleError(module.getDisplayName(), ex)); - String msg = ex.getMessage(); - // Jython run-time errors don't seem to have a message, but have details in toString. - if (msg == null) { - msg = ex.toString(); - } - MessageNotifyUtil.Notify.error(NbBundle.getMessage(this.getClass(), "FileIngestPipeline.moduleError.title.text", module.getDisplayName()), msg); - } - } - } - this.running = false; - return errors; - } - - /** - * This class decorates a file level ingest module with a display name. - */ - private static final class PipelineModule implements FileIngestModule { + static final class FileIngestPipelineModule extends IngestTaskPipeline.PipelineModule { private final FileIngestModule module; - private final String displayName; /** - * Constructs an object that decorates a file level ingest module with a - * display name. + * Constructs a wrapper that adds ingest infrastructure operations to a + * file ingest module. * - * @param module The file level ingest module to be decorated. - * @param displayName The display name. + * + * @param module The module. + * @param displayName The display name of the module. */ - PipelineModule(FileIngestModule module, String displayName) { + FileIngestPipelineModule(FileIngestModule module, String displayName) { + super(module, displayName); this.module = module; - this.displayName = displayName; - } - - /** - * Gets the class name of the decorated ingest module. - * - * @return The class name. - */ - String getClassName() { - return module.getClass().getCanonicalName(); - } - - /** - * Gets the display name of the decorated ingest module. - * - * @return The display name. - */ - String getDisplayName() { - return displayName; } @Override - public void startUp(IngestJobContext context) throws IngestModuleException { - module.startUp(context); - } - - @Override - public IngestModule.ProcessResult process(AbstractFile file) { - return module.process(file); - } - - @Override - public void shutDown() { - module.shutDown(); + void performTask(IngestJobPipeline ingestJobPipeline, FileIngestTask task) throws IngestModuleException { + AbstractFile file = null; + try { + file = task.getFile(); + } catch (TskCoreException ex) { + throw new IngestModuleException(String.format("Failed to get file (file objId = %d)", task.getFileId()), ex); //NON-NLS + } + ingestManager.setIngestTaskProgress(task, getDisplayName()); + ingestJobPipeline.setCurrentFileIngestModule(getDisplayName(), file.getName()); + ProcessResult result = module.process(file); + if (result == ProcessResult.ERROR) { + throw new IngestModuleException(String.format("%s experienced an error analyzing file (file objId = %d)", getDisplayName(), task.getFileId())); //NON-NLS + } } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJob.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJob.java index c73dd940d0..decccd4e84 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJob.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJob.java @@ -416,7 +416,7 @@ public final class IngestJob { Snapshot snapshot = pipeline.getSnapshot(getIngestTasksSnapshot); dataSourceProcessingSnapshots.add(new DataSourceProcessingSnapshot(snapshot)); if (null == dataSourceModule) { - DataSourceIngestPipeline.PipelineModule module = snapshot.getDataSourceLevelIngestModule(); + DataSourceIngestPipeline.DataSourcePipelineModule module = snapshot.getDataSourceLevelIngestModule(); if (null != module) { dataSourceModule = new DataSourceIngestModuleHandle(ingestJobPipelines.get(snapshot.getJobId()), module); } @@ -500,7 +500,7 @@ public final class IngestJob { public static class DataSourceIngestModuleHandle { private final IngestJobPipeline ingestJobPipeline; - private final DataSourceIngestPipeline.PipelineModule module; + private final DataSourceIngestPipeline.DataSourcePipelineModule module; private final boolean cancelled; /** @@ -511,7 +511,7 @@ public final class IngestJob { * @param ingestJobPipeline The ingestJobPipeline that owns the data source level ingest module. * @param module The data source level ingest module. */ - private DataSourceIngestModuleHandle(IngestJobPipeline ingestJobPipeline, DataSourceIngestPipeline.PipelineModule module) { + private DataSourceIngestModuleHandle(IngestJobPipeline ingestJobPipeline, DataSourceIngestPipeline.DataSourcePipelineModule module) { this.ingestJobPipeline = ingestJobPipeline; this.module = module; this.cancelled = ingestJobPipeline.currentDataSourceIngestModuleIsCancelled(); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobPipeline.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobPipeline.java index d5ba4c783b..384f5c63c5 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobPipeline.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobPipeline.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014-2019 Basis Technology Corp. + * Copyright 2014-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -553,7 +553,7 @@ final class IngestJobPipeline { /* * If the data-source-level ingest pipelines were successfully started, - * start the Start the file-level ingest pipelines (one per file ingest + * start the file-level ingest pipelines (one per pipeline file ingest * thread). */ if (errors.isEmpty()) { @@ -940,7 +940,7 @@ final class IngestJobPipeline { synchronized (this.dataSourceIngestPipelineLock) { if (!this.isCancelled() && !this.currentDataSourceIngestPipeline.isEmpty()) { List errors = new ArrayList<>(); - errors.addAll(this.currentDataSourceIngestPipeline.process(task)); + errors.addAll(this.currentDataSourceIngestPipeline.performTask(task)); if (!errors.isEmpty()) { logIngestModuleErrors(errors); } @@ -1014,7 +1014,7 @@ final class IngestJobPipeline { * Run the file through the pipeline. */ List errors = new ArrayList<>(); - errors.addAll(pipeline.process(task)); + errors.addAll(pipeline.performTask(task)); if (!errors.isEmpty()) { logIngestModuleErrors(errors, file); } @@ -1232,9 +1232,9 @@ final class IngestJobPipeline { * * @return The currently running module, may be null. */ - DataSourceIngestPipeline.PipelineModule getCurrentDataSourceIngestModule() { - if (null != this.currentDataSourceIngestPipeline) { - return this.currentDataSourceIngestPipeline.getCurrentlyRunningModule(); + DataSourceIngestPipeline.DataSourcePipelineModule getCurrentDataSourceIngestModule() { + if (null != currentDataSourceIngestPipeline) { + return (DataSourceIngestPipeline.DataSourcePipelineModule) currentDataSourceIngestPipeline.getCurrentlyRunningModule(); } else { return null; } @@ -1274,7 +1274,7 @@ final class IngestJobPipeline { } } } - + // If a data source had no tasks in progress it may now be complete. checkForStageCompleted(); } @@ -1353,18 +1353,18 @@ final class IngestJobPipeline { logErrorMessage(Level.SEVERE, String.format("%s experienced an error during analysis", error.getModuleDisplayName()), error.getThrowable()); //NON-NLS } } - + /** * Write ingest module errors to the log. * * @param errors The errors. - * @param file AbstractFile that caused the errors. + * @param file AbstractFile that caused the errors. */ private void logIngestModuleErrors(List errors, AbstractFile file) { for (IngestModuleError error : errors) { logErrorMessage(Level.SEVERE, String.format("%s experienced an error during analysis while processing file %s, object ID %d", error.getModuleDisplayName(), file.getName(), file.getId()), error.getThrowable()); //NON-NLS } - } + } /** * Gets a snapshot of this jobs state and performance. diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java index 95696378b7..d8a8480776 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2012-2019 Basis Technology Corp. + * Copyright 2012-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -804,7 +804,7 @@ public class IngestManager implements IngestProgressSnapshotProvider { * * @param task The file level ingest job task that was completed. */ - void setIngestTaskProgressCompleted(FileIngestTask task) { + void setIngestTaskProgressCompleted(IngestTask task) { IngestThreadActivitySnapshot prevSnap = ingestThreadActivitySnapshots.get(task.getThreadId()); IngestThreadActivitySnapshot newSnap = new IngestThreadActivitySnapshot(task.getThreadId()); ingestThreadActivitySnapshots.put(task.getThreadId(), newSnap); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestModule.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestModule.java index c5628d1912..10114ac288 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestModule.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2012-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,9 +25,8 @@ package org.sleuthkit.autopsy.ingest; * ingest job it performs (one for each thread that it is using). * * Autopsy will call startUp() before any data is processed, will pass any data - * to be analyzed into the process() method (FileIngestModule.process() or - * DataSourceIngestModule.process()), and call shutDown() after either all data - * is analyzed or the user has canceled the job. + * to be analyzed into the process() method, and call shutDown() after either + * all data is analyzed or the user has canceled the job. * * Autopsy may use multiple threads to complete an ingest job, but it is * guaranteed that a module instance will always be called from a single thread. @@ -47,25 +46,53 @@ package org.sleuthkit.autopsy.ingest; public interface IngestModule { /** - * A return code for derived class process() methods. + * Invoked by Autopsy to allow an ingest module instance to set up any + * internal data structures and acquire any private resources it will need + * during an ingest job. If the module depends on loading any resources, it + * should do so in this method so that it can throw an exception in the case + * of an error and alert the user. Exceptions that are thrown from startUp() + * are logged and stop processing of the data source. + * + * IMPORTANT: If the module instances must share resources, the modules are + * responsible for synchronizing access to the shared resources and doing + * reference counting as required to release those resources correctly. + * Also, more than one ingest job may be in progress at any given time. This + * must also be taken into consideration when sharing resources between + * module instances. See IngestModuleReferenceCounter. + * + * @param context Provides data and services specific to the ingest job and + * the ingest pipeline of which the module is a part. + * + * @throws org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException */ - public enum ProcessResult { - - OK, - ERROR - }; + default void startUp(IngestJobContext context) throws IngestModuleException { + } /** - * A custom exception for the use of ingest modules. + * Invoked by Autopsy when an ingest job is completed (either because the + * data has been analyzed or because the job was cancelled), before the + * ingest module instance is discarded. The module should respond by doing + * things like releasing private resources, submitting final results, and + * posting a final ingest message. + * + * IMPORTANT: If the module instances must share resources, the modules are + * responsible for synchronizing access to the shared resources and doing + * reference counting as required to release those resources correctly. + * Also, more than one ingest job may be in progress at any given time. This + * must also be taken into consideration when sharing resources between + * module instances. See IngestModuleReferenceCounter. + * + */ + default void shutDown() { + } + + /** + * An exception for the use of ingest modules. */ public class IngestModuleException extends Exception { private static final long serialVersionUID = 1L; - @Deprecated - public IngestModuleException() { - } - public IngestModuleException(String message) { super(message); } @@ -73,26 +100,21 @@ public interface IngestModule { public IngestModuleException(String message, Throwable cause) { super(message, cause); } + + @Deprecated + public IngestModuleException() { + } + } /** - * Invoked by Autopsy to allow an ingest module instance to set up any - * internal data structures and acquire any private resources it will need - * during an ingest job. If the module depends on loading any resources, it - * should do so in this method so that it can throw an exception in the case - * of an error and alert the user. Exceptions that are thrown from process() - * and shutDown() are logged, but do not stop processing of the data source. - * - * @param context Provides data and services specific to the ingest job and - * the ingest pipeline of which the module is a part. - * - * @throws org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException + * A return code for subclass process() methods. */ - void startUp(IngestJobContext context) throws IngestModuleException; + public enum ProcessResult { + + OK, + ERROR + + }; - /** - * TODO: The next time an API change is legal, add a cancel() method and - * remove the "ingest job is canceled" queries from the IngestJobContext - * class. - */ } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Snapshot.java b/Core/src/org/sleuthkit/autopsy/ingest/Snapshot.java index 19a0e41c35..dc7eceaad8 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/Snapshot.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/Snapshot.java @@ -34,7 +34,7 @@ public final class Snapshot implements Serializable { private final long jobId; private final long jobStartTime; private final long snapShotTime; - transient private final DataSourceIngestPipeline.PipelineModule dataSourceLevelIngestModule; + transient private final DataSourceIngestPipeline.DataSourcePipelineModule dataSourceLevelIngestModule; private final boolean fileIngestRunning; private final Date fileIngestStartTime; private final long processedFiles; @@ -48,7 +48,7 @@ public final class Snapshot implements Serializable { * Constructs an object to store basic diagnostic statistics for a data * source ingest job. */ - Snapshot(String dataSourceName, long jobId, long jobStartTime, DataSourceIngestPipeline.PipelineModule dataSourceIngestModule, + Snapshot(String dataSourceName, long jobId, long jobStartTime, DataSourceIngestPipeline.DataSourcePipelineModule dataSourceIngestModule, boolean fileIngestRunning, Date fileIngestStartTime, boolean jobCancelled, IngestJob.CancellationReason cancellationReason, List cancelledModules, long processedFiles, long estimatedFilesToProcess, @@ -110,7 +110,7 @@ public final class Snapshot implements Serializable { return jobStartTime; } - DataSourceIngestPipeline.PipelineModule getDataSourceLevelIngestModule() { + DataSourceIngestPipeline.DataSourcePipelineModule getDataSourceLevelIngestModule() { return this.dataSourceLevelIngestModule; } From 6838641d106284c344cb8000b8fb054b34202b80 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 22 Feb 2021 16:03:29 -0500 Subject: [PATCH 24/42] 7332 Refactor ingest task pipelines for extensibility --- .../ingest/DataArtifactIngestModule.java | 40 ++ .../autopsy/ingest/IngestTaskPipeline.java | 353 ++++++++++++++++++ 2 files changed, 393 insertions(+) create mode 100755 Core/src/org/sleuthkit/autopsy/ingest/DataArtifactIngestModule.java create mode 100755 Core/src/org/sleuthkit/autopsy/ingest/IngestTaskPipeline.java diff --git a/Core/src/org/sleuthkit/autopsy/ingest/DataArtifactIngestModule.java b/Core/src/org/sleuthkit/autopsy/ingest/DataArtifactIngestModule.java new file mode 100755 index 0000000000..b5677242cb --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/DataArtifactIngestModule.java @@ -0,0 +1,40 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException; +import org.sleuthkit.datamodel.DataArtifact; + +/** + * Intercace that must be implemented by all ingest modules that process + * artifacts. + */ +public interface DataArtifactIngestModule { + + /** + * Processes a data artifact. + * + * @param artifact The artifact to process. + * + * @throws IngestModuleException Exception is thrown if there is an error + * while processing the data artifact. + */ + void process(DataArtifact artifact) throws IngestModuleException; + +} diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestTaskPipeline.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestTaskPipeline.java new file mode 100755 index 0000000000..aaa430b05e --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestTaskPipeline.java @@ -0,0 +1,353 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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 java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; + +/** + * An abstract superclass for pipelines of ingest modules for a given ingest + * task type. Some examples of ingest task types: data source level ingest + * tasks, file ingest tasks, data artifacts ingest tasks, etc. Subclasses need + * to implement a specialization of the inner PipelineModule decorator abstartc + * superclass for they type of ingest modules that make up the pipeline. + * + * @param The ingest task type. + */ +abstract class IngestTaskPipeline { + + private static final IngestManager ingestManager = IngestManager.getInstance(); + private final IngestJobPipeline ingestJobPipeline; + private final List moduleTemplates; + private final List> modules; + private volatile Date startTime; + private volatile boolean running; + private volatile PipelineModule currentModule; + + /** + * Constructs an instance of an abstract superclass for pipelines of ingest + * modules for a given ingest task type. Some examples of ingest task types: + * data source level ingest tasks, file ingest tasks, data artifacts ingest + * tasks, etc. Subclasses need to implement a specialization of the inner + * PipelineModule decorator abstartc superclass for they type of ingest + * modules that make up the pipeline. + * + * @param ingestJobPipeline The ingest job pipeline that owns this pipeline. + * @param moduleTemplates The ingest module templates that define this + * pipeline. + */ + IngestTaskPipeline(IngestJobPipeline ingestJobPipeline, List moduleTemplates) { + this.ingestJobPipeline = ingestJobPipeline; + this.moduleTemplates = moduleTemplates; + modules = new ArrayList<>(); + } + + /** + * Indicates whether or not there are any ingest modules in this pipeline. + * + * @return True or false. + */ + boolean isEmpty() { + return modules.isEmpty(); + } + + /** + * Queries whether or not this pipeline is running, i.e., started and not + * shut down. + * + * @return True or false. + */ + boolean isRunning() { + return running; + } + + /** + * Starts up the ingest modules in this pipeline. + * + * @return A list of ingest module startup errors, possibly empty. + */ + List startUp() { + createIngestModules(moduleTemplates); + return startUpIngestModules(); + } + + /** + * Creates the ingest modules for this pipeline. + * + * @param moduleTemplates The ingest module templates avaialble to this + * pipeline. + */ + private void createIngestModules(List moduleTemplates) { + for (IngestModuleTemplate template : moduleTemplates) { + Optional> module = acceptModuleTemplate(template); + if (module.isPresent()) { + modules.add(module.get()); + } + } + } + + /** + * Determines if the type of ingest module that can be created from a given + * ingest module template should be added to this pipeline. If so, the + * ingest module is created and returned. + * + * @param ingestModuleTemplate The ingest module template to be used or + * ignored, as appropriate to the pipeline type. + * + * @return An Optional that is either empty or contains a newly created and + * decorated ingest module. + */ + abstract Optional> acceptModuleTemplate(IngestModuleTemplate ingestModuleTemplate); + + /** + * Starts up the ingest modules in the pipeline. + * + * @return A list of ingest module startup errors, possibly empty. + */ + private List startUpIngestModules() { + startTime = new Date(); + running = true; + List errors = new ArrayList<>(); + for (PipelineModule module : modules) { + try { + module.startUp(new IngestJobContext(ingestJobPipeline)); + } catch (Throwable ex) { // Catch-all exception firewall + errors.add(new IngestModuleError(module.getDisplayName(), ex)); + } + } + return errors; + } + + /** + * Returns the start up time of this pipeline. + * + * @return The file processing start time, may be null if this pipeline has + * not been started yet. + */ + Date getStartTime() { + if (startTime == null) { + throw new IllegalStateException("startUp() was not called"); //NON-NLS + } + return new Date(startTime.getTime()); + } + + /** + * Does any preparation required before performing the a task. + * + * @param task The task. + * + * @throws IngestTaskPipelineException Thrown if there is an error preparing + * to perform the task. + */ + abstract void prepareTask(T task) throws IngestTaskPipelineException; + + /** + * Performs an ingest task using the ingest modules in this pipeline. + * + * @param task The task. + * + * @return A list of ingest module task processing errors, possibly empty. + */ + List performTask(T task) { + List errors = new ArrayList<>(); + if (!this.ingestJobPipeline.isCancelled()) { + try { + prepareTask(task); + } catch (IngestTaskPipelineException ex) { + errors.add(new IngestModuleError("Ingest Task Pipeline", ex)); //NON-NLS + return errors; + } + for (PipelineModule module : modules) { + try { + currentModule = module; + currentModule.setProcessingStartTime(); + module.performTask(ingestJobPipeline, task); + } catch (Throwable ex) { // Catch-all exception firewall + errors.add(new IngestModuleError(module.getDisplayName(), ex)); + } + if (ingestJobPipeline.isCancelled()) { + break; + } + } + } + try { + completeTask(task); + } catch (IngestTaskPipelineException ex) { + errors.add(new IngestModuleError("Ingest Task Pipeline", ex)); //NON-NLS + } + ingestManager.setIngestTaskProgressCompleted(task); + currentModule = null; + return errors; + } + + /** + * Gets the currently running module. + * + * @return The module, possibly null if no module is currently running. + */ + PipelineModule getCurrentlyRunningModule() { + return currentModule; + } + + /** + * Does any clean up required after performing the current task. + * + * @param task The current task. + * + * @throws IngestTaskPipelineException Thrown if there is an error cleaning + * up after performing the task. + */ + abstract void completeTask(T task) throws IngestTaskPipelineException; + + /** + * Shuts down all of the modules in the pipeline. + * + * @return A list of shut down errors, possibly empty. + */ + synchronized List shutDown() { + List errors = new ArrayList<>(); + if (running == true) { + for (PipelineModule module : modules) { + try { + module.shutDown(); + } catch (Throwable ex) { // Catch-all exception firewall + errors.add(new IngestModuleError(module.getDisplayName(), ex)); + String msg = ex.getMessage(); + if (msg == null) { + /* + * Jython run-time errors don't seem to have a message, + * but have details in toString(). + */ + msg = ex.toString(); + } + MessageNotifyUtil.Notify.error(NbBundle.getMessage(this.getClass(), "FileIngestPipeline.moduleError.title.text", module.getDisplayName()), msg); + } + } + } + running = false; + return errors; + } + + /** + * An abstract superclass for a wrapper that adds ingest infrastructure + * operations to an ingest module. + */ + static abstract class PipelineModule implements IngestModule { + + private final IngestModule module; + private final String displayName; + + /* + * This field is intended to be written to in an ingest thread and read + * from in an ingest snaphot thread. + */ + private volatile Date processingStartTime; + + /** + * Constructs an instance of an abstract superclass for a wrapper that + * adds ingest infrastructure operations to an ingest module. + * + * @param module The ingest module to be decorated. + * @param displayName The display name for the module. + */ + PipelineModule(IngestModule module, String displayName) { + this.module = module; + this.displayName = displayName; + this.processingStartTime = new Date(); + } + + /** + * Gets the class name of the wrapped ingest module. + * + * @return The class name. + */ + String getClassName() { + return module.getClass().getCanonicalName(); + } + + /** + * Gets the display name of the wrapped ingest module. + * + * @return The display name. + */ + String getDisplayName() { + return displayName; + } + + /** + * Sets the processing start time for the wrapped module to the system + * time when this method is called. + */ + void setProcessingStartTime() { + processingStartTime = new Date(); + } + + /** + * Gets the the processing start time for the wrapped module, as set by + * + * @return The start time, will be null if the module has not started + * processing the data source yet. + */ + Date getProcessingStartTime() { + if (processingStartTime == null) { + throw new IllegalStateException("setProcessingStartTime() was not called"); //NON-NLS + } + return new Date(processingStartTime.getTime()); + } + + @Override + public void startUp(IngestJobContext context) throws IngestModuleException { + module.startUp(context); + } + + /** + * Processes an ingest task. + * + * @param ingestJobPipeline The ingest job pipeline that owns the ingest + * module pipeline this module belongs to. + * @param task The task to process. + * + * @throws IngestModuleException Excepton thrown if there is an error + * performing the task. + */ + abstract void performTask(IngestJobPipeline ingestJobPipeline, T task) throws IngestModuleException; + + } + + /** + * An exception for the use of ingest task pipelines. + */ + public static class IngestTaskPipelineException extends Exception { + + private static final long serialVersionUID = 1L; + + public IngestTaskPipelineException(String message) { + super(message); + } + + public IngestTaskPipelineException(String message, Throwable cause) { + super(message, cause); + } + } + +} From ee4c03f6450b7f620fe90e9e0df961c43eeef771 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Mon, 22 Feb 2021 16:26:26 -0500 Subject: [PATCH 25/42] Fixed the naming of the update and create os account methods in RA --- .../autopsy/recentactivity/ExtractRegistry.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java index bebb543a9a..6cb02f65b8 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java @@ -872,7 +872,7 @@ class ExtractRegistry extends Extract { // For now both an OsAccount and the // TSK_OS_ACCOUNT artifact will be created. try{ - updateOsAccount(regFile, sid, username, homeDir); + createOrUpdateOsAccount(regFile, sid, username, homeDir); } catch(TskCoreException | TskDataException ex) { logger.log(Level.SEVERE, String.format("Failed to create OsAccount for file: %s, sid: %s", regFile.getId(), sid)); @@ -1158,14 +1158,14 @@ class ExtractRegistry extends Extract { String sid = optional.get(); Map userInfo = userInfoMap.remove(sid); if(userInfo != null) { - createOrUpdateOsAccount(osAccount, userInfo, groupMap.get(sid), regAbstractFile); + updateOsAccount(osAccount, userInfo, groupMap.get(sid), regAbstractFile); } } //add remaining userinfos as accounts; for (Map userInfo : userInfoMap.values()) { OsAccount osAccount = accountMgr.createWindowsAccount(userInfo.get(SID_KEY), null, null, host, OsAccountRealm.RealmScope.UNKNOWN); - createOrUpdateOsAccount(osAccount, userInfo, groupMap.get(userInfo.get(SID_KEY)), regAbstractFile); + updateOsAccount(osAccount, userInfo, groupMap.get(userInfo.get(SID_KEY)), regAbstractFile); } // Existing TSK_OS_ACCOUNT code. @@ -2204,7 +2204,7 @@ class ExtractRegistry extends Extract { * @throws TskCoreException * @throws TskDataException */ - private void updateOsAccount(AbstractFile file, String sid, String userName, String homeDir) throws TskCoreException, TskDataException { + private void createOrUpdateOsAccount(AbstractFile file, String sid, String userName, String homeDir) throws TskCoreException, TskDataException { OsAccountManager accountMgr = tskCase.getOsAccountManager(); HostManager hostMrg = tskCase.getHostManager(); Host host = hostMrg.getHost((DataSource)dataSource); @@ -2277,7 +2277,7 @@ class ExtractRegistry extends Extract { * @throws TskDataException * @throws TskCoreException */ - private void createOrUpdateOsAccount(OsAccount osAccount, Map userInfo, List groupList, AbstractFile regFile) throws TskDataException, TskCoreException { + private void updateOsAccount(OsAccount osAccount, Map userInfo, List groupList, AbstractFile regFile) throws TskDataException, TskCoreException { Host host = ((DataSource)dataSource).getHost(); SimpleDateFormat regRipperTimeFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy 'Z'", US); From 78a40f9add63d211f2368b38266d8eb50c642d8d Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 22 Feb 2021 18:22:01 -0500 Subject: [PATCH 26/42] menu text fix --- Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties | 2 +- .../org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 8206f18798..4874b10d2b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -262,5 +262,5 @@ AddImageWizardSelectHostVisual.hostDescription.text=Hosts are used to organize d AddImageWizardSelectHostVisual.useExistingHostRadio.text=Use existing host AddImageWizardSelectHostVisual.specifyNewHostTextField.text= AddImageWizardSelectHostVisual.specifyNewHostRadio.text=Specify new host name -AddImageWizardSelectHostVisual.generateNewRadio.text=Generate new based on based on data source name +AddImageWizardSelectHostVisual.generateNewRadio.text=Generate new host name... AddImageWizardSelectHostVisual.validationMessage.text=\ diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED index 2a22f05c7f..91295677b0 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED @@ -483,5 +483,5 @@ AddImageWizardSelectHostVisual.hostDescription.text=Hosts are used to organize d AddImageWizardSelectHostVisual.useExistingHostRadio.text=Use existing host AddImageWizardSelectHostVisual.specifyNewHostTextField.text= AddImageWizardSelectHostVisual.specifyNewHostRadio.text=Specify new host name -AddImageWizardSelectHostVisual.generateNewRadio.text=Generate new based on based on data source name +AddImageWizardSelectHostVisual.generateNewRadio.text=Generate new host name... AddImageWizardSelectHostVisual.validationMessage.text=\ From bba10d45ba4b6978e04b380f8383c93c2018d1af Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 22 Feb 2021 18:29:37 -0500 Subject: [PATCH 27/42] test fixes --- .../autopsy/testing/AutopsyTestCases.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java b/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java index de8cf07fc8..91a362deaa 100644 --- a/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java +++ b/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java @@ -143,6 +143,10 @@ public class AutopsyTestCases { while (!wo.btNext().isEnabled()) { new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled } + + // pass by host menu with auto-generate host (which should already be selected) + wo.btNext().clickMouse(); + //select the toggle button for Disk Image or VM File it will be the first button created and proceed to next panel JToggleButtonOperator jtbo = new JToggleButtonOperator(wo, 0); jtbo.clickMouse(); @@ -173,6 +177,10 @@ public class AutopsyTestCases { while (!wo.btNext().isEnabled()) { new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled } + + // pass by host menu with auto-generate host (which should already be selected) + wo.btNext().clickMouse(); + //select the toggle button for Logical Files it will be the third button created and proceed to next panel JToggleButtonOperator jtbo = new JToggleButtonOperator(wo, 2); jtbo.clickMouse(); @@ -197,6 +205,10 @@ public class AutopsyTestCases { while (!wo.btFinish().isEnabled()) { new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process } + + // pass by host menu with auto-generate host (which should already be selected) + wo.btNext().clickMouse(); + logger.log(Level.INFO, "Add image took {0}ms", (System.currentTimeMillis() - start)); wo.btFinish().clickMouse(); } catch (TimeoutExpiredException ex) { @@ -218,6 +230,10 @@ public class AutopsyTestCases { while (!wo.btNext().isEnabled()) { new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled } + + // pass by host menu with auto-generate host (which should already be selected) + wo.btNext().clickMouse(); + JTableOperator jto = new JTableOperator(wo, 0); int row = jto.findCellRow("Hash Lookup", 2, 0); jto.clickOnCell(row, 1); @@ -277,6 +293,10 @@ public class AutopsyTestCases { while (!wo.btNext().isEnabled()) { new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled } + + // pass by host menu with auto-generate host (which should already be selected) + wo.btNext().clickMouse(); + JTableOperator jto = new JTableOperator(wo, 0); int row = jto.findCellRow("Keyword Search", 2, 0); jto.clickOnCell(row, 1); @@ -316,6 +336,10 @@ public class AutopsyTestCases { jbo2.pushNoBlock(); WizardOperator wo = new WizardOperator("Add Data Source"); new Timeout("pausing", 10000).sleep(); // let things catch up + + // pass by host menu with auto-generate host (which should already be selected) + wo.btNext().clickMouse(); + wo.btNext().clickMouse(); } catch (TimeoutExpiredException ex) { screenshot("TimeoutScreenshot"); From ddc6c9be63226ff66d8a0384786e8d576f0d1df7 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 22 Feb 2021 19:11:35 -0500 Subject: [PATCH 28/42] fixes --- .../sleuthkit/autopsy/testing/AutopsyTestCases.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java b/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java index 91a362deaa..69897aef9d 100644 --- a/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java +++ b/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java @@ -206,9 +206,6 @@ public class AutopsyTestCases { new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process } - // pass by host menu with auto-generate host (which should already be selected) - wo.btNext().clickMouse(); - logger.log(Level.INFO, "Add image took {0}ms", (System.currentTimeMillis() - start)); wo.btFinish().clickMouse(); } catch (TimeoutExpiredException ex) { @@ -231,9 +228,6 @@ public class AutopsyTestCases { new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled } - // pass by host menu with auto-generate host (which should already be selected) - wo.btNext().clickMouse(); - JTableOperator jto = new JTableOperator(wo, 0); int row = jto.findCellRow("Hash Lookup", 2, 0); jto.clickOnCell(row, 1); @@ -294,9 +288,6 @@ public class AutopsyTestCases { new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled } - // pass by host menu with auto-generate host (which should already be selected) - wo.btNext().clickMouse(); - JTableOperator jto = new JTableOperator(wo, 0); int row = jto.findCellRow("Keyword Search", 2, 0); jto.clickOnCell(row, 1); @@ -336,10 +327,6 @@ public class AutopsyTestCases { jbo2.pushNoBlock(); WizardOperator wo = new WizardOperator("Add Data Source"); new Timeout("pausing", 10000).sleep(); // let things catch up - - // pass by host menu with auto-generate host (which should already be selected) - wo.btNext().clickMouse(); - wo.btNext().clickMouse(); } catch (TimeoutExpiredException ex) { screenshot("TimeoutScreenshot"); From 158bf647dc25cf01f370b852c5fefbcd89bac869 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 22 Feb 2021 19:14:03 -0500 Subject: [PATCH 29/42] fixes --- .../src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java b/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java index 69897aef9d..c4d5c8dae8 100644 --- a/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java +++ b/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java @@ -205,7 +205,6 @@ public class AutopsyTestCases { while (!wo.btFinish().isEnabled()) { new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process } - logger.log(Level.INFO, "Add image took {0}ms", (System.currentTimeMillis() - start)); wo.btFinish().clickMouse(); } catch (TimeoutExpiredException ex) { @@ -227,7 +226,6 @@ public class AutopsyTestCases { while (!wo.btNext().isEnabled()) { new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled } - JTableOperator jto = new JTableOperator(wo, 0); int row = jto.findCellRow("Hash Lookup", 2, 0); jto.clickOnCell(row, 1); @@ -287,7 +285,6 @@ public class AutopsyTestCases { while (!wo.btNext().isEnabled()) { new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled } - JTableOperator jto = new JTableOperator(wo, 0); int row = jto.findCellRow("Keyword Search", 2, 0); jto.clickOnCell(row, 1); From 94435b03baff2183cebb4b71c24c0ceebcc59d03 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Mon, 22 Feb 2021 19:19:10 -0500 Subject: [PATCH 30/42] Added event firing for OsAccount objects --- .../sleuthkit/autopsy/casemodule/Case.java | 40 +++++++++++- .../events/OsAccountAddedEvent.java | 35 ++++++++++ .../events/OsAccountChangedEvent.java | 34 ++++++++++ .../casemodule/events/OsAccountEvent.java | 64 +++++++++++++++++++ .../events/TskDataModelChangeEvent.java | 4 +- 5 files changed, 174 insertions(+), 3 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/events/OsAccountAddedEvent.java create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/events/OsAccountChangedEvent.java create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/events/OsAccountEvent.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index c2fd9d822f..289b94f4ad 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -81,6 +81,8 @@ import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent; import org.sleuthkit.autopsy.casemodule.events.DataSourceDeletedEvent; import org.sleuthkit.autopsy.casemodule.events.DataSourceNameChangedEvent; +import org.sleuthkit.autopsy.casemodule.events.OsAccountAddedEvent; +import org.sleuthkit.autopsy.casemodule.events.OsAccountChangedEvent; import org.sleuthkit.autopsy.casemodule.events.ReportAddedEvent; import org.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeData.CaseNodeDataException; import org.sleuthkit.autopsy.casemodule.multiusercases.CoordinationServiceUtils; @@ -128,6 +130,10 @@ import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.FileSystem; import org.sleuthkit.datamodel.Image; +import org.sleuthkit.datamodel.OsAccount; +import org.sleuthkit.datamodel.OsAccountManager; +import org.sleuthkit.datamodel.OsAccountManager.OsAccountsAddedEvent; +import org.sleuthkit.datamodel.OsAccountManager.OsAccountsChangedEvent; import org.sleuthkit.datamodel.Report; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TimelineManager; @@ -409,7 +415,17 @@ public class Case { * An item in the central repository has had its comment modified. The * old value is null, the new value is string for current comment. */ - CR_COMMENT_CHANGED; + CR_COMMENT_CHANGED, + /** + * OSAccount associated with the current case added. Call getOsAccount + * to get the added account; + */ + OS_ACCOUNT_ADDED, + /** + * OSAccount associated with the current case has changed. + * Call getOsAccount to get the changed account; + */ + OS_ACCOUNT_CHANGED; }; @@ -443,6 +459,20 @@ public class Case { event.getArtifacts(artifactType))); } } + + @Subscribe + public void publishOsAccountAddedEvent(OsAccountManager.OsAccountsAddedEvent event) { + for(OsAccount account: event.getOsAcounts()) { + eventPublisher.publish(new OsAccountAddedEvent(account)); + } + } + + @Subscribe + public void publishOsAccountAddedEvent(OsAccountManager.OsAccountsChangedEvent event) { + for(OsAccount account: event.getOsAcounts()) { + eventPublisher.publish(new OsAccountChangedEvent(account)); + } + } } /** @@ -1639,7 +1669,15 @@ public class Case { public void notifyBlackBoardArtifactTagDeleted(BlackboardArtifactTag deletedTag) { eventPublisher.publish(new BlackBoardArtifactTagDeletedEvent(deletedTag)); } + + public void notifyOsAccountAdded(OsAccount account) { + eventPublisher.publish(new OsAccountAddedEvent(account)); + } + public void notifyOsAccountChanged(OsAccount account) { + eventPublisher.publish(new OsAccountChangedEvent(account)); + } + /** * Adds a report to the case. * diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/events/OsAccountAddedEvent.java b/Core/src/org/sleuthkit/autopsy/casemodule/events/OsAccountAddedEvent.java new file mode 100755 index 0000000000..c9f89903f4 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/events/OsAccountAddedEvent.java @@ -0,0 +1,35 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.events; + +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.OsAccount; + +/** + * Event published when an OsAccount is added to a case. + */ +public final class OsAccountAddedEvent extends OsAccountEvent { + + private static final long serialVersionUID = 1L; + + public OsAccountAddedEvent(OsAccount account) { + super(Case.Events.OS_ACCOUNT_ADDED.toString(), account); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/events/OsAccountChangedEvent.java b/Core/src/org/sleuthkit/autopsy/casemodule/events/OsAccountChangedEvent.java new file mode 100755 index 0000000000..237373a8b9 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/events/OsAccountChangedEvent.java @@ -0,0 +1,34 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.events; + +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.OsAccount; + +/** + * Event published when an OsAccount is updated. + */ +public final class OsAccountChangedEvent extends OsAccountEvent { + + private static final long serialVersionUID = 1L; + + public OsAccountChangedEvent(OsAccount account) { + super(Case.Events.OS_ACCOUNT_CHANGED.toString(), account); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/events/OsAccountEvent.java b/Core/src/org/sleuthkit/autopsy/casemodule/events/OsAccountEvent.java new file mode 100755 index 0000000000..22b0622ba8 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/events/OsAccountEvent.java @@ -0,0 +1,64 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.events; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.sleuthkit.datamodel.OsAccount; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Parent class for specific OsAccount event classes. + */ +class OsAccountEvent extends TskDataModelChangeEvent { + + private static final long serialVersionUID = 1L; + + /** + * Construct a new OsAccountEvent. + * + * @param eventName The name of the event. + * @param account The OsAccount the event applies to. + */ + OsAccountEvent(String eventName, OsAccount account) { + super(eventName, Stream.of(account.getId()).collect(Collectors.toList()), Stream.of(account).collect(Collectors.toList())); + } + + /** + * Returns the OsAccount that changed. + * + * @return The OsAccount that was changed. + */ + public OsAccount getOsAccount() { + List accounts = getNewValue(); + return accounts.get(0); + } + + @Override + protected List getDataModelObjects(SleuthkitCase caseDb, List ids) throws TskCoreException { + Long id = ids.get(0); + OsAccount account = caseDb.getOsAccountManager().getOsAccount(id); + List accounts = new ArrayList<>(); + accounts.add(account); + return accounts; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/events/TskDataModelChangeEvent.java b/Core/src/org/sleuthkit/autopsy/casemodule/events/TskDataModelChangeEvent.java index 891aed0f75..1bd9fd81ac 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/events/TskDataModelChangeEvent.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/events/TskDataModelChangeEvent.java @@ -75,8 +75,8 @@ public abstract class TskDataModelChangeEvent extends AutopsyEvent { * * @return The unique IDs. */ - public final List getDataModelObjectIds() { - return Collections.unmodifiableList(dataModelObjects); + public final List getDataModelObjectIds() { + return Collections.unmodifiableList(dataModelObjectIds); } /** From 040b7d797798f08173f06311a2e5120ee0790d5c Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 23 Feb 2021 08:57:24 -0500 Subject: [PATCH 31/42] variable fix --- test/script/regression.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/script/regression.py b/test/script/regression.py index e217ef8694..1b42f623bc 100644 --- a/test/script/regression.py +++ b/test/script/regression.py @@ -348,9 +348,10 @@ class TestRunner(object): mu_su_str = "multi" if test_data.isMultiUser else "single" for file in glob.glob(test_data.output_path + "/*-Diff.txt"): + newPath = test_data.main_config.args.diff_files_output_folder + "/" + test_data.image + "-" + mu_su_str + "-" + os.path.basename(file) # Eg. copies HTML-Report-Diff.txt to -HTML-Report-Diff.txt - shutil.copy(file, test_data.main_config.args.diff_files_output_folder + - "/" + test_data.image + "-" + mus_su_str + "-" + os.path.basename(file)) + print('copying ' + str(file) + ' to ' + newPath) + shutil.copy(file, newPath) copied = True if not copied: print_report([], "NO DIFF FILES COPIED FROM " + test_data.output_path, "") From eb81320ffd7e1b72ab81dbb92462fbd3532be7d4 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 23 Feb 2021 09:44:53 -0500 Subject: [PATCH 32/42] text fix --- Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties | 2 +- .../org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 4874b10d2b..f3dfe72020 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -262,5 +262,5 @@ AddImageWizardSelectHostVisual.hostDescription.text=Hosts are used to organize d AddImageWizardSelectHostVisual.useExistingHostRadio.text=Use existing host AddImageWizardSelectHostVisual.specifyNewHostTextField.text= AddImageWizardSelectHostVisual.specifyNewHostRadio.text=Specify new host name -AddImageWizardSelectHostVisual.generateNewRadio.text=Generate new host name... +AddImageWizardSelectHostVisual.generateNewRadio.text=Generate new host name based on data source name AddImageWizardSelectHostVisual.validationMessage.text=\ diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED index 91295677b0..f731913af5 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED @@ -483,5 +483,5 @@ AddImageWizardSelectHostVisual.hostDescription.text=Hosts are used to organize d AddImageWizardSelectHostVisual.useExistingHostRadio.text=Use existing host AddImageWizardSelectHostVisual.specifyNewHostTextField.text= AddImageWizardSelectHostVisual.specifyNewHostRadio.text=Specify new host name -AddImageWizardSelectHostVisual.generateNewRadio.text=Generate new host name... +AddImageWizardSelectHostVisual.generateNewRadio.text=Generate new host name based on data source name AddImageWizardSelectHostVisual.validationMessage.text=\ From 9c940ad01386f08920fdd7591da99e435b734f12 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 23 Feb 2021 11:33:41 -0500 Subject: [PATCH 33/42] addressed review comments --- .../recentactivity/ExtractRegistry.java | 62 ++++++++++--------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java index 6cb02f65b8..b04b386442 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java @@ -69,6 +69,7 @@ import java.util.HashSet; import static java.util.Locale.US; import java.util.Optional; import static java.util.TimeZone.getTimeZone; +import java.util.stream.Collectors; import org.openide.util.Lookup; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -1146,7 +1147,7 @@ class ExtractRegistry extends Extract { // New OsAccount Code OsAccountManager accountMgr = tskCase.getOsAccountManager(); HostManager hostMrg = tskCase.getHostManager(); - Host host = hostMrg.getHost(tskCase.getDataSource(regAbstractFile.getDataSourceObjectId())); + Host host = hostMrg.getHost((DataSource)dataSource); Set existingAccounts = accountMgr.getAccounts(host); for(OsAccount osAccount: existingAccounts) { @@ -2367,58 +2368,63 @@ class ExtractRegistry extends Extract { } } - String settingString = ""; - for (String setting : PASSWORD_SETTINGS_FLAGS) { - if (userInfo.containsKey(setting)) { - settingString += setting + ", "; - } - } - + String settingString = getSettingsFromMap(ACCOUNT_SETTINGS_FLAGS, userInfo); if (!settingString.isEmpty()) { settingString = settingString.substring(0, settingString.length() - 2); attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_PASSWORD_SETTINGS, settingString, osAccount, host, regFile)); } - settingString = ""; - for (String setting : ACCOUNT_SETTINGS_FLAGS) { - if (userInfo.containsKey(setting)) { - settingString += setting + ", "; - } - } - + settingString = getSettingsFromMap(ACCOUNT_SETTINGS_FLAGS, userInfo); if (!settingString.isEmpty()) { settingString = settingString.substring(0, settingString.length() - 2); attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_ACCOUNT_SETTINGS, settingString, osAccount, host, regFile)); } - settingString = ""; - for (String setting : ACCOUNT_TYPE_FLAGS) { - if (userInfo.containsKey(setting)) { - settingString += setting + ", "; - } - } - + settingString = getSettingsFromMap(ACCOUNT_TYPE_FLAGS, userInfo); if (!settingString.isEmpty()) { - settingString = settingString.substring(0, settingString.length() - 2); attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_FLAG, settingString, osAccount, host, regFile)); } if (groupList != null && groupList.isEmpty()) { - String groups = ""; - for (String group : groupList) { - groups += group + ", "; - } + String groups = groupList.stream() + .map(String::valueOf) + .collect(Collectors.joining(", ")); attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_GROUPS, - groups.substring(0, groups.length() - 2), osAccount, host, regFile)); + groups, osAccount, host, regFile)); } osAccount.addAttributes(attributeSet); tskCase.getOsAccountManager().updateAccount(osAccount); } + + /** + * Create comma separated list from the set values for the given keys. + * + * @param keys List of map keys. + * @param map Data map. + * + * @return Comma separated String of values. + */ + private String getSettingsFromMap(String[] keys, Map map) { + List settingsList = new ArrayList<>(); + for (String setting : keys) { + if (map.containsKey(setting)) { + settingsList.add(setting); + } + } + + if (!settingsList.isEmpty()) { + return settingsList.stream() + .map(String::valueOf) + .collect(Collectors.joining(", ")); + } + + return ""; + } /** * Helper for constructing a new OsAccountAttribute From 84f30369510fa523cf3225ccc695827846c6568e Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 23 Feb 2021 11:58:57 -0500 Subject: [PATCH 34/42] 7332 Refactor ingest task pipelines for extensibility --- .../autopsy/ingest/DataSourceIngestModuleAdapter.java | 8 ++++---- .../sleuthkit/autopsy/ingest/FileIngestModuleAdapter.java | 7 +++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestModuleAdapter.java b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestModuleAdapter.java index a866c278b6..83b5a1457f 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestModuleAdapter.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestModuleAdapter.java @@ -24,11 +24,11 @@ import org.sleuthkit.datamodel.Content; * An adapter that provides a no-op implementation of the startUp() method for * data source ingest modules. * - * @deprecated As of Java 8, interfaces can have default methods. - * DataSourceIngestModule now provides default no-op versions of startUp() - * and shutDown(). + * NOTE: As of Java 8, interfaces can have default methods. + * DataSourceIngestModule now provides default no-op versions of startUp() and + * shutDown(). This class is no longer needed and can be deprecated when + * convenient. */ -@Deprecated public abstract class DataSourceIngestModuleAdapter implements DataSourceIngestModule { @Override diff --git a/Core/src/org/sleuthkit/autopsy/ingest/FileIngestModuleAdapter.java b/Core/src/org/sleuthkit/autopsy/ingest/FileIngestModuleAdapter.java index 6fbdf529fd..9f733308c8 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/FileIngestModuleAdapter.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/FileIngestModuleAdapter.java @@ -24,11 +24,10 @@ import org.sleuthkit.datamodel.AbstractFile; * An adapter that provides no-op implementations of the startUp() and * shutDown() methods for file ingest modules. * - * @deprecated As of Java 8, interfaces can have default methods. - * FileIngestModule now provides default no-op versions of startUp() and - * shutDown(). + * NOTE: As of Java 8, interfaces can have default methods. FileIngestModule now + * provides default no-op versions of startUp() and shutDown(). This class is no + * longer needed and can be deprecated when convenient. */ -@Deprecated public abstract class FileIngestModuleAdapter implements FileIngestModule { @Override From 62de904bb801793c3a02cad22fc573e9e3484887 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 23 Feb 2021 12:03:22 -0500 Subject: [PATCH 35/42] 7332 Refactor ingest task pipelines for extensibility --- .../ingest/DataArtifactIngestModule.java | 40 ------------------- 1 file changed, 40 deletions(-) delete mode 100755 Core/src/org/sleuthkit/autopsy/ingest/DataArtifactIngestModule.java diff --git a/Core/src/org/sleuthkit/autopsy/ingest/DataArtifactIngestModule.java b/Core/src/org/sleuthkit/autopsy/ingest/DataArtifactIngestModule.java deleted file mode 100755 index b5677242cb..0000000000 --- a/Core/src/org/sleuthkit/autopsy/ingest/DataArtifactIngestModule.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2021 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.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException; -import org.sleuthkit.datamodel.DataArtifact; - -/** - * Intercace that must be implemented by all ingest modules that process - * artifacts. - */ -public interface DataArtifactIngestModule { - - /** - * Processes a data artifact. - * - * @param artifact The artifact to process. - * - * @throws IngestModuleException Exception is thrown if there is an error - * while processing the data artifact. - */ - void process(DataArtifact artifact) throws IngestModuleException; - -} From b03844db67c9fac67f49705ade4e78a242eafb3e Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 23 Feb 2021 13:05:58 -0500 Subject: [PATCH 36/42] 7332 Refactor ingest task pipelines for extensibility --- .../ingest/DataSourceIngestPipeline.java | 9 +++-- .../autopsy/ingest/FileIngestPipeline.java | 2 +- .../autopsy/ingest/IngestManager.java | 2 +- .../autopsy/ingest/IngestModule.java | 2 +- .../autopsy/ingest/IngestTaskPipeline.java | 40 ++++++++----------- 5 files changed, 25 insertions(+), 30 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestPipeline.java b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestPipeline.java index 0ad1a3e60a..6c551da602 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestPipeline.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestPipeline.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2012-2021 Basis Technology Corp. + * Copyright 2014-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -90,11 +90,14 @@ final class DataSourceIngestPipeline extends IngestTaskPipeline { ingestJobPipeline.setCurrentFileIngestModule(getDisplayName(), file.getName()); ProcessResult result = module.process(file); if (result == ProcessResult.ERROR) { - throw new IngestModuleException(String.format("%s experienced an error analyzing file (file objId = %d)", getDisplayName(), task.getFileId())); //NON-NLS + throw new IngestModuleException(String.format("%s experienced an error analyzing %s (file objId = %d)", getDisplayName(), file.getName(), file.getId())); //NON-NLS } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java index d8a8480776..791a45021c 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -804,7 +804,7 @@ public class IngestManager implements IngestProgressSnapshotProvider { * * @param task The file level ingest job task that was completed. */ - void setIngestTaskProgressCompleted(IngestTask task) { + void setIngestTaskProgressCompleted(FileIngestTask task) { IngestThreadActivitySnapshot prevSnap = ingestThreadActivitySnapshots.get(task.getThreadId()); IngestThreadActivitySnapshot newSnap = new IngestThreadActivitySnapshot(task.getThreadId()); ingestThreadActivitySnapshots.put(task.getThreadId(), newSnap); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestModule.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestModule.java index 10114ac288..8bfeef57fb 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestModule.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2012-2021 Basis Technology Corp. + * Copyright 2014-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestTaskPipeline.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestTaskPipeline.java index aaa430b05e..5e918d4ddb 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestTaskPipeline.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestTaskPipeline.java @@ -28,9 +28,9 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; /** * An abstract superclass for pipelines of ingest modules for a given ingest * task type. Some examples of ingest task types: data source level ingest - * tasks, file ingest tasks, data artifacts ingest tasks, etc. Subclasses need - * to implement a specialization of the inner PipelineModule decorator abstartc - * superclass for they type of ingest modules that make up the pipeline. + * tasks, file ingest tasks, data artifact ingest tasks, etc. Subclasses need to + * implement a specialization of the inner PipelineModule abstract superclass + * for the type of ingest modules that make up the pipeline. * * @param The ingest task type. */ @@ -47,10 +47,10 @@ abstract class IngestTaskPipeline { /** * Constructs an instance of an abstract superclass for pipelines of ingest * modules for a given ingest task type. Some examples of ingest task types: - * data source level ingest tasks, file ingest tasks, data artifacts ingest + * data source level ingest tasks, file ingest tasks, data artifact ingest * tasks, etc. Subclasses need to implement a specialization of the inner - * PipelineModule decorator abstartc superclass for they type of ingest - * modules that make up the pipeline. + * PipelineModule abstract superclass for the type of ingest modules that + * make up the pipeline. * * @param ingestJobPipeline The ingest job pipeline that owns this pipeline. * @param moduleTemplates The ingest module templates that define this @@ -115,7 +115,7 @@ abstract class IngestTaskPipeline { * ignored, as appropriate to the pipeline type. * * @return An Optional that is either empty or contains a newly created and - * decorated ingest module. + * wrapped ingest module. */ abstract Optional> acceptModuleTemplate(IngestModuleTemplate ingestModuleTemplate); @@ -152,7 +152,7 @@ abstract class IngestTaskPipeline { } /** - * Does any preparation required before performing the a task. + * Does any preparation required before performing a task. * * @param task The task. * @@ -195,7 +195,6 @@ abstract class IngestTaskPipeline { } catch (IngestTaskPipelineException ex) { errors.add(new IngestModuleError("Ingest Task Pipeline", ex)); //NON-NLS } - ingestManager.setIngestTaskProgressCompleted(task); currentModule = null; return errors; } @@ -210,9 +209,9 @@ abstract class IngestTaskPipeline { } /** - * Does any clean up required after performing the current task. + * Does any clean up required after performing a task. * - * @param task The current task. + * @param task The task. * * @throws IngestTaskPipelineException Thrown if there is an error cleaning * up after performing the task. @@ -224,7 +223,7 @@ abstract class IngestTaskPipeline { * * @return A list of shut down errors, possibly empty. */ - synchronized List shutDown() { + List shutDown() { List errors = new ArrayList<>(); if (running == true) { for (PipelineModule module : modules) { @@ -236,7 +235,8 @@ abstract class IngestTaskPipeline { if (msg == null) { /* * Jython run-time errors don't seem to have a message, - * but have details in toString(). + * but have details in the string returned by + * toString(). */ msg = ex.toString(); } @@ -256,18 +256,13 @@ abstract class IngestTaskPipeline { private final IngestModule module; private final String displayName; - - /* - * This field is intended to be written to in an ingest thread and read - * from in an ingest snaphot thread. - */ private volatile Date processingStartTime; /** * Constructs an instance of an abstract superclass for a wrapper that * adds ingest infrastructure operations to an ingest module. * - * @param module The ingest module to be decorated. + * @param module The ingest module to be wrapped. * @param displayName The display name for the module. */ PipelineModule(IngestModule module, String displayName) { @@ -303,15 +298,12 @@ abstract class IngestTaskPipeline { } /** - * Gets the the processing start time for the wrapped module, as set by + * Gets the the processing start time for the wrapped module. * * @return The start time, will be null if the module has not started * processing the data source yet. */ Date getProcessingStartTime() { - if (processingStartTime == null) { - throw new IllegalStateException("setProcessingStartTime() was not called"); //NON-NLS - } return new Date(processingStartTime.getTime()); } @@ -321,7 +313,7 @@ abstract class IngestTaskPipeline { } /** - * Processes an ingest task. + * Performs an ingest task. * * @param ingestJobPipeline The ingest job pipeline that owns the ingest * module pipeline this module belongs to. From 8e049cf20709ebb7c746166061743cb07c0d557a Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 23 Feb 2021 13:25:14 -0500 Subject: [PATCH 37/42] Inital save --- .../autopsy/datamodel/OsAccounts.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/OsAccounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/OsAccounts.java index faf3cfd0ae..80a0a13cfe 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/OsAccounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/OsAccounts.java @@ -18,9 +18,12 @@ */ package org.sleuthkit.autopsy.datamodel; +import java.beans.PropertyChangeEvent; import java.text.SimpleDateFormat; +import java.util.EnumSet; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.logging.Level; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; @@ -28,6 +31,8 @@ import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.Lookups; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.Host; import org.sleuthkit.datamodel.OsAccount; @@ -101,6 +106,25 @@ public final class OsAccounts implements AutopsyVisitableItem { */ private final class OsAccountNodeFactory extends ChildFactory { + private final Set CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.OS_ACCOUNT_ADDED, Case.Events.OS_ACCOUNT_CHANGED); + + OsAccountNodeFactory() { + Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, (PropertyChangeEvent evt) -> { + String eventType = evt.getPropertyName(); + if (eventType.equals(Case.Events.OS_ACCOUNT_ADDED.toString()) || eventType.equals(Case.Events.OS_ACCOUNT_CHANGED.toString())) { + + try { + Case.getCurrentCaseThrows(); + OsAccounts.OsAccountNodeFactory.this.refresh(true); + } catch (NoCurrentCaseException notUsed) { + /** + * Case is closed, do nothing. + */ + } + } + }); + } + @Override protected boolean createKeys(List list) { try { From bf8eb0fa4a3ee3a4914f5829ecd1aec275df9089 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 23 Feb 2021 13:32:08 -0500 Subject: [PATCH 38/42] Updated to compile with changes in OsAccountManager from SEt to List --- .../recentactivity/ExtractRegistry.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java index b04b386442..1b1661c82e 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java @@ -1149,7 +1149,7 @@ class ExtractRegistry extends Extract { HostManager hostMrg = tskCase.getHostManager(); Host host = hostMrg.getHost((DataSource)dataSource); - Set existingAccounts = accountMgr.getAccounts(host); + List existingAccounts = accountMgr.getAccounts(host); for(OsAccount osAccount: existingAccounts) { Optional optional = osAccount.getUniqueIdWithinRealm(); if(!optional.isPresent()) { @@ -2222,9 +2222,9 @@ class ExtractRegistry extends Extract { } if (homeDir != null && !homeDir.isEmpty()) { - Set attSet = new HashSet<>(); - attSet.add(createOsAccountAttribute(TSK_HOME_DIR, homeDir, osAccount, host, file)); - osAccount.addAttributes(attSet); + List attributes = new ArrayList<>(); + attributes.add(createOsAccountAttribute(TSK_HOME_DIR, homeDir, osAccount, host, file)); + osAccount.addAttributes(attributes); } accountMgr.updateAccount(osAccount); @@ -2284,7 +2284,7 @@ class ExtractRegistry extends Extract { SimpleDateFormat regRipperTimeFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy 'Z'", US); regRipperTimeFormat.setTimeZone(getTimeZone("GMT")); - Set attributeSet = new HashSet<>(); + List attributes = new ArrayList<>(); String value = userInfo.get(ACCOUNT_CREATED_KEY); if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) { @@ -2298,7 +2298,7 @@ class ExtractRegistry extends Extract { if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) { Long time = parseRegRipTime(value); if (time != null) { - attributeSet.add(createOsAccountAttribute(TSK_DATETIME_ACCESSED, + attributes.add(createOsAccountAttribute(TSK_DATETIME_ACCESSED, parseRegRipTime(value), osAccount, host, regFile)); } @@ -2306,7 +2306,7 @@ class ExtractRegistry extends Extract { value = userInfo.get(LOGIN_COUNT_KEY); if (value != null && !value.isEmpty()) { - attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_COUNT, + attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_COUNT, Integer.parseInt(value), osAccount, host, regFile)); } @@ -2321,7 +2321,7 @@ class ExtractRegistry extends Extract { value = userInfo.get(USER_COMMENT_KEY); if (value != null && !value.isEmpty()) { - attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_DESCRIPTION, + attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_DESCRIPTION, value, osAccount, host, regFile)); } @@ -2329,7 +2329,7 @@ class ExtractRegistry extends Extract { if (value != null && !value.isEmpty()) { addEmailAccount(regFile, value); - attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_EMAIL, + attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_EMAIL, value, osAccount, host, regFile)); } @@ -2348,14 +2348,14 @@ class ExtractRegistry extends Extract { if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) { Long time = parseRegRipTime(value); if (time != null) { - attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_PASSWORD_RESET, + attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_PASSWORD_RESET, time, osAccount, host, regFile)); } } value = userInfo.get(PASSWORD_HINT); if (value != null && !value.isEmpty()) { - attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_PASSWORD_HINT, + attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_PASSWORD_HINT, value, osAccount, host, regFile)); } @@ -2363,7 +2363,7 @@ class ExtractRegistry extends Extract { if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) { Long time = parseRegRipTime(value); if (time != null) { - attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_PASSWORD_FAIL, + attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_PASSWORD_FAIL, time, osAccount, host, regFile)); } } @@ -2371,20 +2371,20 @@ class ExtractRegistry extends Extract { String settingString = getSettingsFromMap(ACCOUNT_SETTINGS_FLAGS, userInfo); if (!settingString.isEmpty()) { settingString = settingString.substring(0, settingString.length() - 2); - attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_PASSWORD_SETTINGS, + attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_PASSWORD_SETTINGS, settingString, osAccount, host, regFile)); } settingString = getSettingsFromMap(ACCOUNT_SETTINGS_FLAGS, userInfo); if (!settingString.isEmpty()) { settingString = settingString.substring(0, settingString.length() - 2); - attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_ACCOUNT_SETTINGS, + attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_ACCOUNT_SETTINGS, settingString, osAccount, host, regFile)); } settingString = getSettingsFromMap(ACCOUNT_TYPE_FLAGS, userInfo); if (!settingString.isEmpty()) { - attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_FLAG, + attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_FLAG, settingString, osAccount, host, regFile)); } @@ -2393,11 +2393,11 @@ class ExtractRegistry extends Extract { .map(String::valueOf) .collect(Collectors.joining(", ")); - attributeSet.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_GROUPS, + attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_GROUPS, groups, osAccount, host, regFile)); } - osAccount.addAttributes(attributeSet); + osAccount.addAttributes(attributes); tskCase.getOsAccountManager().updateAccount(osAccount); } From 8dc5a16a44ce29ebf182459d74f2cdfc757c5191 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 23 Feb 2021 13:34:08 -0500 Subject: [PATCH 39/42] Fixed typo in publish method name --- Core/src/org/sleuthkit/autopsy/casemodule/Case.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index b74035e102..716ef9c8b7 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -469,7 +469,7 @@ public class Case { } @Subscribe - public void publishOsAccountAddedEvent(OsAccountManager.OsAccountsChangedEvent event) { + public void publishOsAccountChangedEvent(OsAccountManager.OsAccountsChangedEvent event) { for(OsAccount account: event.getOsAcounts()) { eventPublisher.publish(new OsAccountChangedEvent(account)); } From 55a33b0c32c58da35208b913ecf0568c0d796776 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 23 Feb 2021 15:47:22 -0500 Subject: [PATCH 40/42] OsAccount nodes will update in the tree --- .../autopsy/datamodel/OsAccounts.java | 60 ++++++++++++------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/OsAccounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/OsAccounts.java index 80a0a13cfe..ade1ef6329 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/OsAccounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/OsAccounts.java @@ -19,7 +19,9 @@ package org.sleuthkit.autopsy.datamodel; import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.text.SimpleDateFormat; +import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Optional; @@ -32,7 +34,7 @@ import org.openide.nodes.Sheet; import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.casemodule.events.OsAccountChangedEvent; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.Host; import org.sleuthkit.datamodel.OsAccount; @@ -104,25 +106,23 @@ public final class OsAccounts implements AutopsyVisitableItem { * The child node factory that creates the OsAccountNode children for a * OsAccountListNode. */ - private final class OsAccountNodeFactory extends ChildFactory { + private final class OsAccountNodeFactory extends ChildFactory.Detachable { - private final Set CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.OS_ACCOUNT_ADDED, Case.Events.OS_ACCOUNT_CHANGED); + private final PropertyChangeListener listener = new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + refresh(true); + } + }; - OsAccountNodeFactory() { - Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, (PropertyChangeEvent evt) -> { - String eventType = evt.getPropertyName(); - if (eventType.equals(Case.Events.OS_ACCOUNT_ADDED.toString()) || eventType.equals(Case.Events.OS_ACCOUNT_CHANGED.toString())) { - - try { - Case.getCurrentCaseThrows(); - OsAccounts.OsAccountNodeFactory.this.refresh(true); - } catch (NoCurrentCaseException notUsed) { - /** - * Case is closed, do nothing. - */ - } - } - }); + @Override + protected void addNotify() { + Case.addEventTypeSubscriber(Collections.singleton(Case.Events.OS_ACCOUNT_ADDED), listener); + } + + @Override + protected void removeNotify() { + Case.removeEventTypeSubscriber(Collections.singleton(Case.Events.OS_ACCOUNT_ADDED), listener); } @Override @@ -153,7 +153,18 @@ public final class OsAccounts implements AutopsyVisitableItem { */ public static final class OsAccountNode extends DisplayableItemNode { - private final OsAccount account; + private OsAccount account; + + private final PropertyChangeListener listener = new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if(((OsAccountChangedEvent)evt).getOsAccount().getId() == account.getId()) { + // Update the account node to the new one + account = ((OsAccountChangedEvent)evt).getOsAccount(); + updateSheet(); + } + } + }; /** * Constructs a new OsAccountNode. @@ -167,6 +178,8 @@ public final class OsAccounts implements AutopsyVisitableItem { setName(account.getName()); setDisplayName(account.getName()); setIconBaseWithExtension(ICON_PATH); + + Case.addEventTypeSubscriber(Collections.singleton(Case.Events.OS_ACCOUNT_CHANGED), listener); } @Override @@ -183,7 +196,7 @@ public final class OsAccounts implements AutopsyVisitableItem { public String getItemType() { return getClass().getName(); } - + @Messages({ "OsAccounts_accountNameProperty_name=Name", "OsAccounts_accountNameProperty_displayName=Name", @@ -198,6 +211,13 @@ public final class OsAccounts implements AutopsyVisitableItem { "OsAccounts_loginNameProperty_displayName=Login Name", "OsAccounts_loginNameProperty_desc=Os Account login name" }) + + /** + * Refreshes this node's property sheet. + */ + void updateSheet() { + this.setSheet(createSheet()); + } @Override protected Sheet createSheet() { From 497f26e4ac4ff121210bef69280894be68e20f36 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 24 Feb 2021 14:51:22 -0500 Subject: [PATCH 41/42] Changed the dataModel OSAccount event names to avoid collision --- Core/src/org/sleuthkit/autopsy/casemodule/Case.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 716ef9c8b7..cdde586f97 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -133,8 +133,8 @@ import org.sleuthkit.datamodel.FileSystem; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.OsAccount; import org.sleuthkit.datamodel.OsAccountManager; -import org.sleuthkit.datamodel.OsAccountManager.OsAccountsAddedEvent; -import org.sleuthkit.datamodel.OsAccountManager.OsAccountsChangedEvent; +import org.sleuthkit.datamodel.OsAccountManager.OsAccountsCreationEvent; +import org.sleuthkit.datamodel.OsAccountManager.OsAccountsUpdateEvent; import org.sleuthkit.datamodel.Report; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TimelineManager; @@ -462,14 +462,14 @@ public class Case { } @Subscribe - public void publishOsAccountAddedEvent(OsAccountManager.OsAccountsAddedEvent event) { + public void publishOsAccountAddedEvent(OsAccountsCreationEvent event) { for(OsAccount account: event.getOsAcounts()) { eventPublisher.publish(new OsAccountAddedEvent(account)); } } @Subscribe - public void publishOsAccountChangedEvent(OsAccountManager.OsAccountsChangedEvent event) { + public void publishOsAccountChangedEvent(OsAccountsCreationEvent event) { for(OsAccount account: event.getOsAcounts()) { eventPublisher.publish(new OsAccountChangedEvent(account)); } From 3baefd8e61d5e92060b5bf8c45d799d8a29a5159 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 24 Feb 2021 15:12:00 -0500 Subject: [PATCH 42/42] Fixed typo --- Core/src/org/sleuthkit/autopsy/casemodule/Case.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index cdde586f97..0115b3a53c 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -469,7 +469,7 @@ public class Case { } @Subscribe - public void publishOsAccountChangedEvent(OsAccountsCreationEvent event) { + public void publishOsAccountChangedEvent(OsAccountsUpdateEvent event) { for(OsAccount account: event.getOsAcounts()) { eventPublisher.publish(new OsAccountChangedEvent(account)); }