From 99deb906ef4b6a0ab0e4b0bd9cf4db1f08783da9 Mon Sep 17 00:00:00 2001 From: dhurd Date: Fri, 27 Jul 2012 09:19:34 -0400 Subject: [PATCH 1/8] Added search by MD5 hash; not complete. --- .../AdvancedConfigurationCleanDialog.form | 23 ++ .../AdvancedConfigurationCleanDialog.java | 81 +++++ HashDatabase/nbproject/project.xml | 8 + .../hashdatabase/HashDbSearchAction.java | 61 ++++ .../hashdatabase/HashDbSearchManager.java | 83 +++++ .../hashdatabase/HashDbSearchNode.java | 75 +++++ .../hashdatabase/HashDbSearchPanel.form | 183 +++++++++++ .../hashdatabase/HashDbSearchPanel.java | 309 ++++++++++++++++++ .../HashDbSearchResultFactory.java | 38 +++ .../autopsy/hashdatabase/HashDbSearcher.java | 88 +++++ .../sleuthkit/autopsy/hashdatabase/layer.xml | 8 +- 11 files changed, 956 insertions(+), 1 deletion(-) create mode 100644 CoreComponents/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.form create mode 100644 CoreComponents/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.java create mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchAction.java create mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchManager.java create mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchNode.java create mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.form create mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java create mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchResultFactory.java create mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearcher.java diff --git a/CoreComponents/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.form b/CoreComponents/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.form new file mode 100644 index 0000000000..9c0697f828 --- /dev/null +++ b/CoreComponents/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.form @@ -0,0 +1,23 @@ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/CoreComponents/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.java b/CoreComponents/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.java new file mode 100644 index 0000000000..0ae2014ca4 --- /dev/null +++ b/CoreComponents/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.java @@ -0,0 +1,81 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.corecomponents; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Toolkit; +import javax.swing.JFrame; +import javax.swing.JPanel; + +/** + * Displays a panel in a new clean dialog. A clean dialog contains nothing + * but the panel given to it. No additional buttons or features, except + * the default close operation, which is set to dispose. + */ +public class AdvancedConfigurationCleanDialog extends javax.swing.JDialog { + + /** Creates new form AdvancedConfigurationDialog */ + public AdvancedConfigurationCleanDialog() { + this(false); + } + + /** Creates new form AdvancedConfigurationDialog */ + public AdvancedConfigurationCleanDialog(boolean resizable) { + super(new JFrame(), true); + setResizable(resizable); + if(resizable) { + this.setIconImage(null); + } + initComponents(); + } + + /** + * Display the given panel on a clean dialog. + * @param panel the panel to display + */ + public void display(JPanel panel) { + this.setTitle(panel.getName()); + + panel.setAlignmentX(Component.CENTER_ALIGNMENT); + this.add(panel, 0); + this.pack(); + + Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); + // set the popUp window / JFrame + int w = this.getSize().width; + int h = this.getSize().height; + + // set the location of the popUp Window on the center of the screen + setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); + + this.setVisible(true); + } + + /** + * Close the dialog. + */ + public void close() { + this.dispose(); + } + + /** + * 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() { + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + getContentPane().setLayout(new javax.swing.BoxLayout(getContentPane(), javax.swing.BoxLayout.LINE_AXIS)); + + pack(); + }// //GEN-END:initComponents + + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables +} diff --git a/HashDatabase/nbproject/project.xml b/HashDatabase/nbproject/project.xml index cf99199c2e..aa0cc5a2c7 100644 --- a/HashDatabase/nbproject/project.xml +++ b/HashDatabase/nbproject/project.xml @@ -31,6 +31,14 @@ 7.20.1 + + org.openide.nodes + + + + 7.28.1 + + org.openide.util diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchAction.java new file mode 100644 index 0000000000..28af740519 --- /dev/null +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchAction.java @@ -0,0 +1,61 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 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.hashdatabase; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import org.openide.util.HelpCtx; +import org.openide.util.actions.CallableSystemAction; +import org.sleuthkit.autopsy.corecomponents.AdvancedConfigurationCleanDialog; + +/** + * The HashDbSearchAction opens the HashDbSearchPanel in a dialog. + */ +class HashDbSearchAction extends CallableSystemAction { + + static final String ACTION_NAME = "Hash File Search"; + + @Override + public void performAction() { + final HashDbSearchPanel panel = HashDbSearchPanel.getDefault(); + final AdvancedConfigurationCleanDialog dialog = new AdvancedConfigurationCleanDialog(); + panel.cancelButtonListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + dialog.close(); + } + }); + dialog.display(panel); + } + + @Override + public String getName() { + return ACTION_NAME; + } + + @Override + public HelpCtx getHelpCtx() { + return HelpCtx.DEFAULT_HELP; + } + + @Override + protected boolean asynchronous() { + return false; + } +} diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchManager.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchManager.java new file mode 100644 index 0000000000..e426afa000 --- /dev/null +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchManager.java @@ -0,0 +1,83 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 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.hashdatabase; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.Children; +import org.openide.nodes.Node; +import org.openide.windows.TopComponent; +import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; +import org.sleuthkit.datamodel.FsContent; + +/** + * + */ +public class HashDbSearchManager { + Map> map; + List pairs; + + HashDbSearchManager(Map> map) { + this.map = map; + init(); + } + + + public void execute() { + Node rootNode = null; + + if (map.size() > 0) { + Children childThingNodes = + Children.create(new HashDbSearchResultFactory(pairs), true); + + rootNode = new AbstractNode(childThingNodes); + } else { + rootNode = Node.EMPTY; + } + + final String pathText = "Keyword search"; + TopComponent searchResultWin = DataResultTopComponent.createInstance("Keyword search", pathText, rootNode, map.size()); + searchResultWin.requestActive(); + } + + private void init() { + pairs = new ArrayList(); + for(String hash : map.keySet()) { + ArrayList files = new ArrayList(); + for(FsContent file : map.get(hash)) { + files.add(file); + } + pairs.add(new HashSearchPairs(hash, files)); + } + } + +} + +class HashSearchPairs { + String hash; + List files; + + HashSearchPairs(String hash, List files) { + this.hash = hash; + this.files = files; + } +} diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchNode.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchNode.java new file mode 100644 index 0000000000..d2249cc5f5 --- /dev/null +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchNode.java @@ -0,0 +1,75 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 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.hashdatabase; + +import org.openide.nodes.AbstractNode; +import org.openide.nodes.Children; +import org.openide.nodes.Sheet; +import org.openide.util.lookup.Lookups; +import org.sleuthkit.datamodel.SleuthkitCase; + +/** + * Node for the file search filter + */ +public class HashDbSearchNode extends AbstractNode implements DisplayableItemNode { + + SearchFilters.SearchFilterInterface filter; + SleuthkitCase skCase; + + HashDbSearchNode(SearchFilters.SearchFilterInterface filter, SleuthkitCase skCase) { + super(Children.create(new FileSearchFilterChildren(filter, skCase), true), Lookups.singleton(filter.getDisplayName())); + super.setName(filter.getName()); + super.setDisplayName(filter.getDisplayName()); + this.filter = filter; + this.skCase = skCase; + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); + } + + @Override + public T accept(DisplayableItemNodeVisitor v) { + return v.visit(this); + } + + @Override + protected Sheet createSheet() { + Sheet s = super.createSheet(); + Sheet.Set ss = s.get(Sheet.PROPERTIES); + if (ss == null) { + ss = Sheet.createPropertiesSet(); + s.put(ss); + } + + ss.put(new NodeProperty("Filter Type", + "Filter Type", + "no description", + filter.getDisplayName())); + String extensions = ""; + for(String ext : filter.getFilter()){ + extensions += "'" + ext + "', "; + } + extensions = extensions.substring(0, extensions.lastIndexOf(',')); + ss.put(new NodeProperty("File Extensions", + "File Extensions", + "no description", + extensions)); + + return s; + } + +} diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.form new file mode 100644 index 0000000000..72ebaa2cdc --- /dev/null +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.form @@ -0,0 +1,183 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + <ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbSearchPanel.hashTable.columnModel.title0" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + + + + + + + + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java new file mode 100644 index 0000000000..f4c7db1912 --- /dev/null +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java @@ -0,0 +1,309 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 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.hashdatabase; + +import java.awt.Color; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.table.DefaultTableModel; +import org.sleuthkit.datamodel.FsContent; + +/** + * Searches for files by md5 hash, based off the hash given in this panel. + */ +public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListener { + private static final Logger logger = Logger.getLogger(HashDbSearchPanel.class.getName()); + private static HashDbSearchPanel instance; + private static boolean ingestRunning = false; + + /** + * @return the default instance of this panel + */ + public static HashDbSearchPanel getDefault() { + if (instance == null) { + instance = new HashDbSearchPanel(); + } + return instance; + } + + /** + * Creates new form HashDbSearchPanel + */ + public HashDbSearchPanel() { + setName(HashDbSearchAction.ACTION_NAME); + initComponents(); + customInit(); + } + + final void customInit() { + searchButton.addActionListener(this); + addButton.addActionListener(this); + removeButton.addActionListener(this); + errorField.setVisible(false); + hashField.requestFocus(); + // Pressing enter adds the hash + hashField.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if(e.getKeyChar() == KeyEvent.VK_ENTER) { + addButton.doClick(); + } + } + }); + // Pressing delete removes the selected rows + hashTable.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if(e.getKeyChar() == KeyEvent.VK_DELETE) { + removeButton.doClick(); + } + } + }); + } + + /** + * Don't allow any changes if ingest is running + */ + void setIngestRunning(boolean running) { + ingestRunning = running; + if(running) { + titleLabel.setForeground(Color.red); + titleLabel.setText("Ingest is ongoing; this service will be unavailable until it finishes."); + } else { + titleLabel.setForeground(Color.black); + titleLabel.setText("Search for files with the following MD5 hash(es):"); + } + hashField.setEditable(!ingestRunning); + searchButton.setEnabled(!ingestRunning); + addButton.setEnabled(!ingestRunning); + removeButton.setEnabled(!ingestRunning); + hashTable.setEnabled(!ingestRunning); + hashLabel.setEnabled(!ingestRunning); + } + + void cancelButtonListener(ActionListener l) { + cancelButton.addActionListener(l); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jScrollPane1 = new javax.swing.JScrollPane(); + hashTable = new javax.swing.JTable(); + hashField = new javax.swing.JTextField(); + addButton = new javax.swing.JButton(); + hashLabel = new javax.swing.JLabel(); + cancelButton = new javax.swing.JButton(); + searchButton = new javax.swing.JButton(); + removeButton = new javax.swing.JButton(); + jSeparator1 = new javax.swing.JSeparator(); + titleLabel = new javax.swing.JLabel(); + errorField = new javax.swing.JLabel(); + + hashTable.setModel(new javax.swing.table.DefaultTableModel( + new Object [][] { + + }, + new String [] { + "MD5 Hashes" + } + ) { + Class[] types = new Class [] { + java.lang.String.class + }; + boolean[] canEdit = new boolean [] { + false + }; + + public Class getColumnClass(int columnIndex) { + return types [columnIndex]; + } + + public boolean isCellEditable(int rowIndex, int columnIndex) { + return canEdit [columnIndex]; + } + }); + jScrollPane1.setViewportView(hashTable); + hashTable.getColumnModel().getColumn(0).setHeaderValue(org.openide.util.NbBundle.getMessage(HashDbSearchPanel.class, "HashDbSearchPanel.hashTable.columnModel.title0")); // NOI18N + + hashField.setText(org.openide.util.NbBundle.getMessage(HashDbSearchPanel.class, "HashDbSearchPanel.hashField.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(addButton, org.openide.util.NbBundle.getMessage(HashDbSearchPanel.class, "HashDbSearchPanel.addButton.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(hashLabel, org.openide.util.NbBundle.getMessage(HashDbSearchPanel.class, "HashDbSearchPanel.hashLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(HashDbSearchPanel.class, "HashDbSearchPanel.cancelButton.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(searchButton, org.openide.util.NbBundle.getMessage(HashDbSearchPanel.class, "HashDbSearchPanel.searchButton.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(removeButton, org.openide.util.NbBundle.getMessage(HashDbSearchPanel.class, "HashDbSearchPanel.removeButton.text")); // NOI18N + + titleLabel.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(titleLabel, org.openide.util.NbBundle.getMessage(HashDbSearchPanel.class, "HashDbSearchPanel.titleLabel.text")); // NOI18N + + errorField.setForeground(new java.awt.Color(255, 0, 0)); + org.openide.awt.Mnemonics.setLocalizedText(errorField, org.openide.util.NbBundle.getMessage(HashDbSearchPanel.class, "HashDbSearchPanel.errorField.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(errorField) + .addGap(18, 18, 18) + .addComponent(searchButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(cancelButton)) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane1) + .addComponent(jSeparator1) + .addGroup(layout.createSequentialGroup() + .addComponent(titleLabel) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(layout.createSequentialGroup() + .addComponent(hashLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(addButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(removeButton) + .addGap(0, 0, Short.MAX_VALUE)) + .addComponent(hashField)))))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(titleLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 355, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(26, 26, 26) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(hashLabel) + .addComponent(hashField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(addButton) + .addComponent(removeButton)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 27, Short.MAX_VALUE) + .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cancelButton) + .addComponent(searchButton) + .addComponent(errorField)) + .addContainerGap()) + ); + }// //GEN-END:initComponents + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton addButton; + private javax.swing.JButton cancelButton; + private javax.swing.JLabel errorField; + private javax.swing.JTextField hashField; + private javax.swing.JLabel hashLabel; + private javax.swing.JTable hashTable; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JSeparator jSeparator1; + private javax.swing.JButton removeButton; + private javax.swing.JButton searchButton; + private javax.swing.JLabel titleLabel; + // End of variables declaration//GEN-END:variables + + @Override + public void actionPerformed(ActionEvent e) { + if(e.getSource().equals(searchButton)) { + doSearch(); + } else if(e.getSource().equals(addButton)) { + add(); + } else if(e.getSource().equals(removeButton)) { + remove(); + } + } + + /** + * Search through all tsk_files to find ones with the same hashes as the + * hashes given. + */ + void doSearch() { + // Make sure all files have an md5 hash + if(HashDbSearcher.isReady()) { + errorField.setEnabled(false); + cancelButton.setText("Done"); // no changes so done + // Get all the rows in the table + int numRows = hashTable.getRowCount(); + ArrayList hashes = new ArrayList(); + for(int i=0; i> map = HashDbSearcher.findFilesBymd5(hashes); + HashDbSearchManager man = new HashDbSearchManager(map); + man.execute(); + } else { + errorField.setVisible(true); + } + } + + /** + * Add the given text into the table of hashes. + */ + void add() { + cancelButton.setText("Cancel"); // changes means cancel + DefaultTableModel model = (DefaultTableModel) hashTable.getModel(); + if(!hashField.getText().equals("")) { + model.addRow(new String[] {hashField.getText()}); + hashField.setText(""); // wipe the field + } + hashField.requestFocus(); // select the field to type in + } + + /** + * Remove all of the highlighted/selected rows from the table of hashes. + */ + void remove() { + cancelButton.setText("Cancel"); // changes means cancel + DefaultTableModel model = (DefaultTableModel) hashTable.getModel(); + int rows[] = hashTable.getSelectedRows(); + // Loop backwards to delete highest row index first, otherwise + // index numbers change and the wrong rows are deleted + for(int i=rows.length-1; i>=0; i--) { + model.removeRow(rows[i]); + } + } +} diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchResultFactory.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchResultFactory.java new file mode 100644 index 0000000000..185657bf87 --- /dev/null +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchResultFactory.java @@ -0,0 +1,38 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.hashdatabase; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import org.openide.nodes.ChildFactory; +import org.openide.nodes.Children; +import org.openide.nodes.Node; +import org.sleuthkit.datamodel.FsContent; + +/** + * + * @author dhurd + */ +public class HashDbSearchResultFactory extends ChildFactory{ + List pairs; + + HashDbSearchResultFactory(List pairs) { + this.pairs = pairs; + } + + + + @Override + protected boolean createKeys(List toPopulate) { + toPopulate.addAll(pairs); + return true; + } + + @Override + protected Node createNodeForKey(List pairs) { + return new HashDbSearchNode(pairs, Children.create(this, true)); + } +} diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearcher.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearcher.java new file mode 100644 index 0000000000..057056f11d --- /dev/null +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearcher.java @@ -0,0 +1,88 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 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.hashdatabase; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.FsContent; +import org.sleuthkit.datamodel.SleuthkitCase; + +/** + * Searches by MD5 hash to find all files with the same hash, and + * subsequently the same content. + */ +public class HashDbSearcher { + private static final Case currentCase = Case.getCurrentCase(); + private static final SleuthkitCase skCase = currentCase.getSleuthkitCase(); + private static final Logger logger = Logger.getLogger(HashDbSearcher.class.getName()); + + /** + * Given a string hash value, find all files with that hash. + * @param md5Hash hash value to match files with + * @return a List of all FsContent with the given hash + */ + static List findFilesByMd5(String md5Hash) { + return skCase.findFilesByMd5(md5Hash); + } + + /** + * Given a list of string hash values, returns a map of md5 hashes + * to the list of files hit. + * @param md5Hash hash values to match files with + * @return a Map of md5 hashes mapped to the list of files hit + */ + static Map> findFilesBymd5(List md5Hash) { + Map> map = new HashMap>(); + for(String md5 : md5Hash) { + List files = findFilesByMd5(md5); + if(!files.isEmpty()) { + map.put(md5, files); + } + } + return map; + } + + /** + * Given a file, returns a list of all files with the same + * hash as the given file. + * @param file file with which to match hash values with + * @return a List of all FsContent with the same hash as file + */ + static List findFiles(FsContent file) { + String md5; + if((md5 = file.getMd5Hash()) != null) { + return findFilesByMd5(md5); + } else { + return new ArrayList(); + } + } + + /** + * Checks if the search feature is ready/enabled. Does so by checking + * if there are no Fs files in tsk_files that have and empty md5. + * @return true if the search feature is ready. + */ + static boolean isReady() { + return skCase.md5HashFinished(); + } +} diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/layer.xml b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/layer.xml index b6b1541066..c57d69edf0 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/layer.xml +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/layer.xml @@ -5,6 +5,8 @@ + + @@ -14,6 +16,10 @@ + + + + @@ -29,4 +35,4 @@ - + \ No newline at end of file From 3e337c6ae1289553b9fb146ac05af6e12ded253a Mon Sep 17 00:00:00 2001 From: devin148 Date: Fri, 27 Jul 2012 12:48:08 -0400 Subject: [PATCH 2/8] Updated Searching. --- HashDatabase/nbproject/project.xml | 244 +++++++++--------- .../hashdatabase/HashDbSearchManager.java | 161 ++++++------ .../hashdatabase/HashDbSearchNode.java | 75 ------ .../HashDbSearchResultFactory.java | 77 +++--- 4 files changed, 243 insertions(+), 314 deletions(-) delete mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchNode.java diff --git a/HashDatabase/nbproject/project.xml b/HashDatabase/nbproject/project.xml index aa0cc5a2c7..d5b6fbd052 100644 --- a/HashDatabase/nbproject/project.xml +++ b/HashDatabase/nbproject/project.xml @@ -1,118 +1,126 @@ - - - org.netbeans.modules.apisupport.project - - - org.sleuthkit.autopsy.hashdatabase - - - - org.netbeans.api.progress - - - - 1 - 1.24.1 - - - - org.openide.awt - - - - 7.31.1 - - - - org.openide.dialogs - - - - 7.20.1 - - - - org.openide.nodes - - - - 7.28.1 - - - - org.openide.util - - - - 8.15.1 - - - - org.openide.windows - - - - 6.40.1 - - - - org.sleuthkit.autopsy.casemodule - - - - 1 - 1.0 - - - - org.sleuthkit.autopsy.corecomponents - - - - 1 - 1.0 - - - - org.sleuthkit.autopsy.coreutils - - - - 0-1 - 0.0 - - - - org.sleuthkit.autopsy.datamodel - - - - 1 - 1.0 - - - - org.sleuthkit.autopsy.directorytree - - - - 1 - 1.0 - - - - org.sleuthkit.autopsy.ingest - - - - 0-1 - 1.0 - - - - - org.sleuthkit.autopsy.hashdatabase - - - - + + + org.netbeans.modules.apisupport.project + + + org.sleuthkit.autopsy.hashdatabase + + + + org.netbeans.api.progress + + + + 1 + 1.24.1 + + + + org.openide.awt + + + + 7.31.1 + + + + org.openide.dialogs + + + + 7.20.1 + + + + org.openide.nodes + + + + 7.28.1 + + + + org.openide.util + + + + 8.15.1 + + + + org.openide.util.lookup + + + + 8.15.1 + + + + org.openide.windows + + + + 6.40.1 + + + + org.sleuthkit.autopsy.casemodule + + + + 1 + 1.0 + + + + org.sleuthkit.autopsy.corecomponents + + + + 1 + 1.0 + + + + org.sleuthkit.autopsy.coreutils + + + + 0-1 + 0.0 + + + + org.sleuthkit.autopsy.datamodel + + + + 1 + 1.0 + + + + org.sleuthkit.autopsy.directorytree + + + + 1 + 1.0 + + + + org.sleuthkit.autopsy.ingest + + + + 0-1 + 1.0 + + + + + org.sleuthkit.autopsy.hashdatabase + + + + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchManager.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchManager.java index e426afa000..93e39aed8c 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchManager.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchManager.java @@ -1,83 +1,78 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011 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.hashdatabase; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import org.openide.nodes.AbstractNode; -import org.openide.nodes.Children; -import org.openide.nodes.Node; -import org.openide.windows.TopComponent; -import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; -import org.sleuthkit.datamodel.FsContent; - -/** - * - */ -public class HashDbSearchManager { - Map> map; - List pairs; - - HashDbSearchManager(Map> map) { - this.map = map; - init(); - } - - - public void execute() { - Node rootNode = null; - - if (map.size() > 0) { - Children childThingNodes = - Children.create(new HashDbSearchResultFactory(pairs), true); - - rootNode = new AbstractNode(childThingNodes); - } else { - rootNode = Node.EMPTY; - } - - final String pathText = "Keyword search"; - TopComponent searchResultWin = DataResultTopComponent.createInstance("Keyword search", pathText, rootNode, map.size()); - searchResultWin.requestActive(); - } - - private void init() { - pairs = new ArrayList(); - for(String hash : map.keySet()) { - ArrayList files = new ArrayList(); - for(FsContent file : map.get(hash)) { - files.add(file); - } - pairs.add(new HashSearchPairs(hash, files)); - } - } - -} - -class HashSearchPairs { - String hash; - List files; - - HashSearchPairs(String hash, List files) { - this.hash = hash; - this.files = files; - } -} +/* + * Autopsy Forensic Browser + * + * Copyright 2011 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.hashdatabase; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.Children; +import org.openide.nodes.Node; +import org.openide.windows.TopComponent; +import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; +import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode; +import org.sleuthkit.autopsy.datamodel.KeyValue; +import org.sleuthkit.datamodel.FsContent; + +/** + * + */ +public class HashDbSearchManager { + Map> map; + List keyValues; + + HashDbSearchManager(Map> map) { + this.map = map; + init(); + } + + private void init() { + keyValues = new ArrayList(); + int id = 0; + for(String s : map.keySet()) { + for(FsContent file : map.get(s)) { + Map keyMap = new LinkedHashMap(); + keyMap.put("Hash", s); + AbstractFsContentNode.fillPropertyMap(keyMap, file); + KeyValue kv = new KeyValue("MD5 - Name", keyMap, ++id); + keyValues.add(kv); + } + } + } + + public void execute() { + Collection things = keyValues; + Node rootNode = null; + + if (things.size() > 0) { + Children childThingNodes = + Children.create(new HashDbSearchResultFactory(map, things), true); + + rootNode = new AbstractNode(childThingNodes); + } else { + rootNode = Node.EMPTY; + } + + final String pathText = "MD5 Hash Search"; + TopComponent searchResultWin = DataResultTopComponent.createInstance("MD5 Hash Search", pathText, rootNode, things.size()); + searchResultWin.requestActive(); + } +} diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchNode.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchNode.java deleted file mode 100644 index d2249cc5f5..0000000000 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchNode.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011 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.hashdatabase; - -import org.openide.nodes.AbstractNode; -import org.openide.nodes.Children; -import org.openide.nodes.Sheet; -import org.openide.util.lookup.Lookups; -import org.sleuthkit.datamodel.SleuthkitCase; - -/** - * Node for the file search filter - */ -public class HashDbSearchNode extends AbstractNode implements DisplayableItemNode { - - SearchFilters.SearchFilterInterface filter; - SleuthkitCase skCase; - - HashDbSearchNode(SearchFilters.SearchFilterInterface filter, SleuthkitCase skCase) { - super(Children.create(new FileSearchFilterChildren(filter, skCase), true), Lookups.singleton(filter.getDisplayName())); - super.setName(filter.getName()); - super.setDisplayName(filter.getDisplayName()); - this.filter = filter; - this.skCase = skCase; - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); - } - - @Override - public T accept(DisplayableItemNodeVisitor v) { - return v.visit(this); - } - - @Override - protected Sheet createSheet() { - Sheet s = super.createSheet(); - Sheet.Set ss = s.get(Sheet.PROPERTIES); - if (ss == null) { - ss = Sheet.createPropertiesSet(); - s.put(ss); - } - - ss.put(new NodeProperty("Filter Type", - "Filter Type", - "no description", - filter.getDisplayName())); - String extensions = ""; - for(String ext : filter.getFilter()){ - extensions += "'" + ext + "', "; - } - extensions = extensions.substring(0, extensions.lastIndexOf(',')); - ss.put(new NodeProperty("File Extensions", - "File Extensions", - "no description", - extensions)); - - return s; - } - -} diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchResultFactory.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchResultFactory.java index 185657bf87..a6d7606188 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchResultFactory.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchResultFactory.java @@ -1,38 +1,39 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package org.sleuthkit.autopsy.hashdatabase; - -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import org.openide.nodes.ChildFactory; -import org.openide.nodes.Children; -import org.openide.nodes.Node; -import org.sleuthkit.datamodel.FsContent; - -/** - * - * @author dhurd - */ -public class HashDbSearchResultFactory extends ChildFactory{ - List pairs; - - HashDbSearchResultFactory(List pairs) { - this.pairs = pairs; - } - - - - @Override - protected boolean createKeys(List toPopulate) { - toPopulate.addAll(pairs); - return true; - } - - @Override - protected Node createNodeForKey(List pairs) { - return new HashDbSearchNode(pairs, Children.create(this, true)); - } -} +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.hashdatabase; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import org.openide.nodes.ChildFactory; +import org.openide.nodes.Node; +import org.sleuthkit.autopsy.datamodel.KeyValue; +import org.sleuthkit.autopsy.datamodel.KeyValueNode; +import org.sleuthkit.datamodel.FsContent; + +/** + * + * @author dhurd + */ +public class HashDbSearchResultFactory extends ChildFactory { + Collection keyValues; + Map> map; + + HashDbSearchResultFactory(Map> map, Collection keyValues) { + this.keyValues = keyValues; + this.map = map; + } + + @Override + protected boolean createKeys(List toPopulate) { + toPopulate.addAll(keyValues); + return true; + } + + @Override + protected Node createNodeForKey(KeyValue thing) { + return new KeyValueNode(thing, null); + } +} From 86b8d722bfb47a8ae25afaad613bae029befb30b Mon Sep 17 00:00:00 2001 From: dhurd Date: Fri, 27 Jul 2012 13:31:39 -0400 Subject: [PATCH 3/8] Fixing forms. --- .../AdvancedConfigurationCleanDialog.form | 1 + .../autopsy/hashdatabase/HashDbSearchPanel.form | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/CoreComponents/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.form b/CoreComponents/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.form index 9c0697f828..8c0236cde0 100644 --- a/CoreComponents/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.form +++ b/CoreComponents/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.form @@ -17,6 +17,7 @@ + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.form index 72ebaa2cdc..6014f428eb 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.form @@ -31,22 +31,22 @@ - - - - + + + - + + + - - + @@ -64,7 +64,7 @@ - + From d911801c80741a9f17d5c895c28e1130e1ff1759 Mon Sep 17 00:00:00 2001 From: dhurd Date: Fri, 27 Jul 2012 13:48:59 -0400 Subject: [PATCH 4/8] Trying to fix panel. --- HashDatabase/build.xml | 16 ++-- HashDatabase/nbproject/build-impl.xml | 90 +++++++++---------- .../hashdatabase/HashDbSearchPanel.java | 14 +-- 3 files changed, 60 insertions(+), 60 deletions(-) diff --git a/HashDatabase/build.xml b/HashDatabase/build.xml index 2bc7c94855..e4d9aeb702 100644 --- a/HashDatabase/build.xml +++ b/HashDatabase/build.xml @@ -1,8 +1,8 @@ - - - - - - Builds, tests, and runs the project org.sleuthkit.autopsy.hashdatabase. - - + + + + + + Builds, tests, and runs the project org.sleuthkit.autopsy.hashdatabase. + + diff --git a/HashDatabase/nbproject/build-impl.xml b/HashDatabase/nbproject/build-impl.xml index 1a1de7ed0f..36d67b1769 100644 --- a/HashDatabase/nbproject/build-impl.xml +++ b/HashDatabase/nbproject/build-impl.xml @@ -1,45 +1,45 @@ - - - - - - - - - - - - - You must set 'suite.dir' to point to your containing module suite - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + You must set 'suite.dir' to point to your containing module suite + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java index f4c7db1912..6ee4d79bf8 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java @@ -191,19 +191,19 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jScrollPane1) .addComponent(jSeparator1) - .addGroup(layout.createSequentialGroup() - .addComponent(titleLabel) - .addGap(0, 0, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() .addComponent(hashLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(hashField)) + .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(titleLabel) .addGroup(layout.createSequentialGroup() + .addGap(61, 61, 61) .addComponent(addButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(removeButton) - .addGap(0, 0, Short.MAX_VALUE)) - .addComponent(hashField)))))) + .addComponent(removeButton))) + .addGap(0, 0, Short.MAX_VALUE))))) .addContainerGap()) ); layout.setVerticalGroup( @@ -215,7 +215,7 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 355, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(26, 26, 26) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(hashLabel) + .addComponent(hashLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(hashField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) From 402c428d3e0249db9195ca984b06fcd45f2301ce Mon Sep 17 00:00:00 2001 From: dhurd Date: Fri, 27 Jul 2012 13:52:13 -0400 Subject: [PATCH 5/8] More panels. --- HashDatabase/nbproject/genfiles.properties | 16 +-- .../autopsy/hashdatabase/Bundle.properties | 98 +++++++++++-------- 2 files changed, 63 insertions(+), 51 deletions(-) diff --git a/HashDatabase/nbproject/genfiles.properties b/HashDatabase/nbproject/genfiles.properties index f53f934917..cd36b5ded2 100644 --- a/HashDatabase/nbproject/genfiles.properties +++ b/HashDatabase/nbproject/genfiles.properties @@ -1,8 +1,8 @@ -build.xml.data.CRC32=656aafec -build.xml.script.CRC32=1308cb72 -build.xml.stylesheet.CRC32=a56c6a5b@2.47.2 -# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. -# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. -nbproject/build-impl.xml.data.CRC32=656aafec -nbproject/build-impl.xml.script.CRC32=a7a0d07a -nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.47.2 +build.xml.data.CRC32=6c67008d +build.xml.script.CRC32=1308cb72 +build.xml.stylesheet.CRC32=a56c6a5b@2.50.1 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=6c67008d +nbproject/build-impl.xml.script.CRC32=a7a0d07a +nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.50.1 diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties index 580b129879..1b2076392e 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties @@ -1,43 +1,55 @@ -OpenIDE-Module-Name=HashDatabase -HashDatabaseManagementPanel.okayButton.text=Okay -HashDbPanel.fileSelectButton.text=Select...\n -HashDbSimplePanel.knownLabel.text=NSRL Database: -HashDbSimplePanel.notableLabel.text=Known Bad Database(s): -HashDbSimplePanel.knownValLabel.text=- -HashDbSimplePanel.notableValLabel.text=- -HashDbMgmtPanel.addNotableButton.text=Add Known Bad Database -HashDbMgmtPanel.removeNotableButton.text=Remove Selected -HashDbSimplePanel.jLabel1.text=Select known bad databases to use during ingest: -HashDbSimplePanel.jLabel2.text=NSRL Database: -HashDbMgmtPanel.nsrlNameLabel.text=Not Configured -HashDbMgmtPanel.setNSRLButton.text=Change -HashDbMgmtPanel.jLabel1.text=Known Bad Database(s): -HashDbMgmtPanel.jLabel2.text=NSRL Database: -HashDbMgmtPanel.indexNSRLButton.text=Index -HashDbMgmtPanel.removeNSRLButton.text=Remove -HashDbMgmtPanel.ingestRunningLabel.text=\ -HashDbManagementPanel.nameLabel.text=Hash DB Name: -HashDbManagementPanel.hashDbNameLabel.text=No database selected -HashDbManagementPanel.locationLabel.text=Location: -HashDbManagementPanel.hashDbLocationLabel.text=No database selected -HashDbManagementPanel.deleteButton.text=Delete -HashDbManagementPanel.useForIngestCheckbox.text=Use during ingest -HashDbManagementPanel.showInboxMessagesCheckBox.text=Send messages to inbox during ingest -HashDbManagementPanel.indexLabel.text=Index Status: -HashDbManagementPanel.indexButton.text=Index -HashDbManagementPanel.ingestRunningLabel.text= -HashDbManagementPanel.hashDbIndexStatusLabel.text=No database selected -HashDbManagementPanel.typeLabel.text=Type: -HashDbManagementPanel.hashDbTypeLabel.text=No database selected -HashDbAddDatabaseDialog.cancelButton.text=Cancel -HashDbAddDatabaseDialog.okButton.text=OK -HashDbAddDatabaseDialog.nsrlRadioButton.text=NSRL -HashDbAddDatabaseDialog.knownBadRadioButton.text=Known Bad -HashDbAddDatabaseDialog.databasePathTextField.text= -HashDbAddDatabaseDialog.browseButton.text=Browse -HashDbAddDatabaseDialog.jLabel1.text=Enter the name of the database: -HashDbAddDatabaseDialog.databaseNameTextField.text= -HashDbAddDatabaseDialog.jLabel2.text=Select the type of database: -HashDbAddDatabaseDialog.useForIngestCheckbox.text=Use during ingest -HashDbAddDatabaseDialog.sendInboxMessagesCheckbox.text=Send messages to inbox during ingest -HashDbManagementPanel.importButton.text=Import +OpenIDE-Module-Name=HashDatabase +HashDatabaseManagementPanel.okayButton.text=Okay +HashDbPanel.fileSelectButton.text=Select...\n +HashDbSimplePanel.knownLabel.text=NSRL Database: +HashDbSimplePanel.notableLabel.text=Known Bad Database(s): +HashDbSimplePanel.knownValLabel.text=- +HashDbSimplePanel.notableValLabel.text=- +HashDbMgmtPanel.addNotableButton.text=Add Known Bad Database +HashDbMgmtPanel.removeNotableButton.text=Remove Selected +HashDbSimplePanel.jLabel1.text=Select known bad databases to use during ingest: +HashDbSimplePanel.jLabel2.text=NSRL Database: +HashDbMgmtPanel.nsrlNameLabel.text=Not Configured +HashDbMgmtPanel.setNSRLButton.text=Change +HashDbMgmtPanel.jLabel1.text=Known Bad Database(s): +HashDbMgmtPanel.jLabel2.text=NSRL Database: +HashDbMgmtPanel.indexNSRLButton.text=Index +HashDbMgmtPanel.removeNSRLButton.text=Remove +HashDbMgmtPanel.ingestRunningLabel.text=\ +HashDbManagementPanel.nameLabel.text=Hash DB Name: +HashDbManagementPanel.hashDbNameLabel.text=No database selected +HashDbManagementPanel.locationLabel.text=Location: +HashDbManagementPanel.hashDbLocationLabel.text=No database selected +HashDbManagementPanel.deleteButton.text=Delete +HashDbManagementPanel.useForIngestCheckbox.text=Use during ingest +HashDbManagementPanel.showInboxMessagesCheckBox.text=Send messages to inbox during ingest +HashDbManagementPanel.indexLabel.text=Index Status: +HashDbManagementPanel.indexButton.text=Index +HashDbManagementPanel.ingestRunningLabel.text= +HashDbManagementPanel.hashDbIndexStatusLabel.text=No database selected +HashDbManagementPanel.typeLabel.text=Type: +HashDbManagementPanel.hashDbTypeLabel.text=No database selected +HashDbAddDatabaseDialog.cancelButton.text=Cancel +HashDbAddDatabaseDialog.okButton.text=OK +HashDbAddDatabaseDialog.nsrlRadioButton.text=NSRL +HashDbAddDatabaseDialog.knownBadRadioButton.text=Known Bad +HashDbAddDatabaseDialog.databasePathTextField.text= +HashDbAddDatabaseDialog.browseButton.text=Browse +HashDbAddDatabaseDialog.jLabel1.text=Enter the name of the database: +HashDbAddDatabaseDialog.databaseNameTextField.text= +HashDbAddDatabaseDialog.jLabel2.text=Select the type of database: +HashDbAddDatabaseDialog.useForIngestCheckbox.text=Use during ingest +HashDbAddDatabaseDialog.sendInboxMessagesCheckbox.text=Send messages to inbox during ingest +HashDbManagementPanel.importButton.text=Import +HashDbSearchPanel.hashTable.columnModel.title0=MD5 Hashes +HashDbSearchPanel.hashTable.columnModel.title3=Title 4 +HashDbSearchPanel.hashTable.columnModel.title2=Title 3 +HashDbSearchPanel.hashTable.columnModel.title1=Title 2 +HashDbSearchPanel.addButton.text=Add Hash +HashDbSearchPanel.hashField.text= +HashDbSearchPanel.hashLabel.text=MD5 hash: +HashDbSearchPanel.cancelButton.text=Cancel +HashDbSearchPanel.searchButton.text=Search +HashDbSearchPanel.removeButton.text=Remove Selected +HashDbSearchPanel.titleLabel.text=Search for files with the following MD5 hash(es): +HashDbSearchPanel.errorField.text=Error: Not all files have been hashed. From d3e07d350df925a832c49daff7bf20943d6f5b98 Mon Sep 17 00:00:00 2001 From: devin148 Date: Fri, 27 Jul 2012 14:58:15 -0400 Subject: [PATCH 6/8] Hash nodes added. --- .../autopsy/hashdatabase/Bundle.properties | 1 + .../hashdatabase/HashDbSearchAction.java | 132 ++++++++++-------- .../hashdatabase/HashDbSearchManager.java | 4 +- .../hashdatabase/HashDbSearchPanel.form | 13 ++ .../hashdatabase/HashDbSearchPanel.java | 34 ++++- .../HashDbSearchResultFactory.java | 3 +- 6 files changed, 121 insertions(+), 66 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties index 1b2076392e..47596c42d3 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties @@ -53,3 +53,4 @@ HashDbSearchPanel.searchButton.text=Search HashDbSearchPanel.removeButton.text=Remove Selected HashDbSearchPanel.titleLabel.text=Search for files with the following MD5 hash(es): HashDbSearchPanel.errorField.text=Error: Not all files have been hashed. +HashDbSearchPanel.saveBox.text=Remember Hashes diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchAction.java index 28af740519..460113ee94 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchAction.java @@ -1,61 +1,71 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011 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.hashdatabase; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import org.openide.util.HelpCtx; -import org.openide.util.actions.CallableSystemAction; -import org.sleuthkit.autopsy.corecomponents.AdvancedConfigurationCleanDialog; - -/** - * The HashDbSearchAction opens the HashDbSearchPanel in a dialog. - */ -class HashDbSearchAction extends CallableSystemAction { - - static final String ACTION_NAME = "Hash File Search"; - - @Override - public void performAction() { - final HashDbSearchPanel panel = HashDbSearchPanel.getDefault(); - final AdvancedConfigurationCleanDialog dialog = new AdvancedConfigurationCleanDialog(); - panel.cancelButtonListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - dialog.close(); - } - }); - dialog.display(panel); - } - - @Override - public String getName() { - return ACTION_NAME; - } - - @Override - public HelpCtx getHelpCtx() { - return HelpCtx.DEFAULT_HELP; - } - - @Override - protected boolean asynchronous() { - return false; - } -} +/* + * Autopsy Forensic Browser + * + * Copyright 2011 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.hashdatabase; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import org.openide.util.HelpCtx; +import org.openide.util.actions.CallableSystemAction; +import org.sleuthkit.autopsy.corecomponents.AdvancedConfigurationCleanDialog; + +/** + * The HashDbSearchAction opens the HashDbSearchPanel in a dialog. + */ +class HashDbSearchAction extends CallableSystemAction { + + static final String ACTION_NAME = "Hash File Search"; + + @Override + public void performAction() { + final HashDbSearchPanel panel = HashDbSearchPanel.getDefault(); + final AdvancedConfigurationCleanDialog dialog = new AdvancedConfigurationCleanDialog(); + panel.cancelButtonListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + panel.clear(); + dialog.close(); + } + }); + dialog.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + panel.clear(); + dialog.close(); + } + }); + dialog.display(panel); + } + + @Override + public String getName() { + return ACTION_NAME; + } + + @Override + public HelpCtx getHelpCtx() { + return HelpCtx.DEFAULT_HELP; + } + + @Override + protected boolean asynchronous() { + return false; + } +} diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchManager.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchManager.java index 93e39aed8c..e0c9bfca16 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchManager.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchManager.java @@ -50,9 +50,9 @@ public class HashDbSearchManager { for(String s : map.keySet()) { for(FsContent file : map.get(s)) { Map keyMap = new LinkedHashMap(); - keyMap.put("Hash", s); + keyMap.put("MD5 Hash", s); AbstractFsContentNode.fillPropertyMap(keyMap, file); - KeyValue kv = new KeyValue("MD5 - Name", keyMap, ++id); + KeyValue kv = new KeyValue(file.getName(), keyMap, ++id); keyValues.add(kv); } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.form index 6014f428eb..8dd7bff1ec 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.form @@ -44,6 +44,8 @@ + + @@ -71,6 +73,7 @@ + @@ -179,5 +182,15 @@ + + + + + + + + + + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java index 6ee4d79bf8..699690f04f 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java @@ -128,6 +128,7 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe jSeparator1 = new javax.swing.JSeparator(); titleLabel = new javax.swing.JLabel(); errorField = new javax.swing.JLabel(); + saveBox = new javax.swing.JCheckBox(); hashTable.setModel(new javax.swing.table.DefaultTableModel( new Object [][] { @@ -173,6 +174,13 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe errorField.setForeground(new java.awt.Color(255, 0, 0)); org.openide.awt.Mnemonics.setLocalizedText(errorField, org.openide.util.NbBundle.getMessage(HashDbSearchPanel.class, "HashDbSearchPanel.errorField.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(saveBox, org.openide.util.NbBundle.getMessage(HashDbSearchPanel.class, "HashDbSearchPanel.saveBox.text")); // NOI18N + saveBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + saveBoxActionPerformed(evt); + } + }); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -202,7 +210,9 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe .addGap(61, 61, 61) .addComponent(addButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(removeButton))) + .addComponent(removeButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(saveBox))) .addGap(0, 0, Short.MAX_VALUE))))) .addContainerGap()) ); @@ -220,7 +230,8 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(addButton) - .addComponent(removeButton)) + .addComponent(removeButton) + .addComponent(saveBox)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 27, Short.MAX_VALUE) .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) @@ -231,6 +242,11 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe .addContainerGap()) ); }// //GEN-END:initComponents + + private void saveBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveBoxActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_saveBoxActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton addButton; private javax.swing.JButton cancelButton; @@ -241,6 +257,7 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe private javax.swing.JScrollPane jScrollPane1; private javax.swing.JSeparator jSeparator1; private javax.swing.JButton removeButton; + private javax.swing.JCheckBox saveBox; private javax.swing.JButton searchButton; private javax.swing.JLabel titleLabel; // End of variables declaration//GEN-END:variables @@ -306,4 +323,17 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe model.removeRow(rows[i]); } } + + /** + * Clears the table of hashes + */ + void clear() { + if(!saveBox.isSelected()) { + DefaultTableModel model = (DefaultTableModel) hashTable.getModel(); + int numRows = hashTable.getRowCount(); + for(int i=0; i { @Override protected Node createNodeForKey(KeyValue thing) { - return new KeyValueNode(thing, null); + return new KeyValueNode(thing, Children.LEAF); } } From 66f60982b27a0e3327162887a8cd758e89192517 Mon Sep 17 00:00:00 2001 From: dhurd Date: Fri, 27 Jul 2012 16:19:22 -0400 Subject: [PATCH 7/8] MD5 hash searching implemented through nodes, comeplete. --- .../autopsy/hashdatabase/Bundle.properties | 1 - .../hashdatabase/HashDbSearchAction.java | 18 +++--- .../hashdatabase/HashDbSearchManager.java | 34 ++++++++-- .../hashdatabase/HashDbSearchPanel.form | 12 +--- .../hashdatabase/HashDbSearchPanel.java | 62 ++++++++++--------- .../HashDbSearchResultFactory.java | 37 +++++++---- 6 files changed, 99 insertions(+), 65 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties index 47596c42d3..83fcbf01c4 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties @@ -48,7 +48,6 @@ HashDbSearchPanel.hashTable.columnModel.title1=Title 2 HashDbSearchPanel.addButton.text=Add Hash HashDbSearchPanel.hashField.text= HashDbSearchPanel.hashLabel.text=MD5 hash: -HashDbSearchPanel.cancelButton.text=Cancel HashDbSearchPanel.searchButton.text=Search HashDbSearchPanel.removeButton.text=Remove Selected HashDbSearchPanel.titleLabel.text=Search for files with the following MD5 hash(es): diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchAction.java index 460113ee94..2f24b38ee4 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchAction.java @@ -37,13 +37,7 @@ class HashDbSearchAction extends CallableSystemAction { public void performAction() { final HashDbSearchPanel panel = HashDbSearchPanel.getDefault(); final AdvancedConfigurationCleanDialog dialog = new AdvancedConfigurationCleanDialog(); - panel.cancelButtonListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - panel.clear(); - dialog.close(); - } - }); + // Set the dialog close button to clear then close the window dialog.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { @@ -51,6 +45,16 @@ class HashDbSearchAction extends CallableSystemAction { dialog.close(); } }); + // Have the search button close the window after searching + panel.addSearchActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if(panel.doSearch()) { + panel.clear(); + dialog.close(); + } + } + }); dialog.display(panel); } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchManager.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchManager.java index e0c9bfca16..5ae58ce905 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchManager.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchManager.java @@ -30,36 +30,47 @@ import org.openide.windows.TopComponent; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode; import org.sleuthkit.autopsy.datamodel.KeyValue; +import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.FsContent; /** - * + * Interface/Node manager for hash searching. The manager takes in the raw + * map of MD5 hashes to files, flattens the map, and sends it to the HashDbSearchResultFactory. */ public class HashDbSearchManager { Map> map; - List keyValues; + List keyValues; HashDbSearchManager(Map> map) { this.map = map; init(); } + /** + * Initializes the flattened map of KeyValues. Each map in a KeyValue is a + * row in the table, with the String as it's column name and the Object + * as it's value in the row. + */ private void init() { - keyValues = new ArrayList(); + keyValues = new ArrayList(); int id = 0; for(String s : map.keySet()) { for(FsContent file : map.get(s)) { Map keyMap = new LinkedHashMap(); keyMap.put("MD5 Hash", s); AbstractFsContentNode.fillPropertyMap(keyMap, file); - KeyValue kv = new KeyValue(file.getName(), keyMap, ++id); + KeyValueContent kv = new KeyValueContent(file.getName(), keyMap, ++id, file); keyValues.add(kv); } } } + /** + * Takes the key values, creates nodes through the HashDbSearchResultFactory, and + * displays it in a TopComponent on the GUI. + */ public void execute() { - Collection things = keyValues; + Collection things = keyValues; Node rootNode = null; if (things.size() > 0) { @@ -76,3 +87,16 @@ public class HashDbSearchManager { searchResultWin.requestActive(); } } + +class KeyValueContent extends KeyValue { + Content content; + + KeyValueContent(String name, Map map, int id, Content content) { + super(name, map, id); + this.content = content; + } + + Content getContent() { + return content; + } +} diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.form index 8dd7bff1ec..cc2546ebb2 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.form @@ -21,10 +21,8 @@ - - - + @@ -79,7 +77,6 @@ - @@ -139,13 +136,6 @@ - - - - - - - diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java index 699690f04f..ad1cae6a4e 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java @@ -26,7 +26,6 @@ import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.table.DefaultTableModel; import org.sleuthkit.datamodel.FsContent; @@ -38,7 +37,7 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe private static final Logger logger = Logger.getLogger(HashDbSearchPanel.class.getName()); private static HashDbSearchPanel instance; private static boolean ingestRunning = false; - + /** * @return the default instance of this panel */ @@ -59,7 +58,6 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe } final void customInit() { - searchButton.addActionListener(this); addButton.addActionListener(this); removeButton.addActionListener(this); errorField.setVisible(false); @@ -84,6 +82,13 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe }); } + void addSearchActionListener(ActionListener l) { + for(ActionListener al : searchButton.getActionListeners()) { + searchButton.removeActionListener(al); + } + searchButton.addActionListener(l); + } + /** * Don't allow any changes if ingest is running */ @@ -103,10 +108,6 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe hashTable.setEnabled(!ingestRunning); hashLabel.setEnabled(!ingestRunning); } - - void cancelButtonListener(ActionListener l) { - cancelButton.addActionListener(l); - } /** * This method is called from within the constructor to initialize the form. @@ -122,7 +123,6 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe hashField = new javax.swing.JTextField(); addButton = new javax.swing.JButton(); hashLabel = new javax.swing.JLabel(); - cancelButton = new javax.swing.JButton(); searchButton = new javax.swing.JButton(); removeButton = new javax.swing.JButton(); jSeparator1 = new javax.swing.JSeparator(); @@ -162,8 +162,6 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe org.openide.awt.Mnemonics.setLocalizedText(hashLabel, org.openide.util.NbBundle.getMessage(HashDbSearchPanel.class, "HashDbSearchPanel.hashLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(HashDbSearchPanel.class, "HashDbSearchPanel.cancelButton.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(searchButton, org.openide.util.NbBundle.getMessage(HashDbSearchPanel.class, "HashDbSearchPanel.searchButton.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(removeButton, org.openide.util.NbBundle.getMessage(HashDbSearchPanel.class, "HashDbSearchPanel.removeButton.text")); // NOI18N @@ -190,10 +188,8 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGap(0, 0, Short.MAX_VALUE) .addComponent(errorField) - .addGap(18, 18, 18) - .addComponent(searchButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(cancelButton)) + .addComponent(searchButton)) .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -236,7 +232,6 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(cancelButton) .addComponent(searchButton) .addComponent(errorField)) .addContainerGap()) @@ -249,7 +244,6 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton addButton; - private javax.swing.JButton cancelButton; private javax.swing.JLabel errorField; private javax.swing.JTextField hashField; private javax.swing.JLabel hashLabel; @@ -277,23 +271,31 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe * Search through all tsk_files to find ones with the same hashes as the * hashes given. */ - void doSearch() { + boolean doSearch() { // Make sure all files have an md5 hash if(HashDbSearcher.isReady()) { - errorField.setEnabled(false); - cancelButton.setText("Done"); // no changes so done - // Get all the rows in the table - int numRows = hashTable.getRowCount(); - ArrayList hashes = new ArrayList(); - for(int i=0; i hashes = new ArrayList(); + for(int i=0; i> map = HashDbSearcher.findFilesBymd5(hashes); + HashDbSearchManager man = new HashDbSearchManager(map); + man.execute(); + return true; + } else { + errorField.setText("No hashes have been entered."); + errorField.setVisible(true); + return false; } - // Get the map of hashes to FsContent and send it to the manager - Map> map = HashDbSearcher.findFilesBymd5(hashes); - HashDbSearchManager man = new HashDbSearchManager(map); - man.execute(); } else { + errorField.setText("Error: Not all files have been hashed."); errorField.setVisible(true); + return false; } } @@ -301,7 +303,6 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe * Add the given text into the table of hashes. */ void add() { - cancelButton.setText("Cancel"); // changes means cancel DefaultTableModel model = (DefaultTableModel) hashTable.getModel(); if(!hashField.getText().equals("")) { model.addRow(new String[] {hashField.getText()}); @@ -314,7 +315,6 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe * Remove all of the highlighted/selected rows from the table of hashes. */ void remove() { - cancelButton.setText("Cancel"); // changes means cancel DefaultTableModel model = (DefaultTableModel) hashTable.getModel(); int rows[] = hashTable.getSelectedRows(); // Loop backwards to delete highest row index first, otherwise @@ -331,9 +331,11 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe if(!saveBox.isSelected()) { DefaultTableModel model = (DefaultTableModel) hashTable.getModel(); int numRows = hashTable.getRowCount(); - for(int i=0; i=0; i--) { model.removeRow(i); } } + errorField.setVisible(false); + hashField.setText(""); } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchResultFactory.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchResultFactory.java index 04499a8fed..19f0f6ebaa 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchResultFactory.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchResultFactory.java @@ -1,6 +1,20 @@ /* - * To change this template, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2011 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.hashdatabase; @@ -10,31 +24,32 @@ import java.util.Map; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; -import org.sleuthkit.autopsy.datamodel.KeyValue; +import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.datamodel.KeyValueNode; +import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.FsContent; /** - * - * @author dhurd + * Creates a Node for each KeyValue. */ -public class HashDbSearchResultFactory extends ChildFactory { - Collection keyValues; +public class HashDbSearchResultFactory extends ChildFactory { + Collection keyValues; Map> map; - HashDbSearchResultFactory(Map> map, Collection keyValues) { + HashDbSearchResultFactory(Map> map, Collection keyValues) { this.keyValues = keyValues; this.map = map; } @Override - protected boolean createKeys(List toPopulate) { + protected boolean createKeys(List toPopulate) { toPopulate.addAll(keyValues); return true; } @Override - protected Node createNodeForKey(KeyValue thing) { - return new KeyValueNode(thing, Children.LEAF); + protected Node createNodeForKey(KeyValueContent thing) { + final Content content = thing.getContent(); + return new KeyValueNode(thing, Children.LEAF, Lookups.singleton(content)); } } From 08a0972636d42e3699d3a64021f982f5440b2ce6 Mon Sep 17 00:00:00 2001 From: dhurd Date: Mon, 30 Jul 2012 16:54:12 -0400 Subject: [PATCH 8/8] Added search by MD5 hash to toolbar, as well as search by selected file's MD5 hash to the right click menu. --- .../autopsy/datamodel/ContentUtils.java | 788 ++++++++--------- .../autopsy/datamodel/KeyValueNode.java | 144 ++-- .../directorytree/DataResultFilterNode.java | 798 +++++++++--------- .../directorytree/HashSearchAction.java | 43 + .../directorytree/HashSearchProvider.java | 28 + .../hashdatabase/HashDbSearchManager.java | 17 +- .../hashdatabase/HashDbSearchPanel.java | 2 +- .../HashDbSearchResultFactory.java | 4 +- .../autopsy/hashdatabase/HashDbSearcher.java | 4 +- .../hashdatabase/HashSearchAction.java | 119 +++ .../autopsy/hashdatabase/KeyValueContent.java | 39 + .../hashdatabase/KeyValueFileNode.java | 93 ++ .../sleuthkit/autopsy/hashdatabase/layer.xml | 7 + 13 files changed, 1201 insertions(+), 885 deletions(-) create mode 100644 DirectoryTree/src/org/sleuthkit/autopsy/directorytree/HashSearchAction.java create mode 100644 DirectoryTree/src/org/sleuthkit/autopsy/directorytree/HashSearchProvider.java create mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSearchAction.java create mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/KeyValueContent.java create mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/KeyValueFileNode.java diff --git a/DataModel/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java b/DataModel/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java index 2fb43af3fb..e4f9b748e9 100644 --- a/DataModel/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java +++ b/DataModel/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java @@ -1,394 +1,394 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011 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; - -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.text.SimpleDateFormat; -import java.util.LinkedList; -import java.util.List; -import java.util.TimeZone; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.swing.SwingWorker; -import org.netbeans.api.progress.ProgressHandle; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.ContentVisitor; -import org.sleuthkit.datamodel.Directory; -import org.sleuthkit.datamodel.File; -import org.sleuthkit.datamodel.FileSystem; -import org.sleuthkit.datamodel.FsContent; -import org.sleuthkit.datamodel.Image; -import org.sleuthkit.datamodel.LayoutFile; -import org.sleuthkit.datamodel.ReadContentInputStream; -import org.sleuthkit.datamodel.TskException; -import org.sleuthkit.datamodel.Volume; -import org.sleuthkit.datamodel.VolumeSystem; - -/** - * Static class of utility methods for Content objects - */ -public final class ContentUtils { - - private final static Logger logger = Logger.getLogger(ContentUtils.class.getName()); - private static SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - - // don't instantiate - private ContentUtils() { - throw new AssertionError(); - } - - private static final ShortNameVisitor shortName = new ShortNameVisitor(); - - private static final GetPathVisitor getDisplayPath = new GetPathVisitor(shortName); - - /** - * Returns full path to this node. - * - * @return the path of this node - */ - public static String[] getDisplayPath(Content content) { - return content.accept(getDisplayPath).toArray(new String[]{}); - } - - - /** - * Convert epoch seconds to a string value in the given time zone - * @param epochSeconds - * @param tzone - * @return - */ - public static String getStringTime(long epochSeconds, TimeZone tzone) { - String time = "0000-00-00 00:00:00"; - if (epochSeconds != 0) { - dateFormatter.setTimeZone(tzone); - time = dateFormatter.format(new java.util.Date(epochSeconds * 1000)); - } - return time; - } - - /** - * Convert epoch seconds to a string value (convenience method) - * @param epochSeconds - * @param c - * @return - */ - public static String getStringTime(long epochSeconds, Content c) { - return getStringTime(epochSeconds, getTimeZone(c)); - } - - public static TimeZone getTimeZone(Content c) { - try { - return TimeZone.getTimeZone(c.getImage().getTimeZone()); - } catch(TskException ex) { - return TimeZone.getDefault(); - } - } - - private static final SystemNameVisitor systemName = new SystemNameVisitor(); - - private static final GetPathVisitor getSystemPath = new GetPathVisitor(systemName); - - /** - * Returns full path to this node. - * - * @return the path of this node - */ - public static String[] getSystemPath(Content content) { - return content.accept(getSystemPath).toArray(new String[]{}); - } - - static String getSystemName(Content content) { - return content.accept(systemName); - } - - private static class SystemNameVisitor extends ContentVisitor.Default { - SystemNameVisitor() {} - - @Override - protected String defaultVisit(Content cntnt) { - return cntnt.accept(shortName) + ":" + Long.toString(cntnt.getId()); - } - } - - private static class ShortNameVisitor extends ContentVisitor.Default { - ShortNameVisitor() {} - - @Override - protected String defaultVisit(Content cntnt) { - return cntnt.getName(); - } - } - - private static class GetPathVisitor implements ContentVisitor> { - ContentVisitor toString; - - GetPathVisitor(ContentVisitor toString) { - this.toString = toString; - } - - @Override - public List visit(LayoutFile lay) { - List path = lay.getParent().accept(this); - path.add(toString.visit(lay)); - return path; - } - - @Override - public List visit(Directory dir) { - List path; - - if (dir.isRoot()) { - path = dir.getFileSystem().accept(this); - } else { - try { - path = dir.getParentDirectory().accept(this); - path.add(toString.visit(dir)); - } catch (TskException ex) { - throw new RuntimeException("Couldn't get directory path.", ex); - } - } - - return path; - } - - @Override - public List visit(File file) { - try { - List path = file.getParentDirectory().accept(this); - path.add(toString.visit(file)); - return path; - } catch (TskException ex) { - throw new RuntimeException("Couldn't get file path.", ex); - } - } - - @Override - public List visit(FileSystem fs) { - return fs.getParent().accept(this); - } - - @Override - public List visit(Image image) { - List path = new LinkedList(); - path.add(toString.visit(image)); - return path; - } - - @Override - public List visit(Volume volume) { - List path = volume.getParent().accept(this); - path.add(toString.visit(volume)); - return path; - } - - @Override - public List visit(VolumeSystem vs) { - return vs.getParent().accept(this); - } - } - - - private static final int TO_FILE_BUFFER_SIZE = 8192; - - /** - * Reads all the data from any content object and writes it to a file. - * @param content Any content object. - * @param outputFile Will be created if it doesn't exist, and overwritten if - * it does - * @throws IOException - */ - public static void writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, SwingWorker worker, boolean source) throws IOException { - - InputStream in = new ReadContentInputStream(content); - - boolean append = false; - FileOutputStream out = new FileOutputStream(outputFile, append); - - // Get the unit size for a progress bar - int unit = (int) (content.getSize() / 100); - long totalRead = 0; - - try { - byte[] buffer = new byte[TO_FILE_BUFFER_SIZE]; - int len = in.read(buffer); - while (len != -1) { - // If there is a worker, check for a cancelation - if (worker!=null && worker.isCancelled()) { - break; - } - out.write(buffer, 0, len); - len = in.read(buffer); - totalRead+=len; - // If there is a progress bar and this is the source file, - // report any progress - if(progress!=null && source) { - int totalProgress = (int) (totalRead / unit); - progress.progress(content.getName(), totalProgress); - // If it's not the source, just update the file being processed - } else if(progress!=null && !source) { - progress.progress(content.getName()); - } - } - } finally { - out.close(); - } - } - - public static void writeToFile(Content content, java.io.File outputFile) throws IOException { - writeToFile(content, outputFile, null, null, false); - } - - /** - * Helper to ignore the '.' and '..' directories - */ - public static boolean isDotDirectory(Directory dir) { - String name = dir.getName(); - return name.equals(".") || name.equals(".."); - } - - - /** - * Extracts file/folder as given destination file, recursing into folders. - * Assumes there will be no collisions with existing directories/files, and - * that the directory to contain the destination file already exists. - */ - public static class ExtractFscContentVisitor extends ContentVisitor.Default { - - java.io.File dest; - ProgressHandle progress; - SwingWorker worker; - boolean source = false; - - /** - * Make new extractor for a specific destination - * @param dest The file/folder visited will be extracted as this file - */ - public ExtractFscContentVisitor(java.io.File dest, ProgressHandle progress, SwingWorker worker, boolean source) { - this.dest = dest; - this.progress = progress; - this.worker = worker; - this.source = source; - } - - public ExtractFscContentVisitor(java.io.File dest) { - this.dest = dest; - } - - /** - * Convenience method to make a new instance for given destination - * and extract given content - */ - public static void extract(Content cntnt, java.io.File dest, ProgressHandle progress, SwingWorker worker) { - cntnt.accept(new ExtractFscContentVisitor(dest, progress, worker, true)); - } - - public Void visit(File f) { - try { - ContentUtils.writeToFile(f, dest, progress, worker, source); - } catch (IOException ex) { - logger.log(Level.SEVERE, - "Trouble extracting file to " + dest.getAbsolutePath(), - ex); - } - return null; - } - - @Override - public Void visit(Directory dir) { - - // don't extract . and .. directories - if (isDotDirectory(dir)) { - return null; - } - - dest.mkdir(); - - // member visitor to generate destination files for children - DestFileContentVisitor destFileCV = new DestFileContentVisitor(); - - try { - int numProcessed = 0; - // recurse on children - for (Content child : dir.getChildren()) { - java.io.File childFile = child.accept(destFileCV); - ExtractFscContentVisitor childVisitor = - new ExtractFscContentVisitor(childFile, progress, worker, false); - // If this is the source directory of an extract it - // will have a progress and worker, and will keep track - // of the progress bar's progress - if(worker!=null && worker.isCancelled()) { - break; - } - if(progress!=null && source) { - progress.progress(child.getName(), numProcessed); - } - child.accept(childVisitor); - numProcessed++; - } - } catch (TskException ex) { - logger.log(Level.SEVERE, - "Trouble fetching children to extract.", ex); - } - - return null; - } - - @Override - protected Void defaultVisit(Content cntnt) { - throw new UnsupportedOperationException("Can't extract a " - + cntnt.getClass().getSimpleName()); - } - - /** - * Helper visitor to get the destination file for a child Content object - */ - private class DestFileContentVisitor extends - ContentVisitor.Default { - - /** - * Get destination file by adding File/Directory name to the path - * of parent - */ - private java.io.File getFsContentDest(FsContent fsc) { - String path = dest.getAbsolutePath() + java.io.File.separator - + fsc.getName(); - return new java.io.File(path); - } - - @Override - public java.io.File visit(File f) { - return getFsContentDest(f); - } - - @Override - public java.io.File visit(Directory dir) { - return getFsContentDest(dir); - } - - @Override - protected java.io.File defaultVisit(Content cntnt) { - throw new UnsupportedOperationException("Can't get destination file for a " - + cntnt.getClass().getSimpleName()); - } - } - } -} +/* + * Autopsy Forensic Browser + * + * Copyright 2011 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; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.text.SimpleDateFormat; +import java.util.LinkedList; +import java.util.List; +import java.util.TimeZone; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.SwingWorker; +import org.netbeans.api.progress.ProgressHandle; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.ContentVisitor; +import org.sleuthkit.datamodel.Directory; +import org.sleuthkit.datamodel.File; +import org.sleuthkit.datamodel.FileSystem; +import org.sleuthkit.datamodel.FsContent; +import org.sleuthkit.datamodel.Image; +import org.sleuthkit.datamodel.LayoutFile; +import org.sleuthkit.datamodel.ReadContentInputStream; +import org.sleuthkit.datamodel.TskException; +import org.sleuthkit.datamodel.Volume; +import org.sleuthkit.datamodel.VolumeSystem; + +/** + * Static class of utility methods for Content objects + */ +public final class ContentUtils { + + private final static Logger logger = Logger.getLogger(ContentUtils.class.getName()); + private static SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + // don't instantiate + private ContentUtils() { + throw new AssertionError(); + } + + private static final ShortNameVisitor shortName = new ShortNameVisitor(); + + private static final GetPathVisitor getDisplayPath = new GetPathVisitor(shortName); + + /** + * Returns full path to this node. + * + * @return the path of this node + */ + public static String[] getDisplayPath(Content content) { + return content.accept(getDisplayPath).toArray(new String[]{}); + } + + + /** + * Convert epoch seconds to a string value in the given time zone + * @param epochSeconds + * @param tzone + * @return + */ + public static String getStringTime(long epochSeconds, TimeZone tzone) { + String time = "0000-00-00 00:00:00"; + if (epochSeconds != 0) { + dateFormatter.setTimeZone(tzone); + time = dateFormatter.format(new java.util.Date(epochSeconds * 1000)); + } + return time; + } + + /** + * Convert epoch seconds to a string value (convenience method) + * @param epochSeconds + * @param c + * @return + */ + public static String getStringTime(long epochSeconds, Content c) { + return getStringTime(epochSeconds, getTimeZone(c)); + } + + public static TimeZone getTimeZone(Content c) { + try { + return TimeZone.getTimeZone(c.getImage().getTimeZone()); + } catch(TskException ex) { + return TimeZone.getDefault(); + } + } + + private static final SystemNameVisitor systemName = new SystemNameVisitor(); + + private static final GetPathVisitor getSystemPath = new GetPathVisitor(systemName); + + /** + * Returns full path to this node. + * + * @return the path of this node + */ + public static String[] getSystemPath(Content content) { + return content.accept(getSystemPath).toArray(new String[]{}); + } + + static String getSystemName(Content content) { + return content.accept(systemName); + } + + private static class SystemNameVisitor extends ContentVisitor.Default { + SystemNameVisitor() {} + + @Override + protected String defaultVisit(Content cntnt) { + return cntnt.accept(shortName) + ":" + Long.toString(cntnt.getId()); + } + } + + private static class ShortNameVisitor extends ContentVisitor.Default { + ShortNameVisitor() {} + + @Override + protected String defaultVisit(Content cntnt) { + return cntnt.getName(); + } + } + + private static class GetPathVisitor implements ContentVisitor> { + ContentVisitor toString; + + GetPathVisitor(ContentVisitor toString) { + this.toString = toString; + } + + @Override + public List visit(LayoutFile lay) { + List path = lay.getParent().accept(this); + path.add(toString.visit(lay)); + return path; + } + + @Override + public List visit(Directory dir) { + List path; + + if (dir.isRoot()) { + path = dir.getFileSystem().accept(this); + } else { + try { + path = dir.getParentDirectory().accept(this); + path.add(toString.visit(dir)); + } catch (TskException ex) { + throw new RuntimeException("Couldn't get directory path.", ex); + } + } + + return path; + } + + @Override + public List visit(File file) { + try { + List path = file.getParentDirectory().accept(this); + path.add(toString.visit(file)); + return path; + } catch (TskException ex) { + throw new RuntimeException("Couldn't get file path.", ex); + } + } + + @Override + public List visit(FileSystem fs) { + return fs.getParent().accept(this); + } + + @Override + public List visit(Image image) { + List path = new LinkedList(); + path.add(toString.visit(image)); + return path; + } + + @Override + public List visit(Volume volume) { + List path = volume.getParent().accept(this); + path.add(toString.visit(volume)); + return path; + } + + @Override + public List visit(VolumeSystem vs) { + return vs.getParent().accept(this); + } + } + + + private static final int TO_FILE_BUFFER_SIZE = 8192; + + /** + * Reads all the data from any content object and writes it to a file. + * @param content Any content object. + * @param outputFile Will be created if it doesn't exist, and overwritten if + * it does + * @throws IOException + */ + public static void writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, SwingWorker worker, boolean source) throws IOException { + + InputStream in = new ReadContentInputStream(content); + + boolean append = false; + FileOutputStream out = new FileOutputStream(outputFile, append); + + // Get the unit size for a progress bar + int unit = (int) (content.getSize() / 100); + long totalRead = 0; + + try { + byte[] buffer = new byte[TO_FILE_BUFFER_SIZE]; + int len = in.read(buffer); + while (len != -1) { + // If there is a worker, check for a cancelation + if (worker!=null && worker.isCancelled()) { + break; + } + out.write(buffer, 0, len); + len = in.read(buffer); + totalRead+=len; + // If there is a progress bar, and this is the source file, + // and there will be more than one read, report any progress + if(progress!=null && source && totalRead>=TO_FILE_BUFFER_SIZE) { + int totalProgress = (int) (totalRead / unit); + progress.progress(content.getName(), totalProgress); + // If it's not the source, just update the file being processed + } else if(progress!=null && !source) { + progress.progress(content.getName()); + } + } + } finally { + out.close(); + } + } + + public static void writeToFile(Content content, java.io.File outputFile) throws IOException { + writeToFile(content, outputFile, null, null, false); + } + + /** + * Helper to ignore the '.' and '..' directories + */ + public static boolean isDotDirectory(Directory dir) { + String name = dir.getName(); + return name.equals(".") || name.equals(".."); + } + + + /** + * Extracts file/folder as given destination file, recursing into folders. + * Assumes there will be no collisions with existing directories/files, and + * that the directory to contain the destination file already exists. + */ + public static class ExtractFscContentVisitor extends ContentVisitor.Default { + + java.io.File dest; + ProgressHandle progress; + SwingWorker worker; + boolean source = false; + + /** + * Make new extractor for a specific destination + * @param dest The file/folder visited will be extracted as this file + */ + public ExtractFscContentVisitor(java.io.File dest, ProgressHandle progress, SwingWorker worker, boolean source) { + this.dest = dest; + this.progress = progress; + this.worker = worker; + this.source = source; + } + + public ExtractFscContentVisitor(java.io.File dest) { + this.dest = dest; + } + + /** + * Convenience method to make a new instance for given destination + * and extract given content + */ + public static void extract(Content cntnt, java.io.File dest, ProgressHandle progress, SwingWorker worker) { + cntnt.accept(new ExtractFscContentVisitor(dest, progress, worker, true)); + } + + public Void visit(File f) { + try { + ContentUtils.writeToFile(f, dest, progress, worker, source); + } catch (IOException ex) { + logger.log(Level.SEVERE, + "Trouble extracting file to " + dest.getAbsolutePath(), + ex); + } + return null; + } + + @Override + public Void visit(Directory dir) { + + // don't extract . and .. directories + if (isDotDirectory(dir)) { + return null; + } + + dest.mkdir(); + + // member visitor to generate destination files for children + DestFileContentVisitor destFileCV = new DestFileContentVisitor(); + + try { + int numProcessed = 0; + // recurse on children + for (Content child : dir.getChildren()) { + java.io.File childFile = child.accept(destFileCV); + ExtractFscContentVisitor childVisitor = + new ExtractFscContentVisitor(childFile, progress, worker, false); + // If this is the source directory of an extract it + // will have a progress and worker, and will keep track + // of the progress bar's progress + if(worker!=null && worker.isCancelled()) { + break; + } + if(progress!=null && source) { + progress.progress(child.getName(), numProcessed); + } + child.accept(childVisitor); + numProcessed++; + } + } catch (TskException ex) { + logger.log(Level.SEVERE, + "Trouble fetching children to extract.", ex); + } + + return null; + } + + @Override + protected Void defaultVisit(Content cntnt) { + throw new UnsupportedOperationException("Can't extract a " + + cntnt.getClass().getSimpleName()); + } + + /** + * Helper visitor to get the destination file for a child Content object + */ + private class DestFileContentVisitor extends + ContentVisitor.Default { + + /** + * Get destination file by adding File/Directory name to the path + * of parent + */ + private java.io.File getFsContentDest(FsContent fsc) { + String path = dest.getAbsolutePath() + java.io.File.separator + + fsc.getName(); + return new java.io.File(path); + } + + @Override + public java.io.File visit(File f) { + return getFsContentDest(f); + } + + @Override + public java.io.File visit(Directory dir) { + return getFsContentDest(dir); + } + + @Override + protected java.io.File defaultVisit(Content cntnt) { + throw new UnsupportedOperationException("Can't get destination file for a " + + cntnt.getClass().getSimpleName()); + } + } + } +} diff --git a/DataModel/src/org/sleuthkit/autopsy/datamodel/KeyValueNode.java b/DataModel/src/org/sleuthkit/autopsy/datamodel/KeyValueNode.java index 6eedec478f..aba5b25a8c 100644 --- a/DataModel/src/org/sleuthkit/autopsy/datamodel/KeyValueNode.java +++ b/DataModel/src/org/sleuthkit/autopsy/datamodel/KeyValueNode.java @@ -1,72 +1,72 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011 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; - -import java.util.Map; -import org.openide.nodes.AbstractNode; -import org.openide.nodes.Children; -import org.openide.nodes.Sheet; -import org.openide.util.Lookup; -import org.openide.util.lookup.Lookups; - -/** - * Node that contains a KeyValue object. The node also has that KeyValue object - * set to its lookup so that when the node is passed to the content viewers its - * string will be displayed. - * @author alawrence - */ -public class KeyValueNode extends AbstractNode { - - KeyValue thing; - - public KeyValueNode(KeyValue thing, Children children) { - super(children, Lookups.singleton(thing)); - this.setName(thing.getName()); - this.thing = thing; - } - - public KeyValueNode(KeyValue thing, Children children, Lookup lookup) { - super(children, lookup); - this.setName(thing.getName()); - this.thing = thing; - } - - @Override - protected Sheet createSheet() { - Sheet s = super.createSheet(); - Sheet.Set ss = s.get(Sheet.PROPERTIES); - if (ss == null) { - ss = Sheet.createPropertiesSet(); - s.put(ss); - } - - // table view drops first column of properties under assumption - // that it contains the node's name - ss.put(new NodeProperty("Name", "Name", "n/a", thing.getName())); - - for (Map.Entry entry : thing.getMap().entrySet()) { - String key = entry.getKey(); - Object value = entry.getValue(); - ss.put(new NodeProperty(key, key, "n/a", value)); - } - - return s; - } -} +/* + * Autopsy Forensic Browser + * + * Copyright 2011 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; + +import java.util.Map; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.Children; +import org.openide.nodes.Sheet; +import org.openide.util.Lookup; +import org.openide.util.lookup.Lookups; + +/** + * Node that contains a KeyValue object. The node also has that KeyValue object + * set to its lookup so that when the node is passed to the content viewers its + * string will be displayed. + * @author alawrence + */ +public class KeyValueNode extends AbstractNode { + + KeyValue thing; + + public KeyValueNode(KeyValue thing, Children children) { + super(children, Lookups.singleton(thing)); + this.setName(thing.getName()); + this.thing = thing; + } + + public KeyValueNode(KeyValue thing, Children children, Lookup lookup) { + super(children, lookup); + this.setName(thing.getName()); + this.thing = thing; + } + + @Override + protected Sheet createSheet() { + Sheet s = super.createSheet(); + Sheet.Set ss = s.get(Sheet.PROPERTIES); + if (ss == null) { + ss = Sheet.createPropertiesSet(); + s.put(ss); + } + + // table view drops first column of properties under assumption + // that it contains the node's name + ss.put(new NodeProperty("Name", "Name", "n/a", thing.getName())); + + for (Map.Entry entry : thing.getMap().entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + ss.put(new NodeProperty(key, key, "n/a", value)); + } + + return s; + } +} diff --git a/DirectoryTree/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/DirectoryTree/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index 2bfef28bcb..99814e4dc7 100644 --- a/DirectoryTree/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/DirectoryTree/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -1,399 +1,401 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011 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.directorytree; - -import java.awt.event.ActionEvent; -import java.beans.PropertyVetoException; -import java.util.ArrayList; -import java.util.List; -import org.sleuthkit.autopsy.datamodel.VolumeNode; -import org.sleuthkit.autopsy.datamodel.DirectoryNode; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.swing.AbstractAction; -import javax.swing.Action; -import org.openide.explorer.ExplorerManager; -import org.openide.nodes.AbstractNode; -import org.openide.nodes.FilterNode; -import org.openide.nodes.Node; -import org.openide.nodes.Sheet; -import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode; -import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode.FsContentPropertyType; -import org.sleuthkit.autopsy.datamodel.ArtifactTypeNode; -import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; -import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; -import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; -import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedAccountNode; -import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedFolderNode; -import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedRootNode; -import org.sleuthkit.autopsy.datamodel.ExtractedContentNode; -import org.sleuthkit.autopsy.datamodel.FileNode; -import org.sleuthkit.autopsy.datamodel.FileSearchFilterNode; -import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsRootNode; -import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsSetNode; -import org.sleuthkit.autopsy.datamodel.ImageNode; -import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsKeywordNode; -import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsListNode; -import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode; -import org.sleuthkit.autopsy.datamodel.RecentFilesFilterNode; -import org.sleuthkit.autopsy.datamodel.RecentFilesNode; -import org.sleuthkit.autopsy.datamodel.SearchFiltersNode; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.File; -import org.sleuthkit.datamodel.TskException; - - -/** - * This class wraps nodes as they are passed to the DataResult viewers. It - * defines the actions that the node should have. - */ -public class DataResultFilterNode extends FilterNode{ - - private ExplorerManager sourceEm; - private final DisplayableItemNodeVisitor> getActionsDIV; - private final DisplayableItemNodeVisitor getPreferredActionsDIV; - - - /** the constructor */ - public DataResultFilterNode(Node node, ExplorerManager em) { - super(node, new DataResultFilterChildren(node, em)); - this.sourceEm = em; - getActionsDIV = new GetPopupActionsDisplayableItemNodeVisitor(); - getPreferredActionsDIV = new GetPreferredActionsDisplayableItemNodeVisitor(); - } - - - /** - * Right click action for the nodes that we want to pass to the directory - * table and the output view. - * - * @param popup - * @return actions - */ - @Override - public Action[] getActions(boolean popup) { - - List actions = new ArrayList(); - - final DisplayableItemNode originalNode = (DisplayableItemNode) this.getOriginal(); - actions.addAll(originalNode.accept(getActionsDIV)); - - //actions.add(new IndexContentFilesAction(nodeContent, "Index")); - - return actions.toArray(new Action[actions.size()]); - } - - - /** - * Double click action for the nodes that we want to pass to the directory - * table and the output view. - * - * @return action - */ - @Override - public Action getPreferredAction() { - // double click action(s) for volume node or directory node - - final DisplayableItemNode originalNode; - originalNode = (DisplayableItemNode) this.getOriginal(); - - return originalNode.accept(getPreferredActionsDIV); - } - - @Override - public Node.PropertySet[] getPropertySets() { - Node.PropertySet[] propertySets = super.getPropertySets(); - - for (int i = 0; i < propertySets.length; i++) { - Node.PropertySet ps = propertySets[i]; - - if (ps.getName().equals(Sheet.PROPERTIES)) { - Sheet.Set newPs = new Sheet.Set(); - newPs.setName(ps.getName()); - newPs.setDisplayName(ps.getDisplayName()); - newPs.setShortDescription(ps.getShortDescription()); - - newPs.put(ps.getProperties()); - if(newPs.remove(AbstractFsContentNode.HIDE_PARENT) != null) - newPs.remove(FsContentPropertyType.LOCATION.toString() ); - propertySets[i] = newPs; - } - } - - return propertySets; - } - - private class GetPopupActionsDisplayableItemNodeVisitor extends DisplayableItemNodeVisitor.Default> { - - @Override - public List visit(ImageNode img) { - List actions = new ArrayList(); - actions.add(new NewWindowViewAction("View in New Window", img)); - actions.add(new FileSearchAction("Open File Search")); - actions.addAll(ShowDetailActionVisitor.getActions(img.getLookup().lookup(Content.class))); - return actions; - } - - @Override - public List visit(VolumeNode vol) { - List actions = new ArrayList(); - actions.add(new NewWindowViewAction("View in New Window", vol)); - actions.addAll(ShowDetailActionVisitor.getActions(vol.getLookup().lookup(Content.class))); - - return actions; - } - - @Override - public List visit(DirectoryNode dir) { - List actions = new ArrayList(); - if(!dir.getDirectoryBrowseMode()) { - actions.add(new ViewContextAction("View File in Directory", dir)); - actions.add(null); // creates a menu separator - } - actions.add(new NewWindowViewAction("View in New Window", dir)); - actions.add(null); // creates a menu separator - actions.add(new ExtractAction("Extract Directory", dir)); - return actions; - } - - @Override - public List visit(FileNode f) { - List actions = new ArrayList(); - if(!f.getDirectoryBrowseMode()) { - actions.add(new ViewContextAction("View File in Directory", f)); - actions.add(null); // creates a menu separator - } - actions.add(new NewWindowViewAction("View in New Window", f)); - actions.add(new ExternalViewerAction("Open in External Viewer", f)); - actions.add(null); // creates a menu separator - actions.add(new ExtractAction("Extract File", f)); - return actions; - } - - @Override - public List visit(BlackboardArtifactNode ban) { - List actions = new ArrayList(); - BlackboardArtifact ba = ban.getLookup().lookup(BlackboardArtifact.class); - if(ba.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() - || ba.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { - actions.add(new ViewContextAction("View File in Directory", ban)); - } else { - Content c = findLinked(ban); - if (c != null) { - actions.add(new ViewContextAction("View File in Directory", c)); - } - actions.add(new ViewContextAction("View Source File in Directory", ban)); - } - File f = ban.getLookup().lookup(File.class); - if(f != null) { - actions.add(null); // creates a menu separator - actions.add(new NewWindowViewAction("View in New Window", new FileNode(f))); - actions.add(new ExternalViewerAction("Open in External Viewer", new FileNode(f))); - actions.add(null); // creates a menu separator - actions.add(new ExtractAction("Extract File", new FileNode(f))); - } - return actions; - } - - @Override - protected List defaultVisit(DisplayableItemNode ditem) { - return new ArrayList(); - } - - private Content findLinked(BlackboardArtifactNode ba) { - BlackboardArtifact art = ba.getLookup().lookup(BlackboardArtifact.class); - Content c = null; - try { - for(BlackboardAttribute attr : art.getAttributes()) { - if(attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID()) { - switch(attr.getValueType()) { - case INTEGER: - int i = attr.getValueInt(); - if(i != -1) - c = art.getSleuthkitCase().getContentById(i); - break; - case LONG: - long l = attr.getValueLong(); - if(l != -1) - c = art.getSleuthkitCase().getContentById(l); - break; - } - } - } - } catch(TskException ex) { - Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Error getting linked file", ex); - } - return c; - } - - } - - private class GetPreferredActionsDisplayableItemNodeVisitor extends DisplayableItemNodeVisitor.Default{ - - @Override - public AbstractAction visit(ImageNode in){ - return openChild(in); - } - - @Override - public AbstractAction visit(VolumeNode vn){ - return openChild(vn); - } - - @Override - public AbstractAction visit(ExtractedContentNode ecn) { - return openChild(ecn); - } - - @Override - public AbstractAction visit(KeywordHitsRootNode khrn) { - return openChild(khrn); - } - - @Override - public AbstractAction visit(HashsetHitsRootNode hhrn) { - return openChild(hhrn); - } - - @Override - public AbstractAction visit(HashsetHitsSetNode hhsn) { - return openChild(hhsn); - } - - @Override - public AbstractAction visit(EmailExtractedRootNode eern) { - return openChild(eern); - } - - @Override - public AbstractAction visit(EmailExtractedAccountNode eean) { - return openChild(eean); - } - - @Override - public AbstractAction visit(EmailExtractedFolderNode eefn) { - return openChild(eefn); - } - - @Override - public AbstractAction visit(RecentFilesNode rfn) { - return openChild(rfn); - } - - @Override - public AbstractAction visit(BlackboardArtifactNode ban){ - return new ViewContextAction("View in Directory", ban); - } - - @Override - public AbstractAction visit(ArtifactTypeNode atn){ - return openChild(atn); - } - - @Override - public AbstractAction visit(DirectoryNode dn){ - if(dn.getDisplayName().equals(DirectoryNode.DOTDOTDIR)) - return openParent(dn); - else if(!dn.getDisplayName().equals(DirectoryNode.DOTDIR)) - return openChild(dn); - else - return null; - } - - @Override - public AbstractAction visit(FileSearchFilterNode fsfn){ - return openChild(fsfn); - } - - @Override - public AbstractAction visit(SearchFiltersNode sfn) { - return openChild(sfn); - } - - @Override - public AbstractAction visit(RecentFilesFilterNode rffn) { - return openChild(rffn); - } - - @Override - public AbstractAction visit(KeywordHitsListNode khsn) { - return openChild(khsn); - } - - @Override - public AbstractAction visit(KeywordHitsKeywordNode khmln) { - return openChild(khmln); - } - - - - @Override - protected AbstractAction defaultVisit(DisplayableItemNode c) { - return null; - } - - private AbstractAction openChild(AbstractNode node) { - final Node[] parentNode = sourceEm.getSelectedNodes(); - final Node parentContext = parentNode[0]; - final Node original = node; - - return new AbstractAction() { - - @Override - public void actionPerformed(ActionEvent e) { - if (parentContext != null) { - for (int i = 0; i < parentContext.getChildren().getNodesCount(); i++) { - Node selectedNode = parentContext.getChildren().getNodeAt(i); - if (selectedNode != null && selectedNode.getName().equals(original.getName())) { - try { - sourceEm.setExploredContextAndSelection(selectedNode, new Node[]{selectedNode}); - } catch (PropertyVetoException ex) { - // throw an error here - Logger logger = Logger.getLogger(DataResultFilterNode.class.getName()); - logger.log(Level.WARNING, "Error: can't open the selected directory.", ex); - } - } - } - } - } - }; - } - - private AbstractAction openParent(AbstractNode node) { - Node[] selectedNode = sourceEm.getSelectedNodes(); - Node selectedContext = selectedNode[0]; - final Node parentNode = selectedContext.getParentNode(); - - return new AbstractAction() { - - @Override - public void actionPerformed(ActionEvent e) { - try { - sourceEm.setSelectedNodes(new Node[]{parentNode}); - } catch (PropertyVetoException ex) { - Logger logger = Logger.getLogger(DataResultFilterNode.class.getName()); - logger.log(Level.WARNING, "Error: can't open the parent directory.", ex); - } - } - }; - } - } +/* + * Autopsy Forensic Browser + * + * Copyright 2011 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.directorytree; + +import java.awt.event.ActionEvent; +import java.beans.PropertyVetoException; +import java.util.ArrayList; +import java.util.List; +import org.sleuthkit.autopsy.datamodel.VolumeNode; +import org.sleuthkit.autopsy.datamodel.DirectoryNode; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.AbstractAction; +import javax.swing.Action; +import org.openide.explorer.ExplorerManager; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.FilterNode; +import org.openide.nodes.Node; +import org.openide.nodes.Sheet; +import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode; +import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode.FsContentPropertyType; +import org.sleuthkit.autopsy.datamodel.ArtifactTypeNode; +import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; +import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; +import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; +import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedAccountNode; +import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedFolderNode; +import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedRootNode; +import org.sleuthkit.autopsy.datamodel.ExtractedContentNode; +import org.sleuthkit.autopsy.datamodel.FileNode; +import org.sleuthkit.autopsy.datamodel.FileSearchFilterNode; +import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsRootNode; +import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsSetNode; +import org.sleuthkit.autopsy.datamodel.ImageNode; +import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsKeywordNode; +import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsListNode; +import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode; +import org.sleuthkit.autopsy.datamodel.RecentFilesFilterNode; +import org.sleuthkit.autopsy.datamodel.RecentFilesNode; +import org.sleuthkit.autopsy.datamodel.SearchFiltersNode; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.File; +import org.sleuthkit.datamodel.TskException; + + +/** + * This class wraps nodes as they are passed to the DataResult viewers. It + * defines the actions that the node should have. + */ +public class DataResultFilterNode extends FilterNode{ + + private ExplorerManager sourceEm; + private final DisplayableItemNodeVisitor> getActionsDIV; + private final DisplayableItemNodeVisitor getPreferredActionsDIV; + + + /** the constructor */ + public DataResultFilterNode(Node node, ExplorerManager em) { + super(node, new DataResultFilterChildren(node, em)); + this.sourceEm = em; + getActionsDIV = new GetPopupActionsDisplayableItemNodeVisitor(); + getPreferredActionsDIV = new GetPreferredActionsDisplayableItemNodeVisitor(); + } + + + /** + * Right click action for the nodes that we want to pass to the directory + * table and the output view. + * + * @param popup + * @return actions + */ + @Override + public Action[] getActions(boolean popup) { + + List actions = new ArrayList(); + + final DisplayableItemNode originalNode = (DisplayableItemNode) this.getOriginal(); + actions.addAll(originalNode.accept(getActionsDIV)); + + //actions.add(new IndexContentFilesAction(nodeContent, "Index")); + + return actions.toArray(new Action[actions.size()]); + } + + + /** + * Double click action for the nodes that we want to pass to the directory + * table and the output view. + * + * @return action + */ + @Override + public Action getPreferredAction() { + // double click action(s) for volume node or directory node + + final DisplayableItemNode originalNode; + originalNode = (DisplayableItemNode) this.getOriginal(); + + return originalNode.accept(getPreferredActionsDIV); + } + + @Override + public Node.PropertySet[] getPropertySets() { + Node.PropertySet[] propertySets = super.getPropertySets(); + + for (int i = 0; i < propertySets.length; i++) { + Node.PropertySet ps = propertySets[i]; + + if (ps.getName().equals(Sheet.PROPERTIES)) { + Sheet.Set newPs = new Sheet.Set(); + newPs.setName(ps.getName()); + newPs.setDisplayName(ps.getDisplayName()); + newPs.setShortDescription(ps.getShortDescription()); + + newPs.put(ps.getProperties()); + if(newPs.remove(AbstractFsContentNode.HIDE_PARENT) != null) + newPs.remove(FsContentPropertyType.LOCATION.toString() ); + propertySets[i] = newPs; + } + } + + return propertySets; + } + + private class GetPopupActionsDisplayableItemNodeVisitor extends DisplayableItemNodeVisitor.Default> { + + @Override + public List visit(ImageNode img) { + List actions = new ArrayList(); + actions.add(new NewWindowViewAction("View in New Window", img)); + actions.add(new FileSearchAction("Open File Search")); + actions.addAll(ShowDetailActionVisitor.getActions(img.getLookup().lookup(Content.class))); + return actions; + } + + @Override + public List visit(VolumeNode vol) { + List actions = new ArrayList(); + actions.add(new NewWindowViewAction("View in New Window", vol)); + actions.addAll(ShowDetailActionVisitor.getActions(vol.getLookup().lookup(Content.class))); + + return actions; + } + + @Override + public List visit(DirectoryNode dir) { + List actions = new ArrayList(); + if(!dir.getDirectoryBrowseMode()) { + actions.add(new ViewContextAction("View File in Directory", dir)); + actions.add(null); // creates a menu separator + } + actions.add(new NewWindowViewAction("View in New Window", dir)); + actions.add(null); // creates a menu separator + actions.add(new ExtractAction("Extract Directory", dir)); + return actions; + } + + @Override + public List visit(FileNode f) { + List actions = new ArrayList(); + if(!f.getDirectoryBrowseMode()) { + actions.add(new ViewContextAction("View File in Directory", f)); + actions.add(null); // creates a menu separator + } + actions.add(new NewWindowViewAction("View in New Window", f)); + actions.add(new ExternalViewerAction("Open in External Viewer", f)); + actions.add(null); // creates a menu separator + actions.add(new ExtractAction("Extract File", f)); + actions.add(new HashSearchAction("Search for similar MD5", f)); + return actions; + } + + @Override + public List visit(BlackboardArtifactNode ban) { + List actions = new ArrayList(); + BlackboardArtifact ba = ban.getLookup().lookup(BlackboardArtifact.class); + if(ba.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + || ba.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { + actions.add(new ViewContextAction("View File in Directory", ban)); + } else { + Content c = findLinked(ban); + if (c != null) { + actions.add(new ViewContextAction("View File in Directory", c)); + } + actions.add(new ViewContextAction("View Source File in Directory", ban)); + } + File f = ban.getLookup().lookup(File.class); + if(f != null) { + actions.add(null); // creates a menu separator + actions.add(new NewWindowViewAction("View in New Window", new FileNode(f))); + actions.add(new ExternalViewerAction("Open in External Viewer", new FileNode(f))); + actions.add(null); // creates a menu separator + actions.add(new ExtractAction("Extract File", new FileNode(f))); + actions.add(new HashSearchAction("Search for similar MD5", new FileNode(f))); + } + return actions; + } + + @Override + protected List defaultVisit(DisplayableItemNode ditem) { + return new ArrayList(); + } + + private Content findLinked(BlackboardArtifactNode ba) { + BlackboardArtifact art = ba.getLookup().lookup(BlackboardArtifact.class); + Content c = null; + try { + for(BlackboardAttribute attr : art.getAttributes()) { + if(attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID()) { + switch(attr.getValueType()) { + case INTEGER: + int i = attr.getValueInt(); + if(i != -1) + c = art.getSleuthkitCase().getContentById(i); + break; + case LONG: + long l = attr.getValueLong(); + if(l != -1) + c = art.getSleuthkitCase().getContentById(l); + break; + } + } + } + } catch(TskException ex) { + Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Error getting linked file", ex); + } + return c; + } + + } + + private class GetPreferredActionsDisplayableItemNodeVisitor extends DisplayableItemNodeVisitor.Default{ + + @Override + public AbstractAction visit(ImageNode in){ + return openChild(in); + } + + @Override + public AbstractAction visit(VolumeNode vn){ + return openChild(vn); + } + + @Override + public AbstractAction visit(ExtractedContentNode ecn) { + return openChild(ecn); + } + + @Override + public AbstractAction visit(KeywordHitsRootNode khrn) { + return openChild(khrn); + } + + @Override + public AbstractAction visit(HashsetHitsRootNode hhrn) { + return openChild(hhrn); + } + + @Override + public AbstractAction visit(HashsetHitsSetNode hhsn) { + return openChild(hhsn); + } + + @Override + public AbstractAction visit(EmailExtractedRootNode eern) { + return openChild(eern); + } + + @Override + public AbstractAction visit(EmailExtractedAccountNode eean) { + return openChild(eean); + } + + @Override + public AbstractAction visit(EmailExtractedFolderNode eefn) { + return openChild(eefn); + } + + @Override + public AbstractAction visit(RecentFilesNode rfn) { + return openChild(rfn); + } + + @Override + public AbstractAction visit(BlackboardArtifactNode ban){ + return new ViewContextAction("View in Directory", ban); + } + + @Override + public AbstractAction visit(ArtifactTypeNode atn){ + return openChild(atn); + } + + @Override + public AbstractAction visit(DirectoryNode dn){ + if(dn.getDisplayName().equals(DirectoryNode.DOTDOTDIR)) + return openParent(dn); + else if(!dn.getDisplayName().equals(DirectoryNode.DOTDIR)) + return openChild(dn); + else + return null; + } + + @Override + public AbstractAction visit(FileSearchFilterNode fsfn){ + return openChild(fsfn); + } + + @Override + public AbstractAction visit(SearchFiltersNode sfn) { + return openChild(sfn); + } + + @Override + public AbstractAction visit(RecentFilesFilterNode rffn) { + return openChild(rffn); + } + + @Override + public AbstractAction visit(KeywordHitsListNode khsn) { + return openChild(khsn); + } + + @Override + public AbstractAction visit(KeywordHitsKeywordNode khmln) { + return openChild(khmln); + } + + + + @Override + protected AbstractAction defaultVisit(DisplayableItemNode c) { + return null; + } + + private AbstractAction openChild(AbstractNode node) { + final Node[] parentNode = sourceEm.getSelectedNodes(); + final Node parentContext = parentNode[0]; + final Node original = node; + + return new AbstractAction() { + + @Override + public void actionPerformed(ActionEvent e) { + if (parentContext != null) { + for (int i = 0; i < parentContext.getChildren().getNodesCount(); i++) { + Node selectedNode = parentContext.getChildren().getNodeAt(i); + if (selectedNode != null && selectedNode.getName().equals(original.getName())) { + try { + sourceEm.setExploredContextAndSelection(selectedNode, new Node[]{selectedNode}); + } catch (PropertyVetoException ex) { + // throw an error here + Logger logger = Logger.getLogger(DataResultFilterNode.class.getName()); + logger.log(Level.WARNING, "Error: can't open the selected directory.", ex); + } + } + } + } + } + }; + } + + private AbstractAction openParent(AbstractNode node) { + Node[] selectedNode = sourceEm.getSelectedNodes(); + Node selectedContext = selectedNode[0]; + final Node parentNode = selectedContext.getParentNode(); + + return new AbstractAction() { + + @Override + public void actionPerformed(ActionEvent e) { + try { + sourceEm.setSelectedNodes(new Node[]{parentNode}); + } catch (PropertyVetoException ex) { + Logger logger = Logger.getLogger(DataResultFilterNode.class.getName()); + logger.log(Level.WARNING, "Error: can't open the parent directory.", ex); + } + } + }; + } + } } \ No newline at end of file diff --git a/DirectoryTree/src/org/sleuthkit/autopsy/directorytree/HashSearchAction.java b/DirectoryTree/src/org/sleuthkit/autopsy/directorytree/HashSearchAction.java new file mode 100644 index 0000000000..1e5078f11b --- /dev/null +++ b/DirectoryTree/src/org/sleuthkit/autopsy/directorytree/HashSearchAction.java @@ -0,0 +1,43 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 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.directorytree; + +import java.awt.event.ActionEvent; +import javax.swing.AbstractAction; +import org.openide.nodes.Node; +import org.openide.util.Lookup; + +/** + * Action to lookup the interface and call the real action in HashDatabase. + */ +public class HashSearchAction extends AbstractAction { + Node contentNode; + + public HashSearchAction(String title, Node contentNode) { + super(title); + this.contentNode = contentNode; + } + + @Override + public void actionPerformed(ActionEvent e) { + HashSearchProvider searcher = Lookup.getDefault().lookup(HashSearchProvider.class); + searcher.search(contentNode); + } + +} diff --git a/DirectoryTree/src/org/sleuthkit/autopsy/directorytree/HashSearchProvider.java b/DirectoryTree/src/org/sleuthkit/autopsy/directorytree/HashSearchProvider.java new file mode 100644 index 0000000000..ea868f4b46 --- /dev/null +++ b/DirectoryTree/src/org/sleuthkit/autopsy/directorytree/HashSearchProvider.java @@ -0,0 +1,28 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 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.directorytree; + +import org.openide.nodes.Node; + +/** + * Lookup interface for Hash Search (to deal with circular deps) + */ +public interface HashSearchProvider { + public void search(Node contentNode); +} diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchManager.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchManager.java index 5ae58ce905..eb137278a5 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchManager.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchManager.java @@ -29,8 +29,6 @@ import org.openide.nodes.Node; import org.openide.windows.TopComponent; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode; -import org.sleuthkit.autopsy.datamodel.KeyValue; -import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.FsContent; /** @@ -41,7 +39,7 @@ public class HashDbSearchManager { Map> map; List keyValues; - HashDbSearchManager(Map> map) { + public HashDbSearchManager(Map> map) { this.map = map; init(); } @@ -87,16 +85,3 @@ public class HashDbSearchManager { searchResultWin.requestActive(); } } - -class KeyValueContent extends KeyValue { - Content content; - - KeyValueContent(String name, Map map, int id, Content content) { - super(name, map, id); - this.content = content; - } - - Content getContent() { - return content; - } -} diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java index ad1cae6a4e..ac79cc3f92 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java @@ -295,7 +295,7 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe } else { errorField.setText("Error: Not all files have been hashed."); errorField.setVisible(true); - return false; + return false; } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchResultFactory.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchResultFactory.java index 19f0f6ebaa..386bbeba99 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchResultFactory.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchResultFactory.java @@ -30,7 +30,7 @@ import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.FsContent; /** - * Creates a Node for each KeyValue. + * Creates a Node for each KeyValueContent. */ public class HashDbSearchResultFactory extends ChildFactory { Collection keyValues; @@ -50,6 +50,6 @@ public class HashDbSearchResultFactory extends ChildFactory { @Override protected Node createNodeForKey(KeyValueContent thing) { final Content content = thing.getContent(); - return new KeyValueNode(thing, Children.LEAF, Lookups.singleton(content)); + return new KeyValueFileNode(thing, Children.LEAF); } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearcher.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearcher.java index 057056f11d..f6c0d0e597 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearcher.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearcher.java @@ -19,7 +19,7 @@ package org.sleuthkit.autopsy.hashdatabase; import java.util.ArrayList; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.logging.Logger; @@ -52,7 +52,7 @@ public class HashDbSearcher { * @return a Map of md5 hashes mapped to the list of files hit */ static Map> findFilesBymd5(List md5Hash) { - Map> map = new HashMap>(); + Map> map = new LinkedHashMap>(); for(String md5 : md5Hash) { List files = findFilesByMd5(md5); if(!files.isEmpty()) { diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSearchAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSearchAction.java new file mode 100644 index 0000000000..fb21c95b4a --- /dev/null +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSearchAction.java @@ -0,0 +1,119 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 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.hashdatabase; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; +import org.openide.nodes.Node; +import org.openide.util.HelpCtx; +import org.openide.util.actions.CallableSystemAction; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.datamodel.ContentUtils; +import org.sleuthkit.autopsy.directorytree.HashSearchProvider; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.ContentVisitor; +import org.sleuthkit.datamodel.Directory; +import org.sleuthkit.datamodel.FsContent; +import org.sleuthkit.datamodel.SleuthkitCase; + +/** + * Searches based on file MD5 hash + */ +public class HashSearchAction extends CallableSystemAction implements HashSearchProvider { + + private static final InitializeContentVisitor initializeCV = new InitializeContentVisitor(); + private FsContent fsContent; + private Logger logger = Logger.getLogger(HashSearchAction.class.getName()); + private Case currentCase = Case.getCurrentCase(); + private SleuthkitCase skCase = currentCase.getSleuthkitCase(); + + private static HashSearchAction instance = null; + + HashSearchAction() { + super(); + } + + public static HashSearchAction getDefault() { + if(instance == null){ + instance = new HashSearchAction(); + } + return instance; + } + + @Override + public void search(Node contentNode) { + Content tempContent = contentNode.getLookup().lookup(Content.class); + this.fsContent = tempContent.accept(initializeCV); + doAction(); + } + + /** + * Returns the FsContent if it is supported, otherwise null + */ + private static class InitializeContentVisitor extends ContentVisitor.Default { + + @Override + public FsContent visit(org.sleuthkit.datamodel.File f) { + return f; + } + + @Override + public FsContent visit(Directory dir) { + return ContentUtils.isDotDirectory(dir) ? null : dir; + } + + @Override + protected FsContent defaultVisit(Content cntnt) { + return null; + } + } + + public void doAction() { + performAction(); + } + + /** + * Find all files with the selected file's MD5 hash and display them + * as nodes. + */ + @Override + public void performAction() { + // Make sure all files have an md5 hash + if(skCase.md5HashFinished()) { + // Get the map of hashes to FsContent and send it to the manager + List files = skCase.findFilesByMd5(fsContent.getMd5Hash()); + Map> map = new LinkedHashMap>(); + map.put(fsContent.getMd5Hash(), files); + HashDbSearchManager man = new HashDbSearchManager(map); + man.execute(); + } + } + + @Override + public String getName() { + return "Hash Search"; + } + + @Override + public HelpCtx getHelpCtx() { + return HelpCtx.DEFAULT_HELP; + } +} diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/KeyValueContent.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/KeyValueContent.java new file mode 100644 index 0000000000..696c54e371 --- /dev/null +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/KeyValueContent.java @@ -0,0 +1,39 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 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.hashdatabase; + +import java.util.Map; +import org.sleuthkit.autopsy.datamodel.KeyValue; +import org.sleuthkit.datamodel.Content; + +/** + * A KeyValue mapping where specific content needs to be recognizable. + */ +public class KeyValueContent extends KeyValue { + Content content; + + KeyValueContent(String name, Map map, int id, Content content) { + super(name, map, id); + this.content = content; + } + + Content getContent() { + return content; + } +} diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/KeyValueFileNode.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/KeyValueFileNode.java new file mode 100644 index 0000000000..cc33e8962d --- /dev/null +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/KeyValueFileNode.java @@ -0,0 +1,93 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.hashdatabase; + +import java.util.ArrayList; +import java.util.List; +import javax.swing.Action; +import org.openide.nodes.Children; +import org.openide.util.Lookup; +import org.openide.util.lookup.Lookups; +import org.sleuthkit.autopsy.datamodel.DirectoryNode; +import org.sleuthkit.autopsy.datamodel.FileNode; +import org.sleuthkit.autopsy.datamodel.KeyValue; +import org.sleuthkit.autopsy.datamodel.KeyValueNode; +import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; +import org.sleuthkit.autopsy.directorytree.ExtractAction; +import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.ContentVisitor; +import org.sleuthkit.datamodel.Directory; +import org.sleuthkit.datamodel.File; + +/** + * Node for KeyValueContent, allowing right click actions to be set. + */ +public class KeyValueFileNode extends KeyValueNode { + + KeyValue thing; + Content content; + + public KeyValueFileNode(KeyValueContent thing, Children children) { + super(thing, children, Lookups.singleton(thing)); + this.setName(thing.getName()); + this.thing = thing; + this.content = thing.getContent(); + } + + public KeyValueFileNode(KeyValueContent thing, Children children, Lookup lookup) { + super(thing, children, lookup); + this.setName(thing.getName()); + this.thing = thing; + this.content = thing.getContent(); + } + + /** + * Right click action for the nodes that we want to pass to the directory + * table and the output view. + * + * @param popup + * @return actions + */ + @Override + public Action[] getActions(boolean popup) { + + List actions = new ArrayList(); + + actions.addAll(content.accept(new KeyValueFileNode.GetPopupActionsContentVisitor())); + + return actions.toArray(new Action[actions.size()]); + } + + private class GetPopupActionsContentVisitor extends ContentVisitor.Default> { + + @Override + public List visit(File f) { + List actions = new ArrayList(); + actions.add(new NewWindowViewAction("View in New Window", new FileNode(f))); + actions.add(new ExternalViewerAction("Open in External Viewer", new FileNode(f))); + actions.add(null); // creates a menu separator + actions.add(new ExtractAction("Extract File", new FileNode(f))); + actions.add(new org.sleuthkit.autopsy.directorytree.HashSearchAction("Search for similar MD5", new FileNode(f))); + return actions; + } + + @Override + public List visit(Directory f) { + List actions = new ArrayList(); + actions.add(new NewWindowViewAction("View in New Window", new DirectoryNode(f))); + actions.add(new ExternalViewerAction("Open in External Viewer", new DirectoryNode(f))); + actions.add(null); // creates a menu separator + actions.add(new ExtractAction("Extract File", new DirectoryNode(f))); + actions.add(new org.sleuthkit.autopsy.directorytree.HashSearchAction("Search for similar MD5", new DirectoryNode(f))); + return actions; + } + + @Override + protected List defaultVisit(Content c) { + return new ArrayList(); + } + } +} \ No newline at end of file diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/layer.xml b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/layer.xml index c57d69edf0..fa2c1971fd 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/layer.xml +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/layer.xml @@ -9,6 +9,13 @@ + + + + + + +