/* * 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. */ /* * HashDbMgmtPanel.java * * Created on May 7, 2012, 9:53:42 AM */ package org.sleuthkit.autopsy.hashdatabase; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.AbstractCellEditor; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import org.sleuthkit.autopsy.hashdatabase.HashDb.DBType; import org.sleuthkit.datamodel.SleuthkitJNI; import org.sleuthkit.datamodel.TskException; /** * * @author dfickling */ public class HashDbMgmtPanel extends javax.swing.JPanel { private static final Logger logger = Logger.getLogger(HashDbMgmtPanel.class.getName()); private HashSetTableModel notableTableModel; private HashSetTableModel nsrlTableModel; private JFileChooser fc = new JFileChooser(); private static HashDbMgmtPanel instance; /** Creates new form HashDbMgmtPanel */ private HashDbMgmtPanel() { notableTableModel = new HashSetTableModel(); nsrlTableModel = new HashSetTableModel(); initComponents(); customizeComponents(); } public static HashDbMgmtPanel getDefault() { if(instance == null) { instance = new HashDbMgmtPanel(); } return instance; } private void customizeComponents() { notableHashSetTable.setModel(notableTableModel); notableHashSetTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); notableHashSetTable.setRowHeight(25); notableTableModel.resync(DBType.NOTABLE); nsrlHashSetTable.setModel(nsrlTableModel); nsrlHashSetTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); nsrlHashSetTable.setRowHeight(25); nsrlTableModel.resync(DBType.NSRL); fc.setDragEnabled(false); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); String[] EXTENSION = new String[] { "txt", "idx", "hash", "Hash" }; FileNameExtensionFilter filter = new FileNameExtensionFilter( "Hash Database File", EXTENSION); fc.setFileFilter(filter); fc.setMultiSelectionEnabled(false); final int width1 = jScrollPane1.getPreferredSize().width; TableColumn column1 = null; for (int i = 0; i < notableHashSetTable.getColumnCount(); i++) { column1 = notableHashSetTable.getColumnModel().getColumn(i); if (i == 2) { ButtonRenderer br = new ButtonRenderer(); br.getTheButton().addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int row = notableHashSetTable.getSelectedRow(); try { notableTableModel.getHashSetAt(row).createIndex(); } catch (TskException ex) { logger.log(Level.WARNING, "Error creating index", ex); } notableTableModel.resync(DBType.NOTABLE); } }); column1.setCellRenderer(br); column1.setCellEditor(br); } if (i == 3) { column1.setCellRenderer(new CheckBoxRenderer()); } } final int width2 = jScrollPane2.getPreferredSize().width; TableColumn column2 = null; for (int i = 0; i < nsrlHashSetTable.getColumnCount(); i++) { column2 = nsrlHashSetTable.getColumnModel().getColumn(i); if (i == 2) { ButtonRenderer br = new ButtonRenderer(); br.getTheButton().addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int row = nsrlHashSetTable.getSelectedRow(); try { nsrlTableModel.getHashSetAt(row).createIndex(); } catch (TskException ex) { logger.log(Level.WARNING, "Error creating index", ex); } nsrlTableModel.resync(DBType.NSRL); } }); column2.setCellRenderer(br); column2.setCellEditor(br); } if (i == 3) { column2.setCellRenderer(new CheckBoxRenderer()); } } } /** * Checks if indexes exist for all defined databases * @return true if Sleuth Kit can open the indexes of all databases * than have been selected */ boolean indexesExist() { return notableTableModel.indexesExist() && nsrlTableModel.indexesExist(); } /** * Save the table settings * @return whether save was successful */ boolean save() { notableTableModel.saveAll(); nsrlTableModel.saveAll(); return true; } /** 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(); notableHashSetTable = new javax.swing.JTable(); addNSRLButton = new javax.swing.JButton(); removeNSRLButton = new javax.swing.JButton(); jScrollPane2 = new javax.swing.JScrollPane(); nsrlHashSetTable = new javax.swing.JTable(); addNotableButton = new javax.swing.JButton(); removeNotableButton = new javax.swing.JButton(); jScrollPane1.setViewportView(notableHashSetTable); addNSRLButton.setText(org.openide.util.NbBundle.getMessage(HashDbMgmtPanel.class, "HashDbMgmtPanel.addNSRLButton.text")); // NOI18N addNSRLButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { addNSRLButtonActionPerformed(evt); } }); removeNSRLButton.setText(org.openide.util.NbBundle.getMessage(HashDbMgmtPanel.class, "HashDbMgmtPanel.removeNSRLButton.text")); // NOI18N removeNSRLButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { removeNSRLButtonActionPerformed(evt); } }); nsrlHashSetTable.setModel(new javax.swing.table.DefaultTableModel( new Object [][] { }, new String [] { } )); jScrollPane2.setViewportView(nsrlHashSetTable); addNotableButton.setText(org.openide.util.NbBundle.getMessage(HashDbMgmtPanel.class, "HashDbMgmtPanel.addNotableButton.text")); // NOI18N addNotableButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { addNotableButtonActionPerformed(evt); } }); removeNotableButton.setText(org.openide.util.NbBundle.getMessage(HashDbMgmtPanel.class, "HashDbMgmtPanel.removeNotableButton.text")); // NOI18N removeNotableButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { removeNotableButtonActionPerformed(evt); } }); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(addNSRLButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 235, Short.MAX_VALUE) .addComponent(removeNSRLButton) .addContainerGap()) .addComponent(jScrollPane1, 0, 0, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(addNotableButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 223, Short.MAX_VALUE) .addComponent(removeNotableButton) .addContainerGap()) .addComponent(jScrollPane2, 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 203, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(addNotableButton) .addComponent(removeNotableButton)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 186, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(addNSRLButton) .addComponent(removeNSRLButton)) .addContainerGap()) ); }// //GEN-END:initComponents private void addNSRLButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addNSRLButtonActionPerformed save(); int retval = fc.showOpenDialog(this); if(retval == JFileChooser.APPROVE_OPTION) { File f = fc.getSelectedFile(); try { String filePath = f.getCanonicalPath(); if (HashDb.isIndexPath(filePath)) { filePath = HashDb.toDatabasePath(filePath); } String derivedName; try { derivedName = SleuthkitJNI.getDatabaseName(filePath); } catch (TskException ex) { derivedName = ""; } String setName = (String) JOptionPane.showInputDialog(this, "New Hash Set name:", "New Hash Set", JOptionPane.PLAIN_MESSAGE, null, null, derivedName); nsrlTableModel.newSet(setName, Arrays.asList(new String[] {filePath}), true, HashDb.DBType.NSRL); // TODO: support multiple file paths } catch (IOException ex) { logger.log(Level.WARNING, "Couldn't get selected file path.", ex); } } }//GEN-LAST:event_addNSRLButtonActionPerformed private void addNotableButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addNotableButtonActionPerformed save(); int retval = fc.showOpenDialog(this); if(retval == JFileChooser.APPROVE_OPTION) { File f = fc.getSelectedFile(); try { String filePath = f.getCanonicalPath(); if (HashDb.isIndexPath(filePath)) { filePath = HashDb.toDatabasePath(filePath); } String derivedName; try { derivedName = SleuthkitJNI.getDatabaseName(filePath); } catch (TskException ex) { derivedName = ""; } String setName = (String) JOptionPane.showInputDialog(this, "New Hash Set name:", "New Hash Set", JOptionPane.PLAIN_MESSAGE, null, null, derivedName); if(setName != null && !setName.equals("")) notableTableModel.newSet(setName, Arrays.asList(new String[] {filePath}), true, HashDb.DBType.NOTABLE); // TODO: support multiple file paths } catch (IOException ex) { logger.log(Level.WARNING, "Couldn't get selected file path.", ex); } } }//GEN-LAST:event_addNotableButtonActionPerformed private void removeNotableButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeNotableButtonActionPerformed notableTableModel.removeSetAt(notableHashSetTable.getSelectedRow()); }//GEN-LAST:event_removeNotableButtonActionPerformed private void removeNSRLButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeNSRLButtonActionPerformed nsrlTableModel.removeSetAt(nsrlHashSetTable.getSelectedRow()); }//GEN-LAST:event_removeNSRLButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton addNSRLButton; private javax.swing.JButton addNotableButton; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JScrollPane jScrollPane2; private javax.swing.JTable notableHashSetTable; private javax.swing.JTable nsrlHashSetTable; private javax.swing.JButton removeNSRLButton; private javax.swing.JButton removeNotableButton; // End of variables declaration//GEN-END:variables private class HashSetTableModel extends AbstractTableModel { //data private HashDbXML xmlHandle = HashDbXML.getCurrent(); private List data = new ArrayList(); @Override public int getColumnCount() { return 4; } @Override public int getRowCount() { return data.size(); } @Override public String getColumnName(int column) { switch(column) { case 0: return "Name"; case 1: return "Location"; case 2: return "Status"; default: return "Use For Ingest"; } } @Override public Object getValueAt(int rowIndex, int columnIndex) { HashDb entry = data.get(rowIndex); switch(columnIndex) { case 0: return entry.getName(); case 1: return entry.getDatabasePaths().get(0); //TODO: support multiple paths case 2: return entry.status(); default: return entry.getUseForIngest(); } } @Override public boolean isCellEditable(int rowIndex, int columnIndex) { return columnIndex == 2 || columnIndex == 3; //(status or ingest) } @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { HashDb entry = data.get(rowIndex); switch(columnIndex) { case 0: entry.setName((String) aValue); break; case 1: entry.setDatabasePaths(Arrays.asList(new String[]{(String) aValue}));//TODO: support multiple paths break; case 2: break; case 3: entry.setUseForIngest((Boolean) aValue); } } @Override public Class getColumnClass(int c) { return getValueAt(0, c).getClass(); } void resync(DBType type) { data.clear(); data.addAll(xmlHandle.getSets(type)); fireTableDataChanged(); } void newSet(String name, List paths, boolean useForIngest, DBType type) { xmlHandle.addSet(new HashDb(name, type, paths, useForIngest)); resync(type); } void removeSetAt(int index) { HashDb db = data.get(index); xmlHandle.removeSet(db); resync(db.getType()); } void saveAll() { xmlHandle.putAll(data); } boolean indexesExist() { boolean ret = true; for(HashDb db : xmlHandle.getSets()) { ret = ret && db.databaseExists(); } return ret; } HashDb getHashSetAt(int row) { return data.get(row); } } private class CheckBoxRenderer extends JCheckBox implements TableCellRenderer { @Override public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { this.setHorizontalAlignment(JCheckBox.CENTER); this.setVerticalAlignment(JCheckBox.CENTER); Boolean selected = (Boolean) table.getModel().getValueAt(row, column); setSelected(selected); if (isSelected) { setBackground(notableHashSetTable.getSelectionBackground()); } else { setBackground(notableHashSetTable.getBackground()); } return this; } } private class ButtonRenderer extends AbstractCellEditor implements TableCellRenderer, TableCellEditor { private JButton theButton; private ButtonRenderer() { theButton = new JButton(); } JButton getTheButton() { return theButton; } void updateData( JTable table, boolean isSelected, int row, int column) { theButton.setHorizontalAlignment(JButton.CENTER); theButton.setVerticalAlignment(JButton.CENTER); IndexStatus selected = (IndexStatus) table.getModel().getValueAt(row, column); switch (selected) { case INDEX_OUTDATED: theButton.setText("Re-index"); theButton.setEnabled(true); break; case INDEX_CURRENT: theButton.setText("Re-index"); theButton.setEnabled(true); break; case NO_INDEX: theButton.setText("Index"); theButton.setEnabled(true); break; default: theButton.setText("No DB"); theButton.setEnabled(false); } if (isSelected) { theButton.setBackground(notableHashSetTable.getSelectionBackground()); } else { theButton.setBackground(notableHashSetTable.getBackground()); } } @Override public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { updateData(table, isSelected, row, column); return theButton; } @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { updateData(table, isSelected, row, column); return theButton; } @Override public Object getCellEditorValue() { return null; } } }