From 473a3a9925f360689a6fff71b11a43fc7a6a8a6c Mon Sep 17 00:00:00 2001 From: Dick Fickling Date: Thu, 10 May 2012 17:31:20 -0400 Subject: [PATCH] Further iteration on multiple hash databases. Not 100% tested (is that possible?), but stable enough and we need it to line up Autopsy with new Sleuthkit API. --- .../autopsy/casemodule/ButtonColumn.java | 10 +- .../AdvancedConfigurationDialog.java | 10 +- HashDatabase/nbproject/project.xml | 9 + .../autopsy/hashdatabase/Bundle.properties | 14 +- .../autopsy/hashdatabase/ButtonColumn.java | 227 +++++++++ .../autopsy/hashdatabase/HashDb.java | 85 +++- .../hashdatabase/HashDbIngestService.java | 142 +++--- .../hashdatabase/HashDbMgmtAction.java | 14 +- .../autopsy/hashdatabase/HashDbMgmtPanel.form | 164 ++++--- .../autopsy/hashdatabase/HashDbMgmtPanel.java | 452 +++++++++--------- .../hashdatabase/HashDbSimplePanel.form | 53 +- .../hashdatabase/HashDbSimplePanel.java | 82 ++-- .../autopsy/hashdatabase/HashDbXML.java | 98 ++-- .../autopsy/hashdatabase/IndexStatus.java | 10 +- 14 files changed, 901 insertions(+), 469 deletions(-) create mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ButtonColumn.java diff --git a/Case/src/org/sleuthkit/autopsy/casemodule/ButtonColumn.java b/Case/src/org/sleuthkit/autopsy/casemodule/ButtonColumn.java index 24f67b48f4..8494bbd25f 100644 --- a/Case/src/org/sleuthkit/autopsy/casemodule/ButtonColumn.java +++ b/Case/src/org/sleuthkit/autopsy/casemodule/ButtonColumn.java @@ -57,9 +57,9 @@ class ButtonColumn extends AbstractCellEditor private JButton editButton; private String text; private boolean isButtonColumnEditor; - - String buttonName; + String buttonName; + /** * Create the ButtonColumn to be used as a renderer and editor. The @@ -73,7 +73,7 @@ class ButtonColumn extends AbstractCellEditor */ ButtonColumn(JTable table, Action action, int column, String buttonName) { - this.table = table; + this.table = table; this.action = action; this.buttonName = buttonName; @@ -88,7 +88,7 @@ class ButtonColumn extends AbstractCellEditor columnModel.getColumn(column).setCellRenderer( this ); columnModel.getColumn(column).setCellEditor( this ); table.addMouseListener( this ); - } + } /** @@ -172,7 +172,7 @@ class ButtonColumn extends AbstractCellEditor } //renderButton.setText( (value == null) ? "" : value.toString() ); - renderButton.setText(buttonName); + renderButton.setText(buttonName); return renderButton; } diff --git a/CoreComponents/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationDialog.java b/CoreComponents/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationDialog.java index b347d6cdbf..2748d01551 100644 --- a/CoreComponents/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationDialog.java +++ b/CoreComponents/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationDialog.java @@ -39,8 +39,16 @@ public class AdvancedConfigurationDialog extends javax.swing.JDialog { /** Creates new form AdvancedConfigurationDialog */ public AdvancedConfigurationDialog() { + this(false); + } + + /** Creates new form AdvancedConfigurationDialog */ + public AdvancedConfigurationDialog(boolean resizable) { super(new JFrame(), true); - setResizable(false); + setResizable(resizable); + if(resizable) { + this.setIconImage(null); + } initComponents(); } diff --git a/HashDatabase/nbproject/project.xml b/HashDatabase/nbproject/project.xml index 37f2a9bf8b..cf99199c2e 100644 --- a/HashDatabase/nbproject/project.xml +++ b/HashDatabase/nbproject/project.xml @@ -6,6 +6,15 @@ org.sleuthkit.autopsy.hashdatabase + + org.netbeans.api.progress + + + + 1 + 1.24.1 + + org.openide.awt diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties index e536f4728d..e00c186e67 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties @@ -5,9 +5,15 @@ HashDbSimplePanel.knownLabel.text=Known files database: HashDbSimplePanel.notableLabel.text=Notable files database: HashDbSimplePanel.knownValLabel.text=- HashDbSimplePanel.notableValLabel.text=- -HashDbMgmtPanel.addNotableButton.text=Add Notable Hashset -HashDbMgmtPanel.addNSRLButton.text=Add NSRL Hashset +HashDbMgmtPanel.addNotableButton.text=Add Notable Database HashDbMgmtPanel.removeNotableButton.text=Remove Selected -HashDbMgmtPanel.removeNSRLButton.text=Remove Selected HashDbSimplePanel.jLabel1.text=Notable Hash Databases: -HashDbSimplePanel.jLabel2.text=NSRL Hash Databases: +HashDbSimplePanel.jLabel2.text=NSRL Hash Database: +HashDbMgmtPanel.nsrlNameLabel.text=No NSRL Hashset +HashDbMgmtPanel.setNSRLButton.text=Change +HashDbSimplePanel.nsrlNameLabel.text=No NSRL database set. +HashDbMgmtPanel.jLabel1.text=Notable Hash Databases: +HashDbMgmtPanel.jLabel2.text=NSRL Database: +HashDbMgmtPanel.indexNSRLButton.text=Index +HashDbMgmtPanel.removeNSRLButton.text=Remove +HashDbMgmtPanel.ingestRunningLabel.text=\ diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ButtonColumn.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ButtonColumn.java new file mode 100644 index 0000000000..039a4b0789 --- /dev/null +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ButtonColumn.java @@ -0,0 +1,227 @@ +/* + * 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; + +/** + * @author jantonius + * + * Taken from: http://tips4java.wordpress.com/2009/07/12/table-button-column/ + * Note: everything is the same, except I edited the buttonName + */ +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.table.*; + +/** + * The ButtonColumn class provides a renderer and an editor that looks like a + * JButton. The renderer and editor will then be used for a specified column + * in the table. The TableModel will contain the String to be displayed on + * the button. + * + * The button can be invoked by a mouse click or by pressing the space bar + * when the cell has focus. Optionally a mnemonic can be set to invoke the + * button. When the button is invoked the provided Action is invoked. The + * source of the Action will be the table. The action command will contain + * the model row number of the button that was clicked. + * + */ +public class ButtonColumn extends AbstractCellEditor + implements TableCellRenderer, TableCellEditor, ActionListener, MouseListener +{ + private JTable table; + private Action action; + private int mnemonic; + private Border originalBorder; + private Border focusBorder; + + private JButton renderButton; + private JButton editButton; + private String text; + private boolean isButtonColumnEditor; + + + /** + * Create the ButtonColumn to be used as a renderer and editor. The + * renderer and editor will automatically be installed on the TableColumn + * of the specified column. + * + * @param table the table containing the button renderer/editor + * @param action the Action to be invoked when the button is invoked + * @param column the column to which the button renderer/editor is added + * @param buttonName text displayed on the button + */ + public ButtonColumn(JTable table, Action action, int column) + { + this.table = table; + this.action = action; + + renderButton = new JButton(); + editButton = new JButton(); + editButton.setFocusPainted( false ); + editButton.addActionListener( this ); + originalBorder = editButton.getBorder(); + setFocusBorder( new LineBorder(Color.BLUE) ); + + TableColumnModel columnModel = table.getColumnModel(); + columnModel.getColumn(column).setCellRenderer( this ); + columnModel.getColumn(column).setCellEditor( this ); + table.addMouseListener( this ); + } + + + /** + * Get foreground color of the button when the cell has focus + * + * @return the foreground color + */ + public Border getFocusBorder() + { + return focusBorder; + } + + /** + * The foreground color of the button when the cell has focus + * + * @param focusBorder the foreground color + */ + public void setFocusBorder(Border focusBorder) + { + this.focusBorder = focusBorder; + editButton.setBorder( focusBorder ); + } + + public int getMnemonic() + { + return mnemonic; + } + + /** + * The mnemonic to activate the button when the cell has focus + * + * @param mnemonic the mnemonic + */ + public void setMnemonic(int mnemonic) + { + this.mnemonic = mnemonic; + renderButton.setMnemonic(mnemonic); + editButton.setMnemonic(mnemonic); + } + + @Override + public Component getTableCellEditorComponent( + JTable table, Object value, boolean isSelected, int row, int column) + { + HashDbMgmtPanel.setButtonFromIndexStatus(editButton, (IndexStatus) value); + return editButton; + } + + @Override + public Object getCellEditorValue() + { + return text; + } + +// +// Implement TableCellRenderer interface +// + @Override + public Component getTableCellRendererComponent( + JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) + { + if (isSelected) + { + renderButton.setForeground(table.getSelectionForeground()); + renderButton.setBackground(table.getSelectionBackground()); + } + else + { + renderButton.setForeground(table.getForeground()); + renderButton.setBackground(UIManager.getColor("Button.background")); + } + + if (hasFocus) + { + renderButton.setBorder( focusBorder ); + } + else + { + renderButton.setBorder( originalBorder ); + } + + HashDbMgmtPanel.setButtonFromIndexStatus(renderButton, (IndexStatus) value); + return renderButton; + } + +// +// Implement ActionListener interface +// + /* + * The button has been pressed. Stop editing and invoke the custom Action + */ + @Override + public void actionPerformed(ActionEvent e) + { + int row = table.convertRowIndexToModel( table.getEditingRow() ); + fireEditingStopped(); + + // Invoke the Action + + ActionEvent event = new ActionEvent( + table, + ActionEvent.ACTION_PERFORMED, + "" + row); + action.actionPerformed(event); + } + +// +// Implement MouseListener interface +// + /* + * When the mouse is pressed the editor is invoked. If you then then drag + * the mouse to another cell before releasing it, the editor is still + * active. Make sure editing is stopped when the mouse is released. + */ + @Override + public void mousePressed(MouseEvent e) + { + if (table.isEditing() + && table.getCellEditor() == this) + isButtonColumnEditor = true; + } + + @Override + public void mouseReleased(MouseEvent e) + { + if (isButtonColumnEditor + && table.isEditing()) + table.getCellEditor().stopCellEditing(); + + isButtonColumnEditor = false; + } + + @Override + public void mouseClicked(MouseEvent e) {} + @Override + public void mouseEntered(MouseEvent e) {} + @Override + public void mouseExited(MouseEvent e) {} +} diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index d851c6a971..79a0b478b9 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -20,7 +20,15 @@ package org.sleuthkit.autopsy.hashdatabase; import java.io.File; import java.util.List; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; +import org.netbeans.api.progress.ProgressHandle; +import org.netbeans.api.progress.ProgressHandleFactory; +import org.openide.util.Cancellable; import org.sleuthkit.autopsy.coreutils.Log; import org.sleuthkit.datamodel.SleuthkitJNI; import org.sleuthkit.datamodel.TskException; @@ -32,7 +40,7 @@ import org.sleuthkit.datamodel.TskException; public class HashDb implements Comparable { public enum DBType{ - NSRL, NOTABLE; + NSRL, KNOWN_BAD; } // Suffix added to the end of a database name to get its index file @@ -41,13 +49,13 @@ public class HashDb implements Comparable { private String name; private List databasePaths; // TODO: Length limited to one for now... private boolean useForIngest; - private DBType type; + private boolean indexing; - public HashDb(String name, DBType type, List databasePaths, boolean useForIngest) { + public HashDb(String name, List databasePaths, boolean useForIngest) { this.name = name; - this.type = type; this.databasePaths = databasePaths; this.useForIngest = useForIngest; + this.indexing = false; } boolean getUseForIngest() { @@ -62,10 +70,6 @@ public class HashDb implements Comparable { return databasePaths; } - DBType getType() { - return type; - } - void setUseForIngest(boolean useForIngest) { this.useForIngest = useForIngest; } @@ -78,10 +82,6 @@ public class HashDb implements Comparable { this.databasePaths = databasePaths; } - void setType(DBType type) { - this.type = type; - } - /** * Checks if the database exists. * @return true if a file exists at the database path, else false @@ -132,6 +132,13 @@ public class HashDb implements Comparable { return i.exists() && db.exists() && isOlderThan(i, db); } + + /** + * Checks if the database is being indexed + */ + boolean isIndexing() { + return indexing; + } /** * Returns the status of the HashDb as determined from indexExists(), @@ -142,6 +149,8 @@ public class HashDb implements Comparable { boolean i = this.indexExists(); boolean db = this.databaseExists(); + if(indexing) + return IndexStatus.INDEXING; if (i) { if (db) { return this.isOutdated() ? IndexStatus.INDEX_OUTDATED : IndexStatus.INDEX_CURRENT; @@ -158,7 +167,9 @@ public class HashDb implements Comparable { * @throws TskException if an error occurs in the SleuthKit bindings */ void createIndex() throws TskException { - SleuthkitJNI.createLookupIndex(databasePaths.get(0), name); //TODO: fix for multiple paths + indexing = true; + CreateIndex creator = new CreateIndex(); + creator.execute(); //TODO: error checking } @@ -216,4 +227,52 @@ public class HashDb implements Comparable { public int compareTo(HashDb o) { return this.name.compareTo(o.name); } + + /* Thread that adds image/file and service pairs to queues */ + private class CreateIndex extends SwingWorker { + + private ProgressHandle progress; + + CreateIndex(){}; + + @Override + protected Object doInBackground() throws Exception { + progress = ProgressHandleFactory.createHandle("Indexing " + name, new Cancellable() { + @Override + public boolean cancel() { + return CreateIndex.this.cancel(true); + } + }); + progress.start(); + progress.switchToIndeterminate(); + SleuthkitJNI.createLookupIndex(databasePaths.get(0)); + return null; + } + + /* clean up or start the worker threads */ + @Override + protected void done() { + try { + super.get(); //block and get all exceptions thrown while doInBackground() + } catch (CancellationException e) { + //task was cancelled + handleInterruption(e); + } catch (InterruptedException ex) { + handleInterruption(ex); + } catch (ExecutionException ex) { + handleInterruption(ex); + } catch (Exception ex) { + handleInterruption(ex); + } finally { + indexing = false; + progress.finish(); + HashDbMgmtPanel.getDefault().resync(); + } + } + + private void handleInterruption(Exception ex) { + //TODO: something + Logger.getLogger(CreateIndex.class.getName()).log(Level.WARNING, "interrupted!", ex); + } + } } \ No newline at end of file diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestService.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestService.java index 2ee7557091..334c1d29b8 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestService.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestService.java @@ -19,14 +19,12 @@ package org.sleuthkit.autopsy.hashdatabase; import java.io.IOException; -import java.util.ArrayList; import java.util.Collections; -import java.util.List; +import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.hashdatabase.HashDb.DBType; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestManagerProxy; import org.sleuthkit.autopsy.ingest.IngestMessage; @@ -54,8 +52,9 @@ public class HashDbIngestService implements IngestServiceFsContent { private int count; // Whether or not to do hash lookups (only set to true if there are dbs set) private boolean process; - private List NSRLDbs = new ArrayList(); - private List notableDbs = new ArrayList(); + private HashDb nsrlSet; + private int nsrlPointer; + private Map knownBadSets = new HashMap(); private HashDbIngestService() { @@ -77,33 +76,41 @@ public class HashDbIngestService implements IngestServiceFsContent { */ @Override public void init(IngestManagerProxy managerProxy) { + HashDbMgmtPanel.getDefault().setIngestRunning(true); this.process = false; this.managerProxy = managerProxy; this.managerProxy.postMessage(IngestMessage.createMessage(++messageId, IngestMessage.MessageType.INFO, this, "Started")); this.skCase = Case.getCurrentCase().getSleuthkitCase(); try { HashDbXML hdbxml = HashDbXML.getCurrent(); - NSRLDbs.clear(); - notableDbs.clear(); + nsrlSet = null; + knownBadSets.clear(); skCase.clearLookupDatabases(); - boolean nsrlSet = false; - boolean notablesSet = false; + boolean nsrlIsSet = false; + boolean knownBadIsSet = false; - for(HashDb db : hdbxml.getSets()) { + HashDb nsrl = hdbxml.getNSRLSet(); + if(nsrl != null && IndexStatus.isIngestible(nsrl.status())) { + nsrlIsSet = true; this.process = true; - if(db.getType().equals(DBType.NOTABLE) && db.getUseForIngest()) { - notablesSet = true; - skCase.addKnownBadDatabase(db.getDatabasePaths().get(0), db.getName()); // TODO: support multiple paths - } else if(db.getType().equals(DBType.NSRL) && db.getUseForIngest()) { - nsrlSet = true; - skCase.setNSRLDatabase(db.getDatabasePaths().get(0)); // TODO: support multiple paths - } + this.nsrlSet = nsrl; + nsrlPointer = skCase.setNSRLDatabase(nsrl.getDatabasePaths().get(0)); } - if (!nsrlSet) { + for(HashDb db : hdbxml.getKnownBadSets()) { + IndexStatus status = db.status(); + if (db.getUseForIngest() && IndexStatus.isIngestible(status)) { // TODO: should inform user that we won't use the db if it's not indexed + this.process = true; + knownBadIsSet = true; + int ret = skCase.addKnownBadDatabase(db.getDatabasePaths().get(0)); // TODO: support multiple paths + knownBadSets.put(ret, db); + } + } + + if (!nsrlIsSet) { this.managerProxy.postMessage(IngestMessage.createWarningMessage(++messageId, this, "No NSRL database set", "Known file search will not be executed.")); } - if (!notablesSet) { + if (!knownBadIsSet) { this.managerProxy.postMessage(IngestMessage.createWarningMessage(++messageId, this, "No known bad database set", "Known bad file search will not be executed.")); } @@ -131,7 +138,7 @@ public class HashDbIngestService implements IngestServiceFsContent { detailsSb.append("Notable databases used:"); detailsSb.append(""); - for(HashDb db : notableDbs) { + for(HashDb db : knownBadSets.values()) { detailsSb.append(""); detailsSb.append(db.getName()); detailsSb.append(""); @@ -141,6 +148,8 @@ public class HashDbIngestService implements IngestServiceFsContent { detailsSb.append(""); managerProxy.postMessage(IngestMessage.createMessage(++messageId, IngestMessage.MessageType.INFO, this, "Hash Ingest Complete", detailsSb.toString())); + + HashDbMgmtPanel.getDefault().setIngestRunning(false); } /** @@ -149,6 +158,7 @@ public class HashDbIngestService implements IngestServiceFsContent { @Override public void stop() { //manager.postMessage(IngestMessage.createMessage(++messageId, IngestMessage.MessageType.INFO, this, "STOP")); + HashDbMgmtPanel.getDefault().setIngestRunning(false); } /** @@ -184,46 +194,24 @@ public class HashDbIngestService implements IngestServiceFsContent { String name = fsContent.getName(); try { String md5Hash = Hash.calculateMd5(fsContent); - Map results = skCase.lookupMd5(md5Hash); - for (Map.Entry entry : results.entrySet()) { - String hashSetName = entry.getKey(); - TskData.FileKnown status = entry.getValue(); - boolean changed = skCase.setKnown(fsContent, status); + TskData.FileKnown status = TskData.FileKnown.UKNOWN; + boolean foundBad = false; + for (Map.Entry entry : knownBadSets.entrySet()) { + status = skCase.knownBadLookupMd5(md5Hash, entry.getKey()); if (status.equals(TskData.FileKnown.BAD)) { + foundBad = true; count += 1; - BlackboardArtifact badFile = fsContent.newArtifact(ARTIFACT_TYPE.TSK_HASHSET_HIT); - BlackboardAttribute att2 = new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_HASHSET_NAME.getTypeID(), MODULE_NAME, "Known Bad", hashSetName); - badFile.addAttribute(att2); - BlackboardAttribute att3 = new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_HASH_MD5.getTypeID(), MODULE_NAME, "", md5Hash); - badFile.addAttribute(att3); - StringBuilder detailsSb = new StringBuilder(); - //details - detailsSb.append(""); - //hit - detailsSb.append(""); - detailsSb.append(""); - detailsSb.append(""); - detailsSb.append(""); - - detailsSb.append(""); - detailsSb.append(""); - detailsSb.append(""); - detailsSb.append(""); - - detailsSb.append(""); - detailsSb.append(""); - detailsSb.append(""); - detailsSb.append(""); - - detailsSb.append("
File Name").append(name).append("
MD5 Hash").append(md5Hash).append("
Hashset Name").append(hashSetName).append("
"); - - managerProxy.postMessage(IngestMessage.createDataMessage(++messageId, this, "Notable: " + name, detailsSb.toString(), name + md5Hash, badFile)); - IngestManager.fireServiceDataEvent(new ServiceDataEvent(MODULE_NAME, ARTIFACT_TYPE.TSK_HASHSET_HIT, Collections.singletonList(badFile))); - ret = ProcessResult.OK; - } else if (status.equals(TskData.FileKnown.KNOWN)) { + skCase.setKnown(fsContent, status); + String hashSetName = entry.getValue().getName(); + processBadFile(fsContent, md5Hash, hashSetName); + } + ret = ProcessResult.OK; + } + if(!foundBad) { + status = skCase.nsrlLookupMd5(md5Hash); + if (status.equals(TskData.FileKnown.KNOWN)) { + skCase.setKnown(fsContent, status); ret = ProcessResult.COND_STOP; - } else { - ret = ProcessResult.OK; } } } catch (TskException ex) { @@ -283,4 +271,44 @@ public class HashDbIngestService implements IngestServiceFsContent { public void saveSimpleConfiguration() { } + private void processBadFile(FsContent fsContent, String md5Hash, String hashSetName) { + try { + BlackboardArtifact badFile = fsContent.newArtifact(ARTIFACT_TYPE.TSK_HASHSET_HIT); + BlackboardAttribute att2 = new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_HASHSET_NAME.getTypeID(), MODULE_NAME, "Known Bad", hashSetName); + badFile.addAttribute(att2); + BlackboardAttribute att3 = new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_HASH_MD5.getTypeID(), MODULE_NAME, "", md5Hash); + badFile.addAttribute(att3); + StringBuilder detailsSb = new StringBuilder(); + //details + detailsSb.append(""); + //hit + detailsSb.append(""); + detailsSb.append(""); + detailsSb.append(""); + detailsSb.append(""); + + detailsSb.append(""); + detailsSb.append(""); + detailsSb.append(""); + detailsSb.append(""); + + detailsSb.append(""); + detailsSb.append(""); + detailsSb.append(""); + detailsSb.append(""); + + detailsSb.append("
File Name").append(fsContent.getName()).append("
MD5 Hash").append(md5Hash).append("
Hashset Name").append(hashSetName).append("
"); + + managerProxy.postMessage(IngestMessage.createDataMessage(++messageId, this, + "Notable: " + fsContent.getName(), + detailsSb.toString(), + fsContent.getName() + md5Hash, + badFile)); + IngestManager.fireServiceDataEvent(new ServiceDataEvent(MODULE_NAME, ARTIFACT_TYPE.TSK_HASHSET_HIT, Collections.singletonList(badFile))); + } catch (TskException ex) { + logger.log(Level.WARNING, "Error creating blackboard artifact", ex); + } + + } + } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbMgmtAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbMgmtAction.java index 0a1f238d06..cd134795e3 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbMgmtAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbMgmtAction.java @@ -20,10 +20,6 @@ package org.sleuthkit.autopsy.hashdatabase; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.io.IOException; -import java.util.logging.Level; -import org.openide.DialogDisplayer; -import org.openide.NotifyDescriptor; import org.openide.util.HelpCtx; import org.openide.util.actions.CallableSystemAction; import org.sleuthkit.autopsy.corecomponents.AdvancedConfigurationDialog; @@ -44,17 +40,13 @@ class HashDbMgmtAction extends CallableSystemAction { // initialize panel with loaded settings final HashDbMgmtPanel panel = HashDbMgmtPanel.getDefault(); - final AdvancedConfigurationDialog dialog = new AdvancedConfigurationDialog(); + final AdvancedConfigurationDialog dialog = new AdvancedConfigurationDialog(true); dialog.addApplyButtonListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - if(panel.save()) { - dialog.close(); - } else { - NotifyDescriptor d = new NotifyDescriptor.Message("Error saving settings", NotifyDescriptor.INFORMATION_MESSAGE); - DialogDisplayer.getDefault().notify(d); - } + panel.save(); + dialog.close(); } }); dialog.display(panel); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbMgmtPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbMgmtPanel.form index 018747f4af..46b5d990b4 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbMgmtPanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbMgmtPanel.form @@ -18,39 +18,65 @@ - - - - + + - + + + + + + + + + + + + + + + + + + - + - + + + + + - - - + + + + - - - - - - - - + + + - + + + + + + + + + + + + @@ -67,48 +93,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -129,5 +113,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbMgmtPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbMgmtPanel.java index 56316dd818..f727b66c87 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbMgmtPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbMgmtPanel.java @@ -26,7 +26,6 @@ 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; @@ -34,7 +33,8 @@ 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.AbstractAction; +import javax.swing.Action; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFileChooser; @@ -43,10 +43,8 @@ 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; @@ -58,14 +56,14 @@ 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; + private HashDb nsrlSet; + private static boolean ingestRunning = false; /** Creates new form HashDbMgmtPanel */ private HashDbMgmtPanel() { notableTableModel = new HashSetTableModel(); - nsrlTableModel = new HashSetTableModel(); initComponents(); customizeComponents(); } @@ -74,18 +72,19 @@ public class HashDbMgmtPanel extends javax.swing.JPanel { if(instance == null) { instance = new HashDbMgmtPanel(); } + instance.notableTableModel.resync(); return instance; } + void resync() { + notableTableModel.resync(); + } + 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); + notableHashSetTable.setRowHeight(20); + notableTableModel.resync(); fc.setDragEnabled(false); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); String[] EXTENSION = new String[] { "txt", "idx", "hash", "Hash" }; @@ -94,76 +93,60 @@ public class HashDbMgmtPanel extends javax.swing.JPanel { 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()); + Action indexSet = new AbstractAction() { + + @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(); } + }; + new ButtonColumn(notableHashSetTable, indexSet, 2); + + nsrlSet = HashDbXML.getCurrent().getNSRLSet(); + if(nsrlSet != null) { + nsrlNameLabel.setText(nsrlSet.getName()); + setButtonFromIndexStatus(indexNSRLButton, nsrlSet.status()); + } else { + setButtonFromIndexStatus(indexNSRLButton, IndexStatus.NO_DB); + removeNSRLButton.setEnabled(false); } } - + /** - * Checks if indexes exist for all defined databases - * @return true if Sleuth Kit can open the indexes of all databases - * than have been selected + * Save the modified settings */ - boolean indexesExist() { - return notableTableModel.indexesExist() && nsrlTableModel.indexesExist(); + void save() { + HashDbXML.getCurrent().setNSRLSet(nsrlSet); } /** - * Save the table settings - * @return whether save was successful + * Don't allow any changes if ingest is running */ - boolean save() { - notableTableModel.saveAll(); - nsrlTableModel.saveAll(); - return true; + void setIngestRunning(boolean running) { + addNotableButton.setEnabled(!running); + removeNotableButton.setEnabled(!running); + setNSRLButton.setEnabled(!running); + indexNSRLButton.setEnabled(!running); + removeNSRLButton.setEnabled(!running); + ingestRunning = running; + if(running) + ingestRunningLabel.setText("Ingest is ongoing; some settings will be unavailable until it finishes."); + else + ingestRunningLabel.setText(""); } /** This method is called from within the constructor to @@ -177,39 +160,18 @@ public class HashDbMgmtPanel extends javax.swing.JPanel { 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(); + setNSRLButton = new javax.swing.JButton(); + nsrlNameLabel = new javax.swing.JLabel(); + jLabel1 = new javax.swing.JLabel(); + jLabel2 = new javax.swing.JLabel(); + indexNSRLButton = new javax.swing.JButton(); + removeNSRLButton = new javax.swing.JButton(); + ingestRunningLabel = new javax.swing.JLabel(); 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) { @@ -224,75 +186,94 @@ public class HashDbMgmtPanel extends javax.swing.JPanel { } }); + setNSRLButton.setText(org.openide.util.NbBundle.getMessage(HashDbMgmtPanel.class, "HashDbMgmtPanel.setNSRLButton.text")); // NOI18N + setNSRLButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + setNSRLButtonActionPerformed(evt); + } + }); + + nsrlNameLabel.setText(org.openide.util.NbBundle.getMessage(HashDbMgmtPanel.class, "HashDbMgmtPanel.nsrlNameLabel.text")); // NOI18N + + jLabel1.setText(org.openide.util.NbBundle.getMessage(HashDbMgmtPanel.class, "HashDbMgmtPanel.jLabel1.text")); // NOI18N + + jLabel2.setText(org.openide.util.NbBundle.getMessage(HashDbMgmtPanel.class, "HashDbMgmtPanel.jLabel2.text")); // NOI18N + + indexNSRLButton.setText(org.openide.util.NbBundle.getMessage(HashDbMgmtPanel.class, "HashDbMgmtPanel.indexNSRLButton.text")); // NOI18N + indexNSRLButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + indexNSRLButtonActionPerformed(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); + } + }); + + ingestRunningLabel.setText(org.openide.util.NbBundle.getMessage(HashDbMgmtPanel.class, "HashDbMgmtPanel.ingestRunningLabel.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addComponent(addNSRLButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 235, Short.MAX_VALUE) - .addComponent(removeNSRLButton) - .addContainerGap()) - .addComponent(jScrollPane1, 0, 0, Short.MAX_VALUE) + .addComponent(jLabel1) + .addContainerGap(257, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(10, 10, 10) + .addComponent(nsrlNameLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 63, Short.MAX_VALUE) + .addComponent(indexNSRLButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(setNSRLButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(removeNSRLButton)) + .addComponent(jLabel2)) + .addContainerGap()) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 389, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addContainerGap() .addComponent(addNotableButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 223, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 113, Short.MAX_VALUE) .addComponent(removeNotableButton) .addContainerGap()) - .addComponent(jScrollPane2, 0, 0, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(ingestRunningLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 369, Short.MAX_VALUE) + .addContainerGap()) ); 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) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel2) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(addNotableButton) - .addComponent(removeNotableButton)) + .addComponent(nsrlNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(removeNSRLButton) + .addComponent(setNSRLButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(indexNSRLButton)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 186, Short.MAX_VALUE) + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 163, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(addNSRLButton) - .addComponent(removeNSRLButton)) + .addComponent(removeNotableButton) + .addComponent(addNotableButton)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ingestRunningLabel) .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(); @@ -316,40 +297,110 @@ public class HashDbMgmtPanel extends javax.swing.JPanel { 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 + if(setName != null && !setName.equals("")) { + HashDb newDb = new HashDb(setName, Arrays.asList(new String[] {filePath}), false); + if(IndexStatus.isIngestible(newDb.status())) + newDb.setUseForIngest(true); + notableTableModel.newSet(newDb); // TODO: support multiple file paths + } } catch (IOException ex) { logger.log(Level.WARNING, "Couldn't get selected file path.", ex); } } + save(); }//GEN-LAST:event_addNotableButtonActionPerformed private void removeNotableButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeNotableButtonActionPerformed - notableTableModel.removeSetAt(notableHashSetTable.getSelectedRow()); + int selected = notableHashSetTable.getSelectedRow(); + if(selected >= 0) + notableTableModel.removeSetAt(notableHashSetTable.getSelectedRow()); }//GEN-LAST:event_removeNotableButtonActionPerformed + private void setNSRLButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_setNSRLButtonActionPerformed + 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 = ""; + } + + this.nsrlSet = new HashDb(derivedName, Arrays.asList(new String[]{filePath}), false); // TODO: support multiple file paths + int toIndex = JOptionPane.NO_OPTION; + if(IndexStatus.isIngestible(this.nsrlSet.status())) { + this.nsrlSet.setUseForIngest(true); + } else { + toIndex = JOptionPane.showConfirmDialog(this, + "The NSRL database you added has no index.\n" + + "It will not be used for ingest until you create one.\n" + + "Would you like to do so now?", "No Index Exists", JOptionPane.YES_NO_OPTION); + } + + nsrlNameLabel.setText(nsrlSet.getName()); + setButtonFromIndexStatus(indexNSRLButton, nsrlSet.status()); + removeNSRLButton.setEnabled(true); + save(); + + if(toIndex == JOptionPane.YES_OPTION) { + indexNSRLButtonActionPerformed(null); + } + + + + } catch (IOException ex) { + logger.log(Level.WARNING, "Couldn't get selected file path.", ex); + } + } + }//GEN-LAST:event_setNSRLButtonActionPerformed + + private void indexNSRLButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_indexNSRLButtonActionPerformed + try { + nsrlSet.createIndex(); + } catch (TskException ex) { + logger.log(Level.WARNING, "Error creating index", ex); + } + setButtonFromIndexStatus(indexNSRLButton, nsrlSet.status()); + }//GEN-LAST:event_indexNSRLButtonActionPerformed + private void removeNSRLButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeNSRLButtonActionPerformed - nsrlTableModel.removeSetAt(nsrlHashSetTable.getSelectedRow()); + this.nsrlSet = null; + save(); + setButtonFromIndexStatus(indexNSRLButton, IndexStatus.NO_DB); + nsrlNameLabel.setText(org.openide.util.NbBundle.getMessage(HashDbMgmtPanel.class, "HashDbMgmtPanel.nsrlNameLabel.text")); + removeNSRLButton.setEnabled(false); }//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.JButton indexNSRLButton; + private javax.swing.JLabel ingestRunningLabel; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; private javax.swing.JScrollPane jScrollPane1; - private javax.swing.JScrollPane jScrollPane2; private javax.swing.JTable notableHashSetTable; - private javax.swing.JTable nsrlHashSetTable; + private javax.swing.JLabel nsrlNameLabel; private javax.swing.JButton removeNSRLButton; private javax.swing.JButton removeNotableButton; + private javax.swing.JButton setNSRLButton; // 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() { @@ -358,7 +409,7 @@ public class HashDbMgmtPanel extends javax.swing.JPanel { @Override public int getRowCount() { - return data.size(); + return xmlHandle.getKnownBadSets().size(); } @Override @@ -377,7 +428,7 @@ public class HashDbMgmtPanel extends javax.swing.JPanel { @Override public Object getValueAt(int rowIndex, int columnIndex) { - HashDb entry = data.get(rowIndex); + HashDb entry = xmlHandle.getKnownBadSets().get(rowIndex); switch(columnIndex) { case 0: return entry.getName(); @@ -392,12 +443,18 @@ public class HashDbMgmtPanel extends javax.swing.JPanel { @Override public boolean isCellEditable(int rowIndex, int columnIndex) { - return columnIndex == 2 || columnIndex == 3; //(status or ingest) + if(ingestRunning) + return false; + if(columnIndex == 2) + return true; + if(columnIndex == 3) + return true; + return false; } @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { - HashDb entry = data.get(rowIndex); + HashDb entry = xmlHandle.getKnownBadSets().get(rowIndex); switch(columnIndex) { case 0: entry.setName((String) aValue); @@ -408,7 +465,10 @@ public class HashDbMgmtPanel extends javax.swing.JPanel { case 2: break; case 3: - entry.setUseForIngest((Boolean) aValue); + if(((Boolean) getValueAt(rowIndex, columnIndex)) || IndexStatus.isIngestible(entry.status())) + entry.setUseForIngest((Boolean) aValue); + else + JOptionPane.showMessageDialog(HashDbMgmtPanel.this, "Databases must be indexed before they can be used for ingest."); } } @@ -417,37 +477,22 @@ public class HashDbMgmtPanel extends javax.swing.JPanel { return getValueAt(0, c).getClass(); } - void resync(DBType type) { - data.clear(); - data.addAll(xmlHandle.getSets(type)); + void resync() { fireTableDataChanged(); } - void newSet(String name, List paths, boolean useForIngest, DBType type) { - xmlHandle.addSet(new HashDb(name, type, paths, useForIngest)); - resync(type); + void newSet(HashDb db) { + xmlHandle.addKnownBadSet(db); + resync(); } 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; + xmlHandle.removeKnownBadSetAt(index); + resync(); } HashDb getHashSetAt(int row) { - return data.get(row); + return xmlHandle.getKnownBadSets().get(row); } } @@ -461,6 +506,7 @@ public class HashDbMgmtPanel extends javax.swing.JPanel { this.setHorizontalAlignment(JCheckBox.CENTER); this.setVerticalAlignment(JCheckBox.CENTER); + setEnabled(!ingestRunning); Boolean selected = (Boolean) table.getModel().getValueAt(row, column); setSelected(selected); @@ -473,27 +519,13 @@ public class HashDbMgmtPanel extends javax.swing.JPanel { } } - private class ButtonRenderer extends AbstractCellEditor implements TableCellRenderer, TableCellEditor { - - private JButton theButton; - - private ButtonRenderer() { - theButton = new JButton(); + static void setButtonFromIndexStatus(JButton theButton, IndexStatus status) { + if(ingestRunning) { + theButton.setText("Not Available"); + theButton.setEnabled(false); + return; } - - 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) { + switch (status) { case INDEX_OUTDATED: theButton.setText("Re-index"); theButton.setEnabled(true); @@ -506,38 +538,14 @@ public class HashDbMgmtPanel extends javax.swing.JPanel { theButton.setText("Index"); theButton.setEnabled(true); break; + case INDEXING: + theButton.setText("Indexing"); + theButton.setEnabled(false); + 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; - } - } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.form index ee4a3d0cc0..73c556f986 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.form @@ -16,18 +16,23 @@ - - - - - - + + + + + + + + + + + @@ -35,17 +40,24 @@ - + - + + + + + + + + @@ -53,17 +65,13 @@ - - - - - - - - - - - + + + + + + + @@ -81,5 +89,12 @@ + + + + + + + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java index 34698b4fcc..73e13da6cb 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java @@ -27,10 +27,8 @@ package org.sleuthkit.autopsy.hashdatabase; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; -import javax.swing.ListSelectionModel; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableColumn; -import org.sleuthkit.autopsy.hashdatabase.HashDb.DBType; /** * @@ -39,22 +37,21 @@ import org.sleuthkit.autopsy.hashdatabase.HashDb.DBType; public class HashDbSimplePanel extends javax.swing.JPanel { private static final Logger logger = Logger.getLogger(HashDbSimplePanel.class.getName()); - private HashTableModel notableTableModel; - private HashTableModel nsrlTableModel; + private HashTableModel knownBadTableModel; + private HashDb nsrl; /** Creates new form HashDbSimplePanel */ public HashDbSimplePanel() { - notableTableModel = new HashTableModel(); - nsrlTableModel = new HashTableModel(); + knownBadTableModel = new HashTableModel(); initComponents(); customizeComponents(); } private void customizeComponents() { - notableHashTable.setModel(notableTableModel); + notableHashTable.setModel(knownBadTableModel); notableHashTable.setTableHeader(null); - notableHashTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + notableHashTable.setRowSelectionAllowed(false); //customize column witdhs final int width1 = jScrollPane1.getPreferredSize().width; TableColumn column1 = null; @@ -67,22 +64,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { } } - nsrlHashTable.setModel(nsrlTableModel); - - nsrlHashTable.setTableHeader(null); - nsrlHashTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - //customize column witdhs - final int width2 = jScrollPane1.getPreferredSize().width; - TableColumn column2 = null; - for (int i = 0; i < nsrlHashTable.getColumnCount(); i++) { - column2 = nsrlHashTable.getColumnModel().getColumn(i); - if (i == 0) { - column2.setPreferredWidth(((int) (width2 * 0.15))); - } else { - column2.setPreferredWidth(((int) (width2 * 0.84))); - } - } - reloadLists(); + reloadSets(); } /** This method is called from within the constructor to @@ -96,67 +78,79 @@ public class HashDbSimplePanel extends javax.swing.JPanel { jScrollPane1 = new javax.swing.JScrollPane(); notableHashTable = new javax.swing.JTable(); - jScrollPane2 = new javax.swing.JScrollPane(); - nsrlHashTable = new javax.swing.JTable(); jLabel1 = new javax.swing.JLabel(); jLabel2 = new javax.swing.JLabel(); + nsrlNameLabel = new javax.swing.JLabel(); + jScrollPane1.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1)); + + notableHashTable.setBackground(new java.awt.Color(240, 240, 240)); + notableHashTable.setShowHorizontalLines(false); + notableHashTable.setShowVerticalLines(false); jScrollPane1.setViewportView(notableHashTable); - jScrollPane2.setViewportView(nsrlHashTable); - jLabel1.setText(org.openide.util.NbBundle.getMessage(HashDbSimplePanel.class, "HashDbSimplePanel.jLabel1.text")); // NOI18N jLabel2.setText(org.openide.util.NbBundle.getMessage(HashDbSimplePanel.class, "HashDbSimplePanel.jLabel2.text")); // NOI18N + nsrlNameLabel.setText(org.openide.util.NbBundle.getMessage(HashDbSimplePanel.class, "HashDbSimplePanel.nsrlNameLabel.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(jLabel2) - .addContainerGap(154, Short.MAX_VALUE)) - .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 274, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(jLabel1) .addContainerGap(142, Short.MAX_VALUE)) .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 274, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(10, 10, 10) + .addComponent(nsrlNameLabel)) + .addComponent(jLabel2)) + .addContainerGap(143, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jLabel2) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 35, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(nsrlNameLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jLabel1) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 91, Short.MAX_VALUE)) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 106, Short.MAX_VALUE)) ); }// //GEN-END:initComponents + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JScrollPane jScrollPane1; - private javax.swing.JScrollPane jScrollPane2; private javax.swing.JTable notableHashTable; - private javax.swing.JTable nsrlHashTable; + private javax.swing.JLabel nsrlNameLabel; // End of variables declaration//GEN-END:variables - private void reloadLists() { - nsrlTableModel.resync(DBType.NSRL); - notableTableModel.resync(DBType.NOTABLE); + private void reloadSets() { + nsrl = HashDbXML.getCurrent().getNSRLSet(); + if(nsrl == null) { + nsrlNameLabel.setText("No NSRL database set."); + } else { + nsrlNameLabel.setText(nsrl.getName()); + } + knownBadTableModel.resync(); } private class HashTableModel extends AbstractTableModel { private List data = new ArrayList(); - private void resync(DBType type) { + private void resync() { data.clear(); - data.addAll(HashDbXML.getCurrent().getSets(type)); + data.addAll(HashDbXML.getCurrent().getKnownBadSets()); } @Override @@ -188,8 +182,8 @@ public class HashDbSimplePanel extends javax.swing.JPanel { public void setValueAt(Object aValue, int rowIndex, int columnIndex) { if(columnIndex == 0){ HashDb db = data.get(rowIndex); - HashDbXML.getCurrent().addSet(new HashDb(db.getName(), db.getType(), db.getDatabasePaths(), (Boolean) aValue)); - reloadLists(); + HashDbXML.getCurrent().addKnownBadSet(new HashDb(db.getName(), db.getDatabasePaths(), (Boolean) aValue)); + reloadSets(); } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java index a8ce178faf..28f5f0535b 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java @@ -26,6 +26,7 @@ import java.io.IOException; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.util.ArrayList; +import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -67,11 +68,12 @@ public class HashDbXML { private static final Logger logger = Logger.getLogger(HashDbXML.class.getName()); private static HashDbXML currentInstance; - private Map theSets; + private List knownBadSets; + private HashDb nsrlSet; private String xmlFile; private HashDbXML(String xmlFile) { - theSets = new LinkedHashMap(); + knownBadSets = new ArrayList(); this.xmlFile = xmlFile; } @@ -89,47 +91,56 @@ public class HashDbXML { /** * Get the hash sets */ - public List getSets() { + public List getAllSets() { List ret = new ArrayList(); - ret.addAll(theSets.values()); + ret.addAll(knownBadSets); + ret.add(nsrlSet); return ret; } /** - * Get the NSRL sets + * Get the Known Bad sets */ - public List getSets(DBType type) { - List ret = new ArrayList(); - for(HashDb db : theSets.values()) { - if(db.getType().equals(type)) - ret.add(db); - } - return ret; + public List getKnownBadSets() { + return knownBadSets; + } + + /** + * Get the NSRL set + */ + public HashDb getNSRLSet() { + return nsrlSet; } /** - * Add a hash set (override old set) + * Add a known bad hash set */ - public void addSet(HashDb set) { - theSets.put(set.getName(), set); + public void addKnownBadSet(HashDb set) { + knownBadSets.add(set); save(); } /** - * Remove a hash set + * Set the NSRL hash set (override old set) */ - public void removeSet(HashDb set) { - theSets.remove(set.getName()); + public void setNSRLSet(HashDb set) { + this.nsrlSet = set; save(); } /** - * Put all the given DBs into this XML (overwrite old ones) + * Remove a hash known bad set */ - public void putAll(List sets) { - for(HashDb set : sets) { - theSets.put(set.getName(), set); - } + public void removeKnownBadSetAt(int index) { + knownBadSets.remove(index); + save(); + } + + /** + * Remove the NSRL database + */ + public void removeNSRLSet() { + this.nsrlSet = null; save(); } @@ -139,7 +150,8 @@ public class HashDbXML { public void reload() { boolean created = false; - theSets.clear(); + knownBadSets.clear(); + nsrlSet = null; if (!this.setsFileExists()) { //create new if it doesn't exist @@ -169,14 +181,33 @@ public class HashDbXML { Element rootEl = doc.createElement(ROOT_EL); doc.appendChild(rootEl); - for (String setName : theSets.keySet()) { - HashDb set = theSets.get(setName); + for (HashDb set : knownBadSets) { String useForIngest = Boolean.toString(set.getUseForIngest()); List paths = set.getDatabasePaths(); - String type = set.getType().toString(); + String type = DBType.KNOWN_BAD.toString(); Element setEl = doc.createElement(SET_EL); - setEl.setAttribute(SET_NAME_ATTR, setName); + setEl.setAttribute(SET_NAME_ATTR, set.getName()); + setEl.setAttribute(SET_TYPE_ATTR, type); + setEl.setAttribute(SET_USE_FOR_INGEST_ATTR, useForIngest); + + for (int i = 0; i < paths.size(); i++) { + String path = paths.get(i); + Element pathEl = doc.createElement(PATH_EL); + pathEl.setAttribute(PATH_NUMBER_ATTR, Integer.toString(i)); + pathEl.setTextContent(path); + setEl.appendChild(pathEl); + } + rootEl.appendChild(setEl); + } + + if(nsrlSet != null) { + String useForIngest = Boolean.toString(nsrlSet.getUseForIngest()); + List paths = nsrlSet.getDatabasePaths(); + String type = DBType.NSRL.toString(); + + Element setEl = doc.createElement(SET_EL); + setEl.setAttribute(SET_NAME_ATTR, nsrlSet.getName()); setEl.setAttribute(SET_TYPE_ATTR, type); setEl.setAttribute(SET_USE_FOR_INGEST_ATTR, useForIngest); @@ -231,9 +262,14 @@ public class HashDbXML { String path = pathEl.getTextContent(); paths.add(path); } - - HashDb set = new HashDb(name, typeDBType, paths, useForIngestBool); - theSets.put(name, set); + + HashDb set = new HashDb(name, paths, useForIngestBool); + + if(typeDBType == DBType.KNOWN_BAD) { + knownBadSets.add(set); + } else if(typeDBType == DBType.NSRL) { + this.nsrlSet = set; + } } return true; } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java index f1e30ed568..2500f21ee4 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java @@ -44,7 +44,11 @@ enum IndexStatus { /** * Neither the index nor the database exists. */ - NONE("No index or database."); + NONE("No index or database."), + /** + * The index is currently being generated + */ + INDEXING("The index is currently being generated"); private String message; @@ -62,4 +66,8 @@ enum IndexStatus { String message() { return this.message; } + + public static boolean isIngestible(IndexStatus status) { + return status == NO_DB || status == INDEX_CURRENT || status == INDEX_OUTDATED; + } }