2013-12-11 15:57:19 -05:00

304 lines
8.9 KiB
Java

/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.util.List;
import java.util.logging.Level;
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.Logger;
import org.sleuthkit.datamodel.SleuthkitJNI;
import org.sleuthkit.datamodel.TskException;
/**
* Hash database representation of NSRL and Known Bad hash databases
* with indexing capability
*
*/
public class HashDb implements Comparable<HashDb> {
enum EVENT {INDEXING_DONE };
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
public enum DBType{
NSRL("NSRL"), KNOWN_BAD("Known Bad");
private String displayName;
private DBType(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return this.displayName;
}
}
// Suffix added to the end of a database name to get its index file
private static final String INDEX_SUFFIX = "-md5.idx";
private String name;
private List<String> databasePaths; // TODO: Length limited to one for now...
private boolean useForIngest;
private boolean showInboxMessages;
private boolean indexing;
private DBType type;
public HashDb(String name, List<String> databasePaths, boolean useForIngest, boolean showInboxMessages, DBType type) {
this.name = name;
this.databasePaths = databasePaths;
this.useForIngest = useForIngest;
this.showInboxMessages = showInboxMessages;
this.type = type;
this.indexing = false;
}
void addPropertyChangeListener(PropertyChangeListener pcl) {
pcs.addPropertyChangeListener(pcl);
}
void removePropertyChangeListener(PropertyChangeListener pcl) {
pcs.removePropertyChangeListener(pcl);
}
boolean getUseForIngest() {
return useForIngest;
}
boolean getShowInboxMessages() {
return showInboxMessages;
}
DBType getDbType() {
return type;
}
String getName() {
return name;
}
List<String> getDatabasePaths() {
return databasePaths;
}
void setUseForIngest(boolean useForIngest) {
this.useForIngest = useForIngest;
}
void setShowInboxMessages(boolean showInboxMessages) {
this.showInboxMessages = showInboxMessages;
}
void setName(String name) {
this.name = name;
}
void setDatabasePaths(List<String> databasePaths) {
this.databasePaths = databasePaths;
}
void setDbType(DBType type) {
this.type = type;
}
/**
* Checks if the database exists.
* @return true if a file exists at the database path, else false
*/
boolean databaseExists() {
return databaseFile().exists();
}
/**
* Checks if Sleuth Kit can open the index for the database path.
* @return true if the index was found and opened successfully, else false
*/
boolean indexExists() {
try {
return hasIndex(databasePaths.get(0)); // TODO: support multiple paths
} catch (TskException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Error checking if index exists.", ex);
return false;
}
}
/**
* Gets the database file.
* @return a File initialized with the database path
*/
File databaseFile() {
return new File(databasePaths.get(0)); // TODO: support multiple paths
}
/**
* Gets the index file
* @return a File initialized with an index path derived from the database
* path
*/
File indexFile() {
return new File(toIndexPath(databasePaths.get(0))); // TODO: support multiple paths
}
/**
* Checks if the index file is older than the database file
* @return true if there is are files at the index path and the database
* path, and the index file has an older modified-time than the database
* file, else false
*/
boolean isOutdated() {
File i = indexFile();
File db = databaseFile();
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(),
* databaseExists(), and isOutdated()
* @return IndexStatus enum according to their definitions
*/
IndexStatus status() {
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;
} else {
return IndexStatus.NO_DB;
}
} else {
return db ? IndexStatus.NO_INDEX : IndexStatus.NONE;
}
}
/**
* Tries to index the database (overwrites any existing index)
* @throws TskException if an error occurs in the SleuthKit bindings
*/
void createIndex() throws TskException {
indexing = true;
CreateIndex creator = new CreateIndex();
creator.execute();
}
/**
* Checks if one file is older than an other
* @param a first file
* @param b second file
* @return true if the first file's last modified data is before the second
* file's last modified date
*/
private static boolean isOlderThan(File a, File b) {
return a.lastModified() < b.lastModified();
}
/**
* Determines if a path points to an index by checking the suffix
* @param path
* @return true if index
*/
static boolean isIndexPath(String path) {
return path.endsWith(INDEX_SUFFIX);
}
/**
* Derives database path from an image path by removing the suffix.
* @param indexPath
* @return
*/
static String toDatabasePath(String indexPath) {
return indexPath.substring(0, indexPath.lastIndexOf(INDEX_SUFFIX));
}
/**
* Derives image path from an database path by appending the suffix.
* @param databasePath
* @return
*/
static String toIndexPath(String databasePath) {
return databasePath.concat(INDEX_SUFFIX);
}
/**
* Calls Sleuth Kit method via JNI to determine whether there is an
* index for the given path
* @param databasePath path Path for the database the index is of
* (database doesn't have to actually exist)'
* @return true if index exists
* @throws TskException if there is an error in the JNI call
*/
static boolean hasIndex(String databasePath) throws TskException {
return SleuthkitJNI.lookupIndexExists(databasePath);
}
@Override
public int compareTo(HashDb o) {
return this.name.compareTo(o.name);
}
/* Thread that creates a database's index */
private class CreateIndex extends SwingWorker<Object,Void> {
private ProgressHandle progress;
CreateIndex(){};
@Override
protected Object doInBackground() throws Exception {
progress = ProgressHandleFactory.createHandle("Indexing " + name);
/** We need proper cancel support in TSK to make the task cancellable
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() {
indexing = false;
progress.finish();
pcs.firePropertyChange(EVENT.INDEXING_DONE.toString(), null, name);
}
}
}