Merge branch 'master' of github.com:sleuthkit/autopsy

This commit is contained in:
Brian Carrier 2012-09-12 14:02:04 -04:00
commit dc0f15c2e2
64 changed files with 1345 additions and 1106 deletions

View File

@ -1,4 +1,4 @@
<?xml version="1.1" encoding="UTF-8" ?>
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
@ -20,7 +20,7 @@
<Group type="102" alignment="0" attributes="0">
<Component id="pauseButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="progressSlider" pref="160" max="32767" attributes="0"/>
<Component id="progressSlider" pref="158" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="progressLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
@ -32,10 +32,10 @@
<Group type="102" alignment="1" attributes="0">
<Component id="videoPanel" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="pauseButton" min="-2" max="-2" attributes="0"/>
<Component id="progressLabel" min="-2" max="-2" attributes="0"/>
<Component id="progressSlider" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" max="-2" attributes="0">
<Component id="pauseButton" max="32767" attributes="0"/>
<Component id="progressSlider" max="32767" attributes="0"/>
<Component id="progressLabel" alignment="1" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
@ -47,6 +47,15 @@
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataContentViewerMedia.pauseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[45, 23]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[45, 23]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[45, 23]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="pauseButtonActionPerformed"/>
@ -68,6 +77,9 @@
</Layout>
</Container>
<Component class="javax.swing.JSlider" name="progressSlider">
<Properties>
<Property name="value" type="int" value="0"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="progressLabel">
<Properties>

View File

@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.corecomponents;
import java.awt.Component;
import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.CancellationException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BoxLayout;
@ -45,18 +46,20 @@ import org.sleuthkit.datamodel.TskData;
*
* @author dfickling
*/
@ServiceProvider(service = DataContentViewer.class, position=5)
@ServiceProvider(service = DataContentViewer.class, position = 5)
public class DataContentViewerMedia extends javax.swing.JPanel implements DataContentViewer {
private static final String[] IMAGES = new String[]{ ".jpg", ".jpeg", ".png", ".gif", ".jpe", ".bmp"};
private static final String[] VIDEOS = new String[]{ ".mov", ".m4v", ".flv", ".mp4", ".3gp", ".avi", ".mpg", ".mpeg"};
private static final String[] AUDIOS = new String[]{ ".mp3", ".wav", ".wma"};
private static final String[] IMAGES = new String[]{".jpg", ".jpeg", ".png", ".gif", ".jpe", ".bmp"};
private static final String[] VIDEOS = new String[]{".mov", ".m4v", ".flv", ".mp4", ".3gp", ".avi", ".mpg", ".mpeg"};
private static final String[] AUDIOS = new String[]{".mp3", ".wav", ".wma"};
private static final Logger logger = Logger.getLogger(DataContentViewerMedia.class.getName());
private VideoComponent videoComponent;
private PlayBin2 playbin2;
private File currentFile;
private long durationMillis = 0;
private boolean autoTracking = false; // true if the slider is moving automatically
private final Object playbinLock = new Object(); // lock for synchronization of playbin2 player
/**
* Creates new form DataContentViewerVideo
*/
@ -68,20 +71,24 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
private void customizeComponents() {
Gst.init();
progressSlider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
int time = progressSlider.getValue();
if(playbin2 != null && !autoTracking) {
/**
* Should always try to synchronize any call to
* progressSlider.setValue() to avoid a different thread changing
* playbin while stateChanged() is processing
*/
@Override
public void stateChanged(ChangeEvent e) {
int time = progressSlider.getValue();
synchronized (playbinLock) {
if (playbin2 != null && !autoTracking) {
State orig = playbin2.getState();
playbin2.pause();
playbin2.getState();
playbin2.seek(ClockTime.fromMillis(time));
playbin2.setState(orig);
}
}
});
}
});
}
/**
@ -99,6 +106,9 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
progressLabel = new javax.swing.JLabel();
pauseButton.setText(org.openide.util.NbBundle.getMessage(DataContentViewerMedia.class, "DataContentViewerMedia.pauseButton.text")); // NOI18N
pauseButton.setMaximumSize(new java.awt.Dimension(45, 23));
pauseButton.setMinimumSize(new java.awt.Dimension(45, 23));
pauseButton.setPreferredSize(new java.awt.Dimension(45, 23));
pauseButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
pauseButtonActionPerformed(evt);
@ -116,6 +126,8 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
.addGap(0, 242, Short.MAX_VALUE)
);
progressSlider.setValue(0);
progressLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerMedia.class, "DataContentViewerMedia.progressLabel.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
@ -124,9 +136,9 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(videoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(pauseButton)
.addComponent(pauseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(progressSlider, javax.swing.GroupLayout.DEFAULT_SIZE, 160, Short.MAX_VALUE)
.addComponent(progressSlider, javax.swing.GroupLayout.DEFAULT_SIZE, 158, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(progressLabel)
.addContainerGap())
@ -136,26 +148,30 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(videoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(pauseButton)
.addComponent(progressLabel)
.addComponent(progressSlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(pauseButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(progressSlider, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(progressLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
);
}// </editor-fold>//GEN-END:initComponents
private void pauseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pauseButtonActionPerformed
if(playbin2.getState().equals(State.PLAYING)){
playbin2.pause();
pauseButton.setText("");
} else if(playbin2.getState().equals(State.PAUSED)) {
playbin2.play();
pauseButton.setText("||");
} else {
ExtractMedia em = new ExtractMedia(currentFile, getJFile(currentFile));
em.execute();
synchronized (playbinLock) {
State state = playbin2.getState();
if (state.equals(State.PLAYING)) {
playbin2.pause();
pauseButton.setText("");
playbin2.setState(State.PAUSED);
} else if (state.equals(State.PAUSED)) {
playbin2.play();
pauseButton.setText("||");
playbin2.setState(State.PLAYING);
} else if (state.equals(State.READY)) {
ExtractMedia em = new ExtractMedia(currentFile, getJFile(currentFile));
em.execute();
}
}
}//GEN-LAST:event_pauseButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton pauseButton;
private javax.swing.JLabel progressLabel;
@ -165,48 +181,93 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
@Override
public void setNode(Node selectedNode) {
pauseButton.setText("");
if(selectedNode == null) {
setDataView(null);
reset();
setComponentsVisibility(false);
if (selectedNode == null) {
return;
}
File file = selectedNode.getLookup().lookup(File.class);
setDataView(file);
if(file == null) {
if (file == null) {
return;
}
boolean isVidOrAud = containsExt(file.getName(), VIDEOS) || containsExt(file.getName(), AUDIOS);
pauseButton.setVisible(isVidOrAud);
progressLabel.setVisible(isVidOrAud);
progressSlider.setVisible(isVidOrAud);
currentFile = file;
if (containsExt(file.getName(), IMAGES)) {
showImage(file);
} else if (containsExt(file.getName(), VIDEOS) || containsExt(file.getName(), AUDIOS)) {
setupVideo(file);
}
}
private void setDataView(File file) {
if(file == null) {
setComponentsVisibility(false);
return;
} else {
setComponentsVisibility(true);
}
this.currentFile = file;
if (containsExt(file.getName(), IMAGES)) {
java.io.File ioFile = getJFile(file);
if (!ioFile.exists()) {
try {
ContentUtils.writeToFile(file, ioFile);
} catch (IOException ex) {
logger.log(Level.WARNING, "Error buffering file", ex);
}
/**
* Initialize vars and display the image on the panel.
*
* @param file
*/
private void showImage(File file) {
java.io.File ioFile = getJFile(file);
if (!ioFile.exists()) {
try {
ContentUtils.writeToFile(file, ioFile);
} catch (IOException ex) {
logger.log(Level.WARNING, "Error buffering file", ex);
}
}
videoComponent = new VideoComponent();
synchronized (playbinLock) {
playbin2 = new PlayBin2("ImageViewer");
playbin2.setVideoSink(videoComponent.getElement());
}
videoPanel.removeAll();
videoPanel.setLayout(new BoxLayout(videoPanel, BoxLayout.Y_AXIS));
videoPanel.add(videoComponent);
videoPanel.revalidate();
videoPanel.repaint();
synchronized (playbinLock) {
playbin2.setInputFile(ioFile);
playbin2.play();
}
videoPanel.setVisible(true);
}
/**
* Initialize all the necessary vars to play a video/audio file.
*
* @param file the File to play
*/
private void setupVideo(File file) {
java.io.File ioFile = getJFile(file);
pauseButton.setText("");
progressSlider.setValue(0);
videoComponent = new VideoComponent();
synchronized (playbinLock) {
playbin2 = new PlayBin2("VideoPlayer");
playbin2.setVideoSink(videoComponent.getElement());
}
videoPanel.removeAll();
videoPanel.setLayout(new BoxLayout(videoPanel, BoxLayout.Y_AXIS));
videoPanel.add(videoComponent);
videoPanel.revalidate();
videoPanel.repaint();
synchronized (playbinLock) {
playbin2.setInputFile(ioFile);
playbin2.setState(State.READY);
}
setComponentsVisibility(true);
}
/**
* To set the visibility of specific components in this class.
*
* @param isVisible whether to show or hide the specific components
* @param isVisible whether to show or hide the specific components
*/
private void setComponentsVisibility(boolean isVisible) {
pauseButton.setVisible(isVisible);
@ -237,42 +298,31 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
@Override
public void resetComponent() {
// we don't want this to do anything
// because we already reset on each selected node
}
private void resetVideo() {
if(playbin2 != null) {
if(playbin2.isPlaying()) {
playbin2.stop();
private void reset() {
synchronized (playbinLock) {
if (playbin2 != null) {
if (playbin2.isPlaying()) {
playbin2.stop();
}
playbin2.setState(State.NULL);
// try {
// Thread.sleep(20); // gstreamer needs to catch up
// } catch (InterruptedException ex) { }
if (playbin2.getState().equals(State.NULL)) {
playbin2.dispose();
}
playbin2 = null;
}
playbin2.setState(State.NULL);
if(playbin2.getState() == State.NULL) {
playbin2.dispose();
}
playbin2 = null;
}
videoComponent = null;
playbin2 = new PlayBin2("VideoPlayer");
videoComponent = new VideoComponent();
playbin2.setVideoSink(videoComponent.getElement());
videoPanel.removeAll();
videoPanel.setLayout(new BoxLayout(videoPanel, BoxLayout.Y_AXIS));
videoPanel.add(videoComponent);
videoPanel.revalidate();
videoPanel.repaint();
}
private void stopVideo() {
if(playbin2 != null && playbin2.isPlaying()) {
playbin2.stop();
videoComponent = null;
}
}
@Override
public boolean isSupported(Node node) {
stopVideo();
if (node == null) {
return false;
}
@ -286,14 +336,13 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
return false;
}
if(file.getSize() == 0) {
if (file.getSize() == 0) {
return false;
}
String name = file.getName().toLowerCase();
if(containsExt(name, IMAGES) || containsExt(name, AUDIOS) || containsExt(name, VIDEOS)) {
resetVideo();
if (containsExt(name, IMAGES) || containsExt(name, AUDIOS) || containsExt(name, VIDEOS)) {
return true;
}
@ -302,7 +351,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
@Override
public int isPreferred(Node node, boolean isSupported) {
if(isSupported) {
if (isSupported) {
return 7;
} else {
return 0;
@ -334,17 +383,21 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
}
/* Thread that extracts and plays a file */
private class ExtractMedia extends SwingWorker<Object,Void> {
private class ExtractMedia extends SwingWorker<Object, Void> {
private ProgressHandle progress;
boolean success = false;
private File sFile;
private java.io.File jFile;
String duration;
String position;
ExtractMedia(org.sleuthkit.datamodel.File sFile, java.io.File jFile){
ExtractMedia(org.sleuthkit.datamodel.File sFile, java.io.File jFile) {
this.sFile = sFile;
this.jFile = jFile;
};
}
;
@Override
protected Object doInBackground() throws Exception {
@ -357,9 +410,9 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
});
progressLabel.setText("Buffering...");
progress.start();
progress.switchToIndeterminate();
progress.switchToDeterminate(100);
try {
ContentUtils.writeToFile(sFile, jFile);
ContentUtils.writeToFile(sFile, jFile, progress, this, true);
} catch (IOException ex) {
logger.log(Level.WARNING, "Error buffering file", ex);
}
@ -370,9 +423,19 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
/* clean up or start the worker threads */
@Override
protected void done() {
progress.finish();
if (success) {
play();
try {
super.get(); //block and get all exceptions thrown while doInBackground()
} catch (CancellationException ex) {
logger.log(Level.INFO, "Media buffering was canceled.");
} catch (InterruptedException ex) {
logger.log(Level.INFO, "Media buffering was interrupted.");
} catch (Exception ex) {
logger.log(Level.SEVERE, "Fatal error during media buffering.", ex);
} finally {
progress.finish();
if (!this.isCancelled()) {
play();
}
}
}
@ -381,34 +444,49 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
progressLabel.setText("Error buffering file");
return;
}
playbin2.setInputFile(jFile);
playbin2.play(); // must play, then pause and get state to get duration.
playbin2.pause();
playbin2.getState();
String duration = playbin2.queryDuration().toString();
durationMillis = playbin2.queryDuration().toMillis();
progressSlider.setMaximum((int)durationMillis);
ClockTime dur = null;
synchronized (playbinLock) {
playbin2.play(); // must play, then pause and get state to get duration.
playbin2.pause();
playbin2.getState();
dur = playbin2.queryDuration();
}
duration = dur.toString();
durationMillis = dur.toMillis();
progressSlider.setMaximum((int) durationMillis);
progressSlider.setMinimum(0);
final String finalDuration;
if(duration.length() == 8 && duration.substring(0,3).equals("00:")) {
if (duration.length() == 8 && duration.substring(0, 3).equals("00:")) {
finalDuration = duration.substring(3);
progressLabel.setText("00:00/" + duration);
} else {
finalDuration = duration;
progressLabel.setText("00:00:00/" + duration);
}
playbin2.play();
synchronized (playbinLock) {
playbin2.play();
}
pauseButton.setText("||");
new Thread(new Runnable() {
private boolean isPlayBinReady() {
synchronized (playbinLock) {
return playbin2 != null && !playbin2.getState().equals(State.NULL);
}
}
@Override
public void run() {
long positionMillis = 0;
while (positionMillis < durationMillis
&& playbin2 != null
&& !playbin2.getState().equals(State.NULL)) {
String position = playbin2.queryPosition().toString();
positionMillis = playbin2.queryPosition().toMillis();
&& isPlayBinReady() ) {
ClockTime pos = null;
synchronized (playbinLock) {
pos = playbin2.queryPosition();
}
position = pos.toString();
positionMillis = pos.toMillis();
if (position.length() == 8) {
position = position.substring(3);
}
@ -426,13 +504,22 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
} else {
progressLabel.setText("00:00:00/" + finalDuration);
}
if (playbin2 != null) {
playbin2.stop();
playbin2.getState();
pauseButton.setText("");
progressSlider.setValue(0);
// If it reached the end
if (progressSlider.getValue() == progressSlider.getMaximum()) {
restartVideo();
}
}
public void restartVideo() {
synchronized (playbinLock) {
if (playbin2 != null) {
playbin2.stop();
playbin2.setState(State.READY); // ready to be played again
}
}
pauseButton.setText("");
progressSlider.setValue(0);
}
}).start();
}
}

View File

@ -64,7 +64,7 @@ import org.sleuthkit.autopsy.datamodel.Views;
import org.sleuthkit.autopsy.datamodel.ViewsNode;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent;
import org.sleuthkit.autopsy.ingest.ServiceDataEvent;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content;
@ -685,7 +685,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
}
if (changed.equals(IngestModuleEvent.DATA.toString())) {
final ServiceDataEvent event = (ServiceDataEvent) oldValue;
final ModuleDataEvent event = (ModuleDataEvent) oldValue;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {

View File

@ -32,11 +32,12 @@ import java.util.Collection;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.ingest.IngestManagerProxy;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.IngestMessage;
import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType;
import org.sleuthkit.autopsy.ingest.IngestServiceAbstract;
import org.sleuthkit.autopsy.ingest.IngestServiceAbstractFile;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstract;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
@ -51,29 +52,31 @@ import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
* Ingests an image file and, if available, adds it's date, latitude, longitude,
* altitude, device model, and device make to a blackboard artifact.
*/
public final class ExifParserFileIngestService implements IngestServiceAbstractFile {
public final class ExifParserFileIngestModule implements IngestModuleAbstractFile {
private IngestServices services;
final String MODULE_NAME = "Exif Parser";
private static final Logger logger = Logger.getLogger(ExifParserFileIngestService.class.getName());
private static ExifParserFileIngestService defaultInstance = null;
private IngestManagerProxy managerProxy;
private static final Logger logger = Logger.getLogger(ExifParserFileIngestModule.class.getName());
private static ExifParserFileIngestModule defaultInstance = null;
private static int messageId = 0;
//file ingest services require a private constructor
//file ingest modules require a private constructor
//to ensure singleton instances
private ExifParserFileIngestService() {
private ExifParserFileIngestModule() {
}
//default instance used for service registration
public static synchronized ExifParserFileIngestService getDefault() {
//default instance used for module registration
public static synchronized ExifParserFileIngestModule getDefault() {
if (defaultInstance == null) {
defaultInstance = new ExifParserFileIngestService();
defaultInstance = new ExifParserFileIngestModule();
}
return defaultInstance;
}
@Override
public IngestServiceAbstractFile.ProcessResult process(AbstractFile content) {
public IngestModuleAbstractFile.ProcessResult process(AbstractFile content) {
if(content.getType().equals(TSK_DB_FILES_TYPE_ENUM.FS)) {
FsContent fsContent = (FsContent) content;
if(fsContent.isFile()) {
@ -83,10 +86,10 @@ public final class ExifParserFileIngestService implements IngestServiceAbstractF
}
}
return IngestServiceAbstractFile.ProcessResult.UNKNOWN;
return IngestModuleAbstractFile.ProcessResult.UNKNOWN;
}
public IngestServiceAbstractFile.ProcessResult processFile(FsContent f) {
public IngestModuleAbstractFile.ProcessResult processFile(FsContent f) {
InputStream in = null;
BufferedInputStream bin = null;
@ -144,10 +147,10 @@ public final class ExifParserFileIngestService implements IngestServiceAbstractF
bba.addAttributes(attributes);
}
return IngestServiceAbstractFile.ProcessResult.OK;
return IngestModuleAbstractFile.ProcessResult.OK;
} catch (TskCoreException ex) {
Logger.getLogger(ExifParserFileIngestService.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(ExifParserFileIngestModule.class.getName()).log(Level.SEVERE, null, ex);
} catch (ImageProcessingException ex) {
logger.log(Level.WARNING, "Failed to process the image.", ex);
} catch (IOException ex) {
@ -162,7 +165,7 @@ public final class ExifParserFileIngestService implements IngestServiceAbstractF
}
// If we got here, there was an error
return IngestServiceAbstractFile.ProcessResult.ERROR;
return IngestModuleAbstractFile.ProcessResult.ERROR;
}
private boolean parsableFormat(FsContent f) {
@ -185,9 +188,9 @@ public final class ExifParserFileIngestService implements IngestServiceAbstractF
logger.log(Level.INFO, "completed exif parsing " + this.toString());
final IngestMessage msg = IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Complete");
managerProxy.postMessage(msg);
services.postMessage(msg);
//service specific cleanup due to completion here
//module specific cleanup due to completion here
}
@Override
@ -201,23 +204,23 @@ public final class ExifParserFileIngestService implements IngestServiceAbstractF
}
@Override
public void init(IngestManagerProxy managerProxy) {
public void init(IngestModuleInit initContext) {
services = IngestServices.getDefault();
logger.log(Level.INFO, "init() " + this.toString());
this.managerProxy = managerProxy;
}
@Override
public void stop() {
logger.log(Level.INFO, "stop()");
managerProxy.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Stopped"));
services.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Stopped"));
//service specific cleanup due to interruption here
//module specific cleanup due to interruption here
}
@Override
public IngestServiceAbstract.ServiceType getType() {
return IngestServiceAbstract.ServiceType.AbstractFile;
public IngestModuleAbstract.ModuleType getType() {
return IngestModuleAbstract.ModuleType.AbstractFile;
}
@Override

View File

@ -2,9 +2,9 @@
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.2//EN" "http://www.netbeans.org/dtds/filesystem-1_2.dtd">
<filesystem>
<folder name="Services">
<file name="org-sleuthkit-autopsy-exifparser-ExifParserFileIngestService.instance">
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.ingest.IngestServiceAbstractFile"/>
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.exifparser.ExifParserFileIngestService.getDefault"/>
<file name="org-sleuthkit-autopsy-exifparser-ExifParserFileIngestModule.instance">
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile"/>
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.exifparser.ExifParserFileIngestModule.getDefault"/>
<attr name="position" intvalue="110"/>
</file>
</folder>

View File

@ -25,11 +25,11 @@ import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.IngestManagerProxy;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.IngestMessage;
import org.sleuthkit.autopsy.ingest.IngestServiceAbstractFile;
import org.sleuthkit.autopsy.ingest.ServiceDataEvent;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute;
@ -44,14 +44,14 @@ import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskException;
public class HashDbIngestService implements IngestServiceAbstractFile {
public class HashDbIngestModule implements IngestModuleAbstractFile {
private static HashDbIngestService instance = null;
private static HashDbIngestModule instance = null;
public final static String MODULE_NAME = "Hash Lookup";
public final static String MODULE_DESCRIPTION = "Identifies known and notables files using supplied hash databases, such as a standard NSRL database.";
private static final Logger logger = Logger.getLogger(HashDbIngestService.class.getName());
private static final Logger logger = Logger.getLogger(HashDbIngestModule.class.getName());
private Processor processor = new Processor();
private IngestManagerProxy managerProxy;
private IngestServices services;
private SleuthkitCase skCase;
private static int messageId = 0;
private int count;
@ -66,29 +66,24 @@ public class HashDbIngestService implements IngestServiceAbstractFile {
private Map<Integer, HashDb> knownBadSets = new HashMap<Integer, HashDb>();
private HashDbIngestService() {
private HashDbIngestModule() {
count = 0;
}
public static synchronized HashDbIngestService getDefault() {
public static synchronized HashDbIngestModule getDefault() {
if (instance == null) {
instance = new HashDbIngestService();
instance = new HashDbIngestModule();
}
return instance;
}
/**
* notification from manager that brand new processing should be initiated.
* Service loads its configuration and performs initialization
*
* @param managerProxy handle to the manager to postMessage() to
*/
@Override
public void init(IngestManagerProxy managerProxy) {
public void init(IngestModuleInit initContext) {
services = IngestServices.getDefault();
HashDbManagementPanel.getDefault().setIngestRunning(true);
HashDbSimplePanel.setIngestRunning(true);
this.managerProxy = managerProxy;
this.managerProxy.postMessage(IngestMessage.createMessage(++messageId, IngestMessage.MessageType.INFO, this, "Started"));
this.services.postMessage(IngestMessage.createMessage(++messageId, IngestMessage.MessageType.INFO, this, "Started"));
this.skCase = Case.getCurrentCase().getSleuthkitCase();
try {
HashDbXML hdbxml = HashDbXML.getCurrent();
@ -116,10 +111,10 @@ public class HashDbIngestService implements IngestServiceAbstractFile {
}
if (!nsrlIsSet) {
this.managerProxy.postMessage(IngestMessage.createWarningMessage(++messageId, this, "No NSRL database set", "Known file search will not be executed."));
this.services.postMessage(IngestMessage.createWarningMessage(++messageId, this, "No NSRL database set", "Known file search will not be executed."));
}
if (!knownBadIsSet) {
this.managerProxy.postMessage(IngestMessage.createWarningMessage(++messageId, this, "No known bad database set", "Known bad file search will not be executed."));
this.services.postMessage(IngestMessage.createWarningMessage(++messageId, this, "No known bad database set", "Known bad file search will not be executed."));
}
} catch (TskException ex) {
@ -127,10 +122,7 @@ public class HashDbIngestService implements IngestServiceAbstractFile {
}
}
/**
* notification from manager that there is no more content to process and all work is done.
* Service performs any clean-up, notifies viewers and may also write results to the black-board
*/
@Override
public void complete() {
StringBuilder detailsSb = new StringBuilder();
@ -156,7 +148,7 @@ public class HashDbIngestService implements IngestServiceAbstractFile {
}
detailsSb.append("</table>");
managerProxy.postMessage(IngestMessage.createMessage(++messageId, IngestMessage.MessageType.INFO, this, "Hash Ingest Complete", detailsSb.toString()));
services.postMessage(IngestMessage.createMessage(++messageId, IngestMessage.MessageType.INFO, this, "Hash Ingest Complete", detailsSb.toString()));
HashDbManagementPanel.getDefault().setIngestRunning(false);
HashDbSimplePanel.setIngestRunning(false);
@ -173,9 +165,9 @@ public class HashDbIngestService implements IngestServiceAbstractFile {
}
/**
* get specific name of the service
* should be unique across services, a user-friendly name of the service shown in GUI
* @return The name of this Ingest Service
* get specific name of the module
* should be unique across modules, a user-friendly name of the module shown in GUI
* @return The name of this Ingest Module
*/
@Override
public String getName() {
@ -199,8 +191,8 @@ public class HashDbIngestService implements IngestServiceAbstractFile {
}
@Override
public ServiceType getType() {
return ServiceType.AbstractFile;
public ModuleType getType() {
return ModuleType.AbstractFile;
}
@Override
@ -266,13 +258,13 @@ public class HashDbIngestService implements IngestServiceAbstractFile {
detailsSb.append("</table>");
managerProxy.postMessage(IngestMessage.createDataMessage(++messageId, this,
services.postMessage(IngestMessage.createDataMessage(++messageId, this,
"Notable: " + abstractFile.getName(),
detailsSb.toString(),
abstractFile.getName() + md5Hash,
badFile));
}
IngestManagerProxy.fireServiceDataEvent(new ServiceDataEvent(MODULE_NAME, ARTIFACT_TYPE.TSK_HASHSET_HIT, Collections.singletonList(badFile)));
services.fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, ARTIFACT_TYPE.TSK_HASHSET_HIT, Collections.singletonList(badFile)));
} catch (TskException ex) {
logger.log(Level.WARNING, "Error creating blackboard artifact", ex);
}
@ -293,11 +285,10 @@ public class HashDbIngestService implements IngestServiceAbstractFile {
private ProcessResult process(FsContent fsContent) {
ProcessResult ret = ProcessResult.UNKNOWN;
ProcessResult ret = ProcessResult.OK;
boolean processFile = true;
if (fsContent.getSize() == 0
|| fsContent.getKnown().equals(TskData.FileKnown.BAD)) {
ret = ProcessResult.OK;
processFile = false;
}
if (processFile && (nsrlIsSet || knownBadIsSet)) {
@ -322,7 +313,6 @@ public class HashDbIngestService implements IngestServiceAbstractFile {
String hashSetName = entry.getValue().getName();
processBadFile(fsContent, md5Hash, hashSetName, entry.getValue().getShowInboxMessages());
}
ret = ProcessResult.OK;
}
if (!foundBad && nsrlIsSet) {
long lookupstart = System.currentTimeMillis();
@ -330,17 +320,16 @@ public class HashDbIngestService implements IngestServiceAbstractFile {
lookuptime += (System.currentTimeMillis()-lookupstart);
if (status.equals(TskData.FileKnown.KNOWN)) {
skCase.setKnown(fsContent, status);
ret = ProcessResult.COND_STOP;
}
}
} catch (TskException ex) {
logger.log(Level.WARNING, "Couldn't analyze file " + name + " - see sleuthkit log for details", ex);
managerProxy.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestService.this, "Hash Lookup Error: " + name,
services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Hash Lookup Error: " + name,
"Error encountered while updating the hash values for " + name + "."));
ret = ProcessResult.ERROR;
} catch (IOException ex) {
logger.log(Level.WARNING, "Error reading file " + name, ex);
managerProxy.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestService.this, "Read Error: " + name,
services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Read Error: " + name,
"Error encountered while calculating the hash value for " + name + "."));
ret = ProcessResult.ERROR;
}
@ -357,7 +346,7 @@ public class HashDbIngestService implements IngestServiceAbstractFile {
}
catch (IOException ex) {
logger.log(Level.WARNING, "Error reading file " + name, ex);
managerProxy.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestService.this, "Read Error: " + name,
services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Read Error: " + name,
"Error encountered while calculating the hash value for " + name + " without databases."));
}
}

View File

@ -40,9 +40,9 @@
</folder>
</folder>
<folder name="Services">
<file name="org-sleuthkit-autopsy-hashdatabase-HashDbIngestService.instance">
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.ingest.IngestServiceAbstractFile"/>
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.hashdatabase.HashDbIngestService.getDefault"/>
<file name="org-sleuthkit-autopsy-hashdatabase-HashDbIngestModule.instance">
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile"/>
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.hashdatabase.HashDbIngestModule.getDefault"/>
<attr name="position" intvalue="200"/>
</file>
</folder>

View File

@ -7,14 +7,14 @@ HINT_IngestTopComponent=Ingest window
OpenIDE-Module-Name=Ingest
IngestTopComponent.messageFrame.title=Messages
IngestTopComponent.ingestProgressLabel.text=File Ingest Progress
IngestControlPanel.topLable.text=Image ingest services
IngestControlPanel.topLable.text=Image ingest modules
IngestControlPanel.startButton.text=Start
IngestDialogPanel.ingestServicesLabel.text=Image Ingest Services
IngestDialogPanel.ingestServicesLabel.text=Image Ingest Modules
IngestDialogForm2.okButton.text=OK
IngestDialogForm2.cancelButton.text=Cancel
IngestDialogForm.cancelButton.text=Cancel
IngestDialogForm.startButton.text=Start
IngestDialogForm.jLabel1.text=Ingest Services
IngestDialogForm.jLabel1.text=Ingest Modules
IngestTopComponent.refreshFreqLabel.text=Refresh frequency
IngestMessageDetailsPanel.backButton.text=
IngestMessageDetailsPanel.viewArtifactButton.text=Go to Result

View File

@ -28,7 +28,7 @@
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="servicesScrollPane" max="32767" attributes="1"/>
<Component id="modulesScrollPane" max="32767" attributes="1"/>
<Component id="timePanel" alignment="0" max="32767" attributes="1"/>
<Component id="processUnallocPanel" alignment="0" max="32767" attributes="0"/>
</Group>
@ -45,7 +45,7 @@
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jPanel1" pref="235" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="servicesScrollPane" pref="0" max="32767" attributes="0"/>
<Component id="modulesScrollPane" pref="0" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="processUnallocPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
@ -58,7 +58,7 @@
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="servicesScrollPane">
<Container class="javax.swing.JScrollPane" name="modulesScrollPane">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo">
@ -74,7 +74,7 @@
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTable" name="servicesTable">
<Component class="javax.swing.JTable" name="modulesTable">
<Properties>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="f0" green="f0" red="f0" type="rgb"/>
@ -180,17 +180,10 @@
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Component id="timeRadioButton1" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="timeLabel" min="-2" max="-2" attributes="0"/>
<Component id="timeRadioButton2" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="timeRadioButton3" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Component id="timeRadioButton1" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="timeLabel" min="-2" max="-2" attributes="0"/>
<Component id="timeRadioButton2" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="timeRadioButton3" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>

View File

@ -44,15 +44,15 @@ import org.sleuthkit.autopsy.ingest.IngestManager.UpdateFrequency;
import org.sleuthkit.datamodel.Image;
/**
* main configuration panel for all ingest services, reusable JPanel component
* main configuration panel for all ingest modules, reusable JPanel component
*/
public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfigurator {
private IngestManager manager = null;
private List<IngestServiceAbstract> services;
private IngestServiceAbstract currentService;
private Map<String, Boolean> serviceStates;
private ServicesTableModel tableModel;
private List<IngestModuleAbstract> modules;
private IngestModuleAbstract currentModule;
private Map<String, Boolean> moduleStates;
private ModulesTableModel tableModel;
private static final Logger logger = Logger.getLogger(IngestDialogPanel.class.getName());
// The image that's just been added to the database
private Image image;
@ -60,9 +60,9 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
/** Creates new form IngestDialogPanel */
private IngestDialogPanel() {
tableModel = new ServicesTableModel();
services = new ArrayList<IngestServiceAbstract>();
serviceStates = new HashMap<String, Boolean>();
tableModel = new ModulesTableModel();
modules = new ArrayList<IngestModuleAbstract>();
moduleStates = new HashMap<String, Boolean>();
initComponents();
customizeComponents();
}
@ -75,15 +75,15 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
}
private void customizeComponents() {
servicesTable.setModel(tableModel);
modulesTable.setModel(tableModel);
this.manager = IngestManager.getDefault();
Collection<IngestServiceImage> imageServices = IngestManager.enumerateImageServices();
for (final IngestServiceImage service : imageServices) {
addService(service);
Collection<IngestModuleImage> imageModules = IngestManager.enumerateImageModules();
for (final IngestModuleImage module : imageModules) {
addModule(module);
}
Collection<IngestServiceAbstractFile> fsServices = IngestManager.enumerateAbstractFileServices();
for (final IngestServiceAbstractFile service : fsServices) {
addService(service);
Collection<IngestModuleAbstractFile> fsModules = IngestManager.enumerateAbstractFileModules();
for (final IngestModuleAbstractFile module : fsModules) {
addModule(module);
}
//time setting
@ -113,17 +113,17 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
//
}
servicesTable.setTableHeader(null);
servicesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
modulesTable.setTableHeader(null);
modulesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
//custom renderer for tooltips
ServiceTableRenderer renderer = new ServiceTableRenderer();
ModulesTableRenderer renderer = new ModulesTableRenderer();
//customize column witdhs
final int width = servicesScrollPane.getPreferredSize().width;
final int width = modulesScrollPane.getPreferredSize().width;
TableColumn column = null;
for (int i = 0; i < servicesTable.getColumnCount(); i++) {
column = servicesTable.getColumnModel().getColumn(i);
for (int i = 0; i < modulesTable.getColumnCount(); i++) {
column = modulesTable.getColumnModel().getColumn(i);
if (i == 0) {
column.setPreferredWidth(((int) (width * 0.15)));
} else {
@ -132,7 +132,7 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
}
}
servicesTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
modulesTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
@ -140,11 +140,11 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
if (!listSelectionModel.isSelectionEmpty()) {
save();
int index = listSelectionModel.getMinSelectionIndex();
currentService = services.get(index);
currentModule = modules.get(index);
reloadSimpleConfiguration();
advancedButton.setEnabled(currentService.hasAdvancedConfiguration());
advancedButton.setEnabled(currentModule.hasAdvancedConfiguration());
} else {
currentService = null;
currentModule = null;
}
}
});
@ -176,10 +176,10 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
}
}
private void addService(IngestServiceAbstract service) {
final String serviceName = service.getName();
services.add(service);
serviceStates.put(serviceName, true);
private void addModule(IngestModuleAbstract module) {
final String moduleName = module.getName();
modules.add(module);
moduleStates.put(moduleName, true);
}
/** This method is called from within the constructor to
@ -192,8 +192,8 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
private void initComponents() {
timeGroup = new javax.swing.ButtonGroup();
servicesScrollPane = new javax.swing.JScrollPane();
servicesTable = new javax.swing.JTable();
modulesScrollPane = new javax.swing.JScrollPane();
modulesTable = new javax.swing.JTable();
jPanel1 = new javax.swing.JPanel();
advancedButton = new javax.swing.JButton();
jSeparator2 = new javax.swing.JSeparator();
@ -209,11 +209,11 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
setPreferredSize(new java.awt.Dimension(522, 257));
servicesScrollPane.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(160, 160, 160)));
servicesScrollPane.setPreferredSize(new java.awt.Dimension(160, 160));
modulesScrollPane.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(160, 160, 160)));
modulesScrollPane.setPreferredSize(new java.awt.Dimension(160, 160));
servicesTable.setBackground(new java.awt.Color(240, 240, 240));
servicesTable.setModel(new javax.swing.table.DefaultTableModel(
modulesTable.setBackground(new java.awt.Color(240, 240, 240));
modulesTable.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] {
},
@ -221,9 +221,9 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
}
));
servicesTable.setShowHorizontalLines(false);
servicesTable.setShowVerticalLines(false);
servicesScrollPane.setViewportView(servicesTable);
modulesTable.setShowHorizontalLines(false);
modulesTable.setShowVerticalLines(false);
modulesScrollPane.setViewportView(modulesTable);
jPanel1.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(160, 160, 160)));
jPanel1.setPreferredSize(new java.awt.Dimension(338, 257));
@ -290,14 +290,10 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
.addGroup(timePanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(timePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(timePanelLayout.createSequentialGroup()
.addGap(0, 0, 0)
.addComponent(timeRadioButton1))
.addGroup(timePanelLayout.createSequentialGroup()
.addGroup(timePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(timeLabel)
.addComponent(timeRadioButton2)
.addComponent(timeRadioButton3))))
.addComponent(timeRadioButton1)
.addComponent(timeLabel)
.addComponent(timeRadioButton2)
.addComponent(timeRadioButton3))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
timePanelLayout.setVerticalGroup(
@ -347,7 +343,7 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(servicesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(modulesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(timePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(processUnallocPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@ -361,7 +357,7 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 235, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(servicesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
.addComponent(modulesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(processUnallocPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@ -377,11 +373,11 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
@Override
public void actionPerformed(ActionEvent e) {
dialog.close();
currentService.saveAdvancedConfiguration();
currentModule.saveAdvancedConfiguration();
reloadSimpleConfiguration();
}
});
dialog.display(currentService.getAdvancedConfiguration());
dialog.display(currentModule.getAdvancedConfiguration());
}//GEN-LAST:event_advancedButtonActionPerformed
private void timeRadioButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_timeRadioButton1ActionPerformed
@ -397,10 +393,10 @@ private void timeRadioButton1ActionPerformed(java.awt.event.ActionEvent evt) {//
private javax.swing.JPanel jPanel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JSeparator jSeparator2;
private javax.swing.JScrollPane modulesScrollPane;
private javax.swing.JTable modulesTable;
private javax.swing.JCheckBox processUnallocCheckbox;
private javax.swing.JPanel processUnallocPanel;
private javax.swing.JScrollPane servicesScrollPane;
private javax.swing.JTable servicesTable;
private javax.swing.JPanel simplePanel;
private javax.swing.ButtonGroup timeGroup;
private javax.swing.JLabel timeLabel;
@ -410,11 +406,11 @@ private void timeRadioButton1ActionPerformed(java.awt.event.ActionEvent evt) {//
private javax.swing.JRadioButton timeRadioButton3;
// End of variables declaration//GEN-END:variables
private class ServicesTableModel extends AbstractTableModel {
private class ModulesTableModel extends AbstractTableModel {
@Override
public int getRowCount() {
return services.size();
return modules.size();
}
@Override
@ -424,9 +420,9 @@ private void timeRadioButton1ActionPerformed(java.awt.event.ActionEvent evt) {//
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
String name = services.get(rowIndex).getName();
String name = modules.get(rowIndex).getName();
if (columnIndex == 0) {
return serviceStates.get(name);
return moduleStates.get(name);
} else {
return name;
}
@ -440,7 +436,7 @@ private void timeRadioButton1ActionPerformed(java.awt.event.ActionEvent evt) {//
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (columnIndex == 0) {
serviceStates.put((String) getValueAt(rowIndex, 1), (Boolean) aValue);
moduleStates.put((String) getValueAt(rowIndex, 1), (Boolean) aValue);
}
}
@ -451,15 +447,15 @@ private void timeRadioButton1ActionPerformed(java.awt.event.ActionEvent evt) {//
}
}
List<IngestServiceAbstract> getServicesToStart() {
List<IngestServiceAbstract> servicesToStart = new ArrayList<IngestServiceAbstract>();
for (IngestServiceAbstract service : services) {
boolean serviceEnabled = serviceStates.get(service.getName());
if (serviceEnabled) {
servicesToStart.add(service);
List<IngestModuleAbstract> getModulesToStart() {
List<IngestModuleAbstract> modulesToStart = new ArrayList<IngestModuleAbstract>();
for (IngestModuleAbstract module : modules) {
boolean moduleEnabled = moduleStates.get(module.getName());
if (moduleEnabled) {
modulesToStart.add(module);
}
}
return servicesToStart;
return modulesToStart;
}
private boolean timeSelectionEnabled() {
@ -482,8 +478,8 @@ private void timeRadioButton1ActionPerformed(java.awt.event.ActionEvent evt) {//
private void reloadSimpleConfiguration() {
simplePanel.removeAll();
if (currentService.hasSimpleConfiguration()) {
simplePanel.add(currentService.getSimpleConfiguration());
if (currentModule.hasSimpleConfiguration()) {
simplePanel.add(currentModule.getSimpleConfiguration());
}
simplePanel.revalidate();
simplePanel.repaint();
@ -495,8 +491,8 @@ private void timeRadioButton1ActionPerformed(java.awt.event.ActionEvent evt) {//
*/
@Override
public void save() {
if (currentService != null && currentService.hasSimpleConfiguration()) {
currentService.saveSimpleConfiguration();
if (currentModule != null && currentModule.hasSimpleConfiguration()) {
currentModule.saveSimpleConfiguration();
}
}
@ -512,11 +508,11 @@ private void timeRadioButton1ActionPerformed(java.awt.event.ActionEvent evt) {//
@Override
public void start() {
//pick the services
List<IngestServiceAbstract> servicesToStart = getServicesToStart();
//pick the modules
List<IngestModuleAbstract> modulesToStart = getModulesToStart();
if (!servicesToStart.isEmpty()) {
manager.execute(servicesToStart, image);
if (!modulesToStart.isEmpty()) {
manager.execute(modulesToStart, image);
}
//update ingest freq. refresh
@ -537,9 +533,9 @@ private void timeRadioButton1ActionPerformed(java.awt.event.ActionEvent evt) {//
/**
* Custom cell renderer for tooltips with service description
* Custom cell renderer for tooltips with module description
*/
private class ServiceTableRenderer extends DefaultTableCellRenderer {
private class ModulesTableRenderer extends DefaultTableCellRenderer {
@Override
public Component getTableCellRendererComponent(
@ -550,10 +546,10 @@ private void timeRadioButton1ActionPerformed(java.awt.event.ActionEvent evt) {//
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (column == 1) {
//String serviceName = (String) table.getModel().getValueAt(row, column);
IngestServiceAbstract service = services.get(row);
String serviceDescr = service.getDescription();
setToolTipText(serviceDescr);
//String moduleName = (String) table.getModel().getValueAt(row, column);
IngestModuleAbstract module = modules.get(row);
String moduleDescr = module.getDescription();
setToolTipText(moduleDescr);
}

View File

@ -31,42 +31,42 @@ import org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent;
import org.sleuthkit.datamodel.Image;
/**
* worker for every ingest image service there is a separate instance per image
* / service pair
* worker for every ingest image module there is a separate instance per image
* / module pair
*/
public class IngestImageThread extends SwingWorker<Object, Void> {
private Logger logger = Logger.getLogger(IngestImageThread.class.getName());
private ProgressHandle progress;
private Image image;
private IngestServiceImage service;
private IngestModuleImage module;
private IngestImageWorkerController controller;
private IngestManager manager;
IngestImageThread(IngestManager manager, Image image, IngestServiceImage service) {
IngestImageThread(IngestManager manager, Image image, IngestModuleImage module) {
this.manager = manager;
this.image = image;
this.service = service;
this.module = module;
}
Image getImage() {
return image;
}
IngestServiceImage getService() {
return service;
IngestModuleImage getModule() {
return module;
}
@Override
protected Object doInBackground() throws Exception {
logger.log(Level.INFO, "Starting processing of service: " + service.getName());
logger.log(Level.INFO, "Starting processing of module: " + module.getName());
final String displayName = service.getName() + " image id:" + image.getId();
final String displayName = module.getName() + " image id:" + image.getId();
progress = ProgressHandleFactory.createHandle(displayName, new Cancellable() {
@Override
public boolean cancel() {
logger.log(Level.INFO, "Image ingest service " + service.getName() + " cancelled by user.");
logger.log(Level.INFO, "Image ingest module " + module.getName() + " cancelled by user.");
if (progress != null) {
progress.setDisplayName(displayName + " (Cancelling...)");
}
@ -80,18 +80,18 @@ public class IngestImageThread extends SwingWorker<Object, Void> {
controller = new IngestImageWorkerController(this, progress);
if (isCancelled()) {
logger.log(Level.INFO, "Terminating image ingest service " + service.getName() + " due to cancellation.");
logger.log(Level.INFO, "Terminating image ingest module " + module.getName() + " due to cancellation.");
return null;
}
final StopWatch timer = new StopWatch();
timer.start();
try {
service.process(image, controller);
module.process(image, controller);
} catch (Exception e) {
logger.log(Level.WARNING, "Exception in service: " + service.getName() + " image: " + image.getName(), e);
logger.log(Level.WARNING, "Exception in module: " + module.getName() + " image: " + image.getName(), e);
} finally {
timer.stop();
logger.log(Level.INFO, "Done processing of service: " + service.getName()
logger.log(Level.INFO, "Done processing of module: " + module.getName()
+ " took " + timer.getElapsedTimeSecs() + " secs. to process()" );
EventQueue.invokeLater(new Runnable() {
@ -102,27 +102,27 @@ public class IngestImageThread extends SwingWorker<Object, Void> {
});
//cleanup queues (worker and image/service)
//cleanup queues (worker and image/module)
manager.removeImageIngestWorker(this);
if (!this.isCancelled()) {
logger.log(Level.INFO, "Service " + service.getName() + " completed");
logger.log(Level.INFO, "Module " + module.getName() + " completed");
try {
service.complete();
module.complete();
}
catch (Exception e) {
logger.log(Level.INFO, "Error completing the service " + service.getName(), e);
logger.log(Level.INFO, "Error completing the module " + module.getName(), e);
}
IngestManager.fireServiceEvent(IngestModuleEvent.COMPLETED.toString(), service.getName());
IngestManager.fireModuleEvent(IngestModuleEvent.COMPLETED.toString(), module.getName());
} else {
logger.log(Level.INFO, "Service " + service.getName() + " stopped");
logger.log(Level.INFO, "Module " + module.getName() + " stopped");
try {
service.stop();
module.stop();
}
catch (Exception e) {
logger.log(Level.INFO, "Error stopping the service" + service.getName(), e);
logger.log(Level.INFO, "Error stopping the module" + module.getName(), e);
}
IngestManager.fireServiceEvent(IngestModuleEvent.STOPPED.toString(), service.getName());
IngestManager.fireModuleEvent(IngestModuleEvent.STOPPED.toString(), module.getName());
}
}

View File

@ -21,8 +21,8 @@ package org.sleuthkit.autopsy.ingest;
import org.netbeans.api.progress.ProgressHandle;
/**
* Controller for image level ingest services
* Used by services to check task status and to post progress to
* Controller for image level ingest modules
* Used by modules to check task status and to post progress to
*/
public class IngestImageWorkerController {
@ -40,8 +40,8 @@ public class IngestImageWorkerController {
}
/**
* Check if the task has been cancelled. This should be polled by the service periodically
* And the service needs to act, i.e. break out of its processing loop and call its stop() to cleanup
* Check if the task has been cancelled. This should be polled by the module periodically
* And the module needs to act, i.e. break out of its processing loop and call its stop() to cleanup
*
* @return true if the task has been cancelled, false otherwise
*/
@ -70,7 +70,7 @@ public class IngestImageWorkerController {
/**
* Update the progress bar with the number of work units performed, if in the determinate mode
* @param workUnits number of work units performed so far by the service
* @param workUnits number of work units performed so far by the module
*/
public void progress(int workUnits) {
if (progress != null) {

File diff suppressed because it is too large Load Diff

View File

@ -1,94 +0,0 @@
/*
* 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.ingest;
/**
* Ingest manager facade used by ingest services
*
* Facility for services to interact with the ingest manager
* for sending data events, ingest messages, getting configuration, such as
* update frequency configuration
*
*/
public class IngestManagerProxy {
private IngestManager manager;
IngestManagerProxy(IngestManager manager) {
this.manager = manager;
}
/**
* Post ingest message
* @param message ingest message to be posted by ingest service
*/
public void postMessage(final IngestMessage message) {
manager.postMessage(message);
}
/**
* Fire service event to notify registered service event listeners
* @param eventType the event type, defined in IngestManager.IngestManagerEvents
* @param serviceName the service name
*/
public static void fireServiceEvent(String eventType, String serviceName) {
IngestManager.fireServiceEvent(eventType, serviceName);
}
/**
* Fire service data event to notify registered service data event listeners
* @param serviceDataEvent service data event, encapsulating blackboard artifact data
*/
public static void fireServiceDataEvent(ServiceDataEvent serviceDataEvent) {
IngestManager.fireServiceDataEvent(serviceDataEvent);;
}
/**
* Facility for the service to query the currently set recommended data update frequency in minutes
* Services that post data in controlled time intervals, should obey this setting
*
* @return max. number of minutes before service posts new data, if data is available
*/
public int getUpdateFrequency() {
return manager.getUpdateFrequency().getTime();
}
/**
* Facility for a file ingest service to check a return value from another file ingest service
* that executed for the same file earlier in the file ingest pipeline
* The service return value can be used as a guideline to skip processing the file
*
* @param serviceName registered service name of the service to check the return value of
* @return the return value of the previously executed service for the currently processed file in the file ingest pipeline
*/
public IngestServiceAbstractFile.ProcessResult getAbstractFileServiceResult(String serviceName) {
return manager.getAbstractFileServiceResult(serviceName);
}
}

View File

@ -24,7 +24,7 @@ import org.sleuthkit.autopsy.datamodel.KeyValue;
import org.sleuthkit.datamodel.BlackboardArtifact;
/**
* Representation of subject posted by ingest services
* Representation of subject posted by ingest modules
*
* Message should have a unique ID within context of originating source
*
@ -37,7 +37,7 @@ public class IngestMessage {
};
private long ID;
private MessageType messageType;
private IngestServiceAbstract source;
private IngestModuleAbstract source;
private String subject;
private String detailsHtml;
private String uniqueKey;
@ -46,7 +46,7 @@ public class IngestMessage {
private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static int managerMessageId = 0;
private IngestMessage(long ID, MessageType messageType, IngestServiceAbstract source, String subject, String detailsHtml, String uniqueKey) {
private IngestMessage(long ID, MessageType messageType, IngestModuleAbstract source, String subject, String detailsHtml, String uniqueKey) {
this.ID = ID;
this.source = source;
this.messageType = messageType;
@ -63,7 +63,7 @@ public class IngestMessage {
return ID;
}
public IngestServiceAbstract getSource() {
public IngestModuleAbstract getSource() {
return source;
}
@ -163,12 +163,12 @@ public class IngestMessage {
* Create a simple message with a subject only
* @param ID ID of the message, unique in the context of module that generated it
* @param messageType message type
* @param source originating service
* @param source originating module
* @param subject message subject to be displayed
* @param details message details to be displayed, or null
* @return
*/
public static IngestMessage createMessage(long ID, MessageType messageType, IngestServiceAbstract source, String subject, String details) {
public static IngestMessage createMessage(long ID, MessageType messageType, IngestModuleAbstract source, String subject, String details) {
if (messageType == null || source == null || subject == null) {
throw new IllegalArgumentException("message type, source and subject cannot be null");
}
@ -179,11 +179,11 @@ public class IngestMessage {
* Create a simple message with a subject only
* @param ID ID of the message, unique in the context of module that generated it
* @param messageType message type
* @param source originating service
* @param source originating module
* @param subject message subject to be displayed
* @return
*/
public static IngestMessage createMessage(long ID, MessageType messageType, IngestServiceAbstract source, String subject) {
public static IngestMessage createMessage(long ID, MessageType messageType, IngestModuleAbstract source, String subject) {
return createMessage(ID, messageType, source, subject, null);
}
@ -191,12 +191,12 @@ public class IngestMessage {
/**
* Create error message
* @param ID ID of the message, unique in the context of module that generated it
* @param source originating service
* @param source originating module
* @param subject message subject to be displayed
* @param details message details to be displayed, or null
* @return
*/
public static IngestMessage createErrorMessage(long ID, IngestServiceAbstract source, String subject, String details) {
public static IngestMessage createErrorMessage(long ID, IngestModuleAbstract source, String subject, String details) {
if (source == null || subject == null) {
throw new IllegalArgumentException("source and subject cannot be null");
}
@ -206,12 +206,12 @@ public class IngestMessage {
/**
* Create warning message
* @param ID ID of the message, unique in the context of module that generated it
* @param source originating service
* @param source originating module
* @param subject message subject to be displayed
* @param details message details to be displayed, or null
* @return
*/
public static IngestMessage createWarningMessage(long ID, IngestServiceAbstract source, String subject, String details) {
public static IngestMessage createWarningMessage(long ID, IngestModuleAbstract source, String subject, String details) {
if (source == null || subject == null) {
throw new IllegalArgumentException("source and subject cannot be null");
}
@ -221,14 +221,14 @@ public class IngestMessage {
/**
*
* @param ID ID of the message, unique in the context of module that generated it
* @param source originating service
* @param source originating module
* @param subject message subject to be displayed
* @param detailsHtml html formatted detailed message (without leading and closing &lt;html&gt; tags), for instance, a human-readable representation of the data.
* @param uniqueKey unique key determining uniqueness of the message, or null. Helps grouping similar messages and determine their importance. Subsequent messages with the same uniqueKey will be treated with lower priority.
* @param data data blackboard artifact associated with the message, the same as fired in ServiceDataEvent by the service
* @param data data blackboard artifact associated with the message, the same as fired in ModuleDataEvent by the module
* @return
*/
public static IngestMessage createDataMessage(long ID, IngestServiceAbstract source, String subject, String detailsHtml, String uniqueKey, BlackboardArtifact data) {
public static IngestMessage createDataMessage(long ID, IngestModuleAbstract source, String subject, String detailsHtml, String uniqueKey, BlackboardArtifact data) {
if (source == null || subject == null || detailsHtml == null || data == null) {
throw new IllegalArgumentException("source, subject, details and data cannot be null");
}

View File

@ -45,7 +45,7 @@ import org.sleuthkit.autopsy.ingest.IngestMessage.*;
import org.sleuthkit.datamodel.BlackboardArtifact;
/**
* Notification window showing messages from services to user
* Notification window showing messages from modules to user
*
*/
class IngestMessagePanel extends javax.swing.JPanel {
@ -62,7 +62,7 @@ class IngestMessagePanel extends javax.swing.JPanel {
private enum COLUMN {
SUBJECT, COUNT, SERVICE
SUBJECT, COUNT, MODULE
};
private static PropertyChangeSupport messagePcs = new PropertyChangeSupport(IngestMessagePanel.class);
static final String MESSAGE_CHANGE_EVT = "MESSAGE_CHANGE_EVT"; //number of unread messages changed
@ -320,10 +320,10 @@ class IngestMessagePanel extends javax.swing.JPanel {
//data
private List<TableEntry> messageData = new ArrayList<TableEntry>();
//for keeping track of messages to group, per service, by uniqness
private Map<IngestServiceAbstract, Map<String, List<IngestMessageGroup>>> groupings = new HashMap<IngestServiceAbstract, Map<String, List<IngestMessageGroup>>>();
//for keeping track of messages to group, per module, by uniqness
private Map<IngestModuleAbstract, Map<String, List<IngestMessageGroup>>> groupings = new HashMap<IngestModuleAbstract, Map<String, List<IngestMessageGroup>>>();
private boolean chronoSort = true; //chronological sort default
private static final int MESSAGE_GROUP_THRESH = 3; //group messages after 3 messages per service with same uniqness
private static final int MESSAGE_GROUP_THRESH = 3; //group messages after 3 messages per module with same uniqness
private Logger logger = Logger.getLogger(MessageTableModel.class.getName());
MessageTableModel() {
@ -331,12 +331,12 @@ class IngestMessagePanel extends javax.swing.JPanel {
}
private void init() {
//initialize groupings map with services
for (IngestServiceAbstract service : IngestManager.enumerateAbstractFileServices()) {
groupings.put(service, new HashMap<String, List<IngestMessageGroup>>());
//initialize groupings map with modules
for (IngestModuleAbstract module : IngestManager.enumerateAbstractFileModules()) {
groupings.put(module, new HashMap<String, List<IngestMessageGroup>>());
}
for (IngestServiceAbstract service : IngestManager.enumerateImageServices()) {
groupings.put(service, new HashMap<String, List<IngestMessageGroup>>());
for (IngestModuleAbstract module : IngestManager.enumerateImageModules()) {
groupings.put(module, new HashMap<String, List<IngestMessageGroup>>());
}
}
@ -418,8 +418,8 @@ class IngestMessagePanel extends javax.swing.JPanel {
switch (columnIndex) {
case 0:
Object service = entry.messageGroup.getSource();
if (service == null) {
Object module = entry.messageGroup.getSource();
if (module == null) {
ret = "";
} else {
ret = (Object) entry.messageGroup.getSource().getName();
@ -462,13 +462,13 @@ class IngestMessagePanel extends javax.swing.JPanel {
}
synchronized public void addMessage(IngestMessage m) {
//check how many messages per service with the same uniqness
//check how many messages per module with the same uniqness
//and add to existing group or create a new group
IngestServiceAbstract service = m.getSource();
IngestModuleAbstract module = m.getSource();
IngestMessageGroup messageGroup = null;
if (service != null && m.getMessageType() == IngestMessage.MessageType.DATA) {
if (module != null && m.getMessageType() == IngestMessage.MessageType.DATA) {
//not a manager message, a data message, then group
final Map<String, List<IngestMessageGroup>> groups = groupings.get(service);
final Map<String, List<IngestMessageGroup>> groups = groupings.get(module);
//groups for this uniqueness
final String uniqueness = m.getUniqueKey();
List<IngestMessageGroup> uniqGroups = groups.get(uniqueness);
@ -732,9 +732,9 @@ class IngestMessagePanel extends javax.swing.JPanel {
}
/*
* return source service, should be the same for all msgs
* return source module, should be the same for all msgs
*/
IngestServiceAbstract getSource() {
IngestModuleAbstract getSource() {
return messages.get(0).getSource();
}

View File

@ -280,7 +280,7 @@ public final class IngestMessageTopComponent extends TopComponent implements Ing
}
/**
* Display IngestMessage from service (forwarded by IngestManager)
* Display IngestMessage from module (forwarded by IngestManager)
*/
@Override
public void displayMessage(IngestMessage ingestMessage) {

View File

@ -16,17 +16,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
import java.awt.Component;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import org.openide.util.actions.Presenter;
import org.openide.windows.Mode;
import org.openide.windows.WindowManager;
//@ActionID(category = "File",
//id = "org.sleuthkit.autopsy.ingest.IngestMessagesAction")
@ -36,15 +31,14 @@ import org.openide.windows.WindowManager;
// @ActionReference(path = "Toolbars/File", position = 575)
//})
//@Messages("CTL_IngestMessagesAction=Messages")
public final class IngestMessagesAction extends AbstractAction implements Presenter.Toolbar {
public final class IngestMessagesAction extends AbstractAction implements Presenter.Toolbar {
@Override
public void actionPerformed(ActionEvent e) {
}
@Override
public Component getToolbarPresenter() {
return new IngestMessagesToolbar();
return IngestMessagesToolbar.getDefault();
}
}

View File

@ -1,4 +1,4 @@
<?xml version="1.1" encoding="UTF-8" ?>
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Properties>

View File

@ -37,17 +37,30 @@ import org.sleuthkit.autopsy.casemodule.Case;
public class IngestMessagesToolbar extends javax.swing.JPanel {
private IngestMessagesButton ingestMessagesButton = new IngestMessagesButton();
private static IngestMessagesToolbar instance;
/** Creates new form IngestMessagesToolbar */
public IngestMessagesToolbar() {
/**
* Creates new form IngestMessagesToolbar
*/
private IngestMessagesToolbar() {
initComponents();
customizeComponents();
}
/** 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.
/**
* @return the default instance IngestMessagesToolbar
*/
public static IngestMessagesToolbar getDefault() {
if (instance == null) {
instance = new IngestMessagesToolbar();
}
return instance;
}
/**
* 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")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
@ -82,7 +95,6 @@ public class IngestMessagesToolbar extends javax.swing.JPanel {
ingestMessagesButton.setMinimumSize(new java.awt.Dimension(38, 24));
ingestMessagesButton.setPreferredSize(new java.awt.Dimension(38, 24));
ingestMessagesButton.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent evt) {
showIngestMessages();
@ -98,7 +110,6 @@ public class IngestMessagesToolbar extends javax.swing.JPanel {
this.setBorder(null);
IngestMessagePanel.addPropertyChangeSupportListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
final int numberMessages = (Integer) evt.getNewValue();
@ -110,7 +121,6 @@ public class IngestMessagesToolbar extends javax.swing.JPanel {
});
Case.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(Case.CASE_CURRENT_CASE)) {
@ -140,7 +150,6 @@ public class IngestMessagesToolbar extends javax.swing.JPanel {
private static class IngestMessagesButton extends JButton {
private static final int fontSize = 9;
private static final Font messagesFont = new java.awt.Font("Tahoma", Font.PLAIN, fontSize);
private int messages = 0;
@ -149,8 +158,9 @@ public class IngestMessagesToolbar extends javax.swing.JPanel {
public void paint(Graphics g) {
super.paint(g);
if (messages == 0)
if (messages == 0) {
return;
}
//paint text
String messageStr = Integer.toString(messages);
final int len = messageStr.length();
@ -158,13 +168,14 @@ public class IngestMessagesToolbar extends javax.swing.JPanel {
int dx = len * 5 + 5;
int x = getSize().width - dx;
if (x<0)
if (x < 0) {
x = 0;
}
g.setColor(Color.GRAY);
//g.fillRect(x, 1, dx, fontSize);
g.fillRoundRect(x, 1, dx, fontSize, 2, 2);
g.setColor(Color.WHITE);
g.drawString(messageStr, x+2, fontSize);
g.drawString(messageStr, x + 2, fontSize);
}
void setMessages(int messages) {

View File

@ -21,75 +21,77 @@ package org.sleuthkit.autopsy.ingest;
/**
* Base interface for ingest services
* Base interface for ingest modules
*/
public interface IngestServiceAbstract {
public interface IngestModuleAbstract {
/**
* Possible service types for the implementing classes
* Possible module types for the implementing classes
*/
public enum ServiceType {
public enum ModuleType {
/**
* Image type service
* Image type module
*/
Image,
/**
* AbstractFile type service
* AbstractFile type module
*/
AbstractFile
};
/**
* Notification from manager that brand new ingest should be initiated.
* Service loads its configuration and performs initialization
* Invoked once per new worker thread, per ingest
*
* @param managerProxy manager facade that can be used by the service to communicate with the manager, e.g.
* for posting messages, getting configurations
* Notification from manager that brand new ingest should be initiated..
* Module loads its configuration and performs initialization.
* Invoked once per new worker thread, per ingest.
* In this method initialize always IngestServices handle
* using IngestServices.getDefault() lazy-loading approach.
* NEVER initialize IngestServices handle in the member declaration, because it might result
* in multiple instances of the singleton -- different class loaders are used in different modules.
* @param initContext context used to initialize some modules
*/
public void init(IngestManagerProxy managerProxy);
public void init(IngestModuleInit initContext);
/**
* Notification from manager that there is no more content to process and all work is done.
* Service performs any clean-up of internal resources, and finalizes processing to produce complete result
* Service also posts ingest message indicating it is done, and posts ingest stats and errors in the details of the message.
* Module performs any clean-up of internal resources, and finalizes processing to produce complete result
* Module also posts ingest message indicating it is done, and posts ingest stats and errors in the details of the message.
*/
public void complete();
/**
* Notification from manager to stop processing due to some interruption (user, error, exception)
* Service performs any clean-up of internal resources
* Module performs any clean-up of internal resources
* It may also discard any pending results, but it should ensure it is in a defined state so that ingest can be rerun later.
*/
public void stop();
/**
* Gets specific name of the service
* The name should be unique across services
* @return unique service name
* Gets specific name of the module
* The name should be unique across modules
* @return unique module name
*/
public String getName();
/**
* Gets user-friendly description of the service
* @return service description
* Gets user-friendly description of the module
* @return module description
*/
public String getDescription();
/**
* Returns type of the service
* @return service type
* Returns type of the module
* @return module type
*/
public ServiceType getType();
public ModuleType getType();
/**
* A service can manage and use additional threads to perform some work in the background.
* This method provides insight to the manager if the service has truly completed its work or not.
* A module can manage and use additional threads to perform some work in the background.
* This method provides insight to the manager if the module has truly completed its work or not.
*
*
* @return true if any background threads/workers managed by this service are still running or are pending to be run,
* false if all work has been done, or if background threads are not used/managed by this service
* @return true if any background threads/workers managed by this module are still running or are pending to be run,
* false if all work has been done, or if background threads are not used/managed by this module
*/
public boolean hasBackgroundJobsRunning();
@ -98,7 +100,7 @@ public interface IngestServiceAbstract {
* Used to determine if a module has implemented a simple (run-time)
* configuration panel that is displayed by the ingest manager.
*
* @return true if this service has a simple (run-time) configuration
* @return true if this module has a simple (run-time) configuration
*/
public boolean hasSimpleConfiguration();
@ -106,7 +108,7 @@ public interface IngestServiceAbstract {
* Used to determine if a module has implemented an advanced (general)
* configuration that can be used for more in-depth module configuration.
*
* @return true if this service has an advanced configuration
* @return true if this module has an advanced configuration
*/
public boolean hasAdvancedConfiguration();

View File

@ -21,25 +21,23 @@ package org.sleuthkit.autopsy.ingest;
import org.sleuthkit.datamodel.AbstractFile;
/**
* Ingest service interface that will be called for every file in the image
* Ingest module interface that will be called for every file in the image
*/
public interface IngestServiceAbstractFile extends IngestServiceAbstract {
public interface IngestModuleAbstractFile extends IngestModuleAbstract {
/**
* Return value resulting from processing AbstractFile
* Can be used by IngestManager to stop processing the file, or by subsequent module
* If ERROR, can be used subsequent module
* in the pipeline as a hint to stop processing the file
*/
public enum ProcessResult {
OK, ///< Indicates that processing was successful (including if the file was largely ignored by the module)
COND_STOP, ///< Indicates that the module thinks that the pipeline could stop processing, but it is up to the IngestManager to decide. Use this, for example, if a hash lookup detects that a file is known to be good and can be ignored.
STOP, ///< Indicates that the module thinks that the pipeline processing should be stopped unconditionally for the current file (this should be used sparingly for critical system errors and could be removed in future version)
ERROR, ///< Indicates that an error was encountered while processing the file, hint for later modules that depend on this module to skip processing the file due to error condition (such as file could not be read)
UNKNOWN ///< Indicates that a return value for the module is not known. This should not be returned directly by modules, but is used when modules want to learn about a return value from a previously run module.
UNKNOWN ///< Indicates that a return value for the module is not known. This should not be returned directly by modules, but is used to indicate the module has not set its return value (e.g. it never ran)
};
/**
* Entry point to process file / directory by the service. See \ref ingestmodule_making for details
* Entry point to process file / directory by the module. See \ref ingestmodule_making for details
* on what modules are responsible for doing.
*
* @param abstractFile file to process

View File

@ -22,26 +22,26 @@ import org.sleuthkit.datamodel.Image;
/**
*
* Ingest service that acts on entire image
* Image ingest services run each in its own background thread
* Ingest module that acts on entire image
* Image ingest modules run each in its own background thread
* in parallel to the file processing ingest pipeline and other image ingest modules
*/
public interface IngestServiceImage extends IngestServiceAbstract {
public interface IngestModuleImage extends IngestModuleAbstract {
/**
* Entry point to process the image by the service.
* Entry point to process the image by the module.
*
* Service does all the processing work in this method.
* Module does all the processing work in this method.
* It is responsible for extracting content of interest from the image (i.e. using DataModel API) and processing it.
* Results of processing, such as extracted data or analysis results, should be posted to the blackboard.
*
* The service notifies the ingest inbox of interesting events (data, errors, warnings, infos)
* The module notifies the ingest inbox of interesting events (data, errors, warnings, infos)
* by posting ingest messages
* The service notifies data viewers by firing events using IngestManager.fireServiceDataEvent
* The module notifies data viewers by firing events using IngestManagerProxy.fireModuleDataEvent
*
* The service is responsible for posting progress to controller
* And to periodically check controller if it should break out of the processing loop because task has been cancelled
* The module is responsible for posting progress to controller
* And to periodically check controller if it should break out of the processing loop because task has been canceled
*
* @param image to process
* @param controller to post progress to and to use for checking if cancellation has occurred

View File

@ -0,0 +1,49 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012 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.ingest;
/**
*
* Context passed to a module at initialization time.
* It may contain module configuration required to initialize some modules.
*/
public class IngestModuleInit {
private String moduleArgs;
/**
* Get module arguments
* @return module args string, used by some modules
*/
public String getModuleArgs() {
return moduleArgs;
}
/**
* Sets module args. string (only used by module pipeline)
* @param moduleArgs arguments to set for the module
*/
void setModuleArgs(String moduleArgs) {
this.moduleArgs = moduleArgs;
}
}

View File

@ -0,0 +1,107 @@
/*
* 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.ingest;
/**
* Services available to ingest modules via singleton instance,
* e.g. for interacting with the ingest manager
* for sending data events, ingest messages, getting configurations, etc.
*
*/
public class IngestServices {
private IngestManager manager;
private static IngestServices instance;
private IngestServices() {
this.manager = IngestManager.getDefault();
}
/**
* Get handle to module services
* @return the services handle
*/
public static synchronized IngestServices getDefault() {
if (instance == null) {
instance = new IngestServices();
}
return instance;
}
/**
* Post ingest message
* @param message ingest message to be posted by ingest module
*/
public void postMessage(final IngestMessage message) {
manager.postMessage(message);
}
/**
* Fire module event to notify registered module event listeners
* @param eventType the event type, defined in IngestManager.IngestManagerEvents
* @param moduleName the module name
*/
public void fireModuleEvent(String eventType, String moduleName) {
IngestManager.fireModuleEvent(eventType, moduleName);
}
/**
* Fire module data event to notify registered module data event listeners
* @param moduleDataEvent module data event, encapsulating blackboard artifact data
*/
public void fireModuleDataEvent(ModuleDataEvent moduleDataEvent) {
IngestManager.fireModuleDataEvent(moduleDataEvent);
}
/**
* Facility for the module to query the currently set recommended data update frequency in minutes
* Modules that post data in controlled time intervals, should obey this setting
*
* @return max. number of minutes before module posts new data, if data is available
*
* @Deprecated individual modules are be responsible for maintaining such settings
*/
public int getUpdateFrequency() {
return manager.getUpdateFrequency().getTime();
}
/**
* Facility for a file ingest module to check a return value from another file ingest module
* that executed for the same file earlier in the file ingest pipeline
* The module return value can be used as a guideline to skip processing the file
*
* @param moduleName registered module name of the module to check the return value of
* @return the return value of the previously executed module for the currently processed file in the file ingest pipeline
*/
public IngestModuleAbstractFile.ProcessResult getAbstractFileModuleResult(String moduleName) {
return manager.getAbstractFileModuleResult(moduleName);
}
}

View File

@ -38,6 +38,7 @@ public class Installer extends ModuleInstall {
@Override
public void run() {
//at this point UI top component is present for sure, ensure manager has it
manager.initUI();
//force ingest inbox closed, even if previous state was open
//IngestMessageTopComponent.findInstance().close();

View File

@ -32,33 +32,33 @@ import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
* The object wraps a collection of blackboard artifacts and their associated attributes that are to be reported as the new data to listeners.
* Passing the data as part of the event reduces memory footprint and decreases number of garbage collections of the blackboard artifacts and attributes objects (the objects are expected to be reused by the data event listeners).
*
* If a service does not pass the data as part of ServiceDataEvent (ServiceDataEvent.getArtifacts() returns null) - it is an indication that the service
* If a module does not pass the data as part of ModuleDataEvent (ModuleDataEvent.getArtifacts() returns null) - it is an indication that the module
* has new data but it does not implement new data tracking. The listener can then perform a blackboard query to get the latest data of interest (e.g. by artifact type).
*
* By design, only a single type of artifacts can be contained in a single data event.
*/
public class ServiceDataEvent {
public class ModuleDataEvent {
private String serviceName;
private String moduleName;
private ARTIFACT_TYPE artifactType;
private Collection<BlackboardArtifact> artifactIDs;
/**
* @param serviceName Module name
* @param moduleName Module name
* @param artifactType Type of artifact that was posted to blackboard
*/
public ServiceDataEvent(String serviceName, ARTIFACT_TYPE artifactType) {
this.serviceName = serviceName;
public ModuleDataEvent(String moduleName, ARTIFACT_TYPE artifactType) {
this.moduleName = moduleName;
this.artifactType = artifactType;
}
/**
* @param serviceName Module name
* @param moduleName Module name
* @param artifactType Type of artifact that was posted to blackboard
* @param artifactIDs List of specific artifact ID values that were added to blackboard
*/
public ServiceDataEvent(String serviceName, ARTIFACT_TYPE artifactType, Collection<BlackboardArtifact> artifactIDs) {
this(serviceName, artifactType);
public ModuleDataEvent(String moduleName, ARTIFACT_TYPE artifactType, Collection<BlackboardArtifact> artifactIDs) {
this(moduleName, artifactType);
this.artifactIDs = artifactIDs;
}
@ -79,11 +79,11 @@ public class ServiceDataEvent {
}
/**
* get service name that created the artifacts and fired the event
* get module name that created the artifacts and fired the event
* @return
*/
public String getServiceName() {
return serviceName;
public String getModuleName() {
return moduleName;
}

View File

@ -18,45 +18,45 @@
*/
package org.sleuthkit.autopsy.ingest.example;
import java.beans.PropertyChangeListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.ingest.IngestManagerProxy;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.IngestMessage;
import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType;
import org.sleuthkit.autopsy.ingest.IngestServiceAbstract.ServiceType;
import org.sleuthkit.autopsy.ingest.IngestServiceAbstractFile;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstract.ModuleType;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.datamodel.AbstractFile;
/**
* Example implementation of a fscontent image ingest service
* Example implementation of a file ingest module
*
*/
public class ExampleAbstractFileIngestService implements IngestServiceAbstractFile {
public class ExampleAbstractFileIngestModule implements IngestModuleAbstractFile {
private static final Logger logger = Logger.getLogger(ExampleAbstractFileIngestService.class.getName());
private static ExampleAbstractFileIngestService instance = null;
private IngestManagerProxy managerProxy;
private static final Logger logger = Logger.getLogger(ExampleAbstractFileIngestModule.class.getName());
private static ExampleAbstractFileIngestModule instance = null;
private IngestServices services;
private static int messageId = 0;
//file ingest services require a private constructor
//file ingest modules require a private constructor
//to ensure singleton instances
private ExampleAbstractFileIngestService() {
private ExampleAbstractFileIngestModule() {
}
public static synchronized ExampleAbstractFileIngestService getDefault() {
public static synchronized ExampleAbstractFileIngestModule getDefault() {
if (instance == null) {
instance = new ExampleAbstractFileIngestService();
instance = new ExampleAbstractFileIngestModule();
}
return instance;
}
@Override
public ProcessResult process(AbstractFile fsContent) {
managerProxy.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Processing " + fsContent.getName()));
services.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Processing " + fsContent.getName()));
//service specific AbstractFile processing code here
//module specific AbstractFile processing code here
try {
Thread.sleep(100);
} catch (InterruptedException e) {
@ -68,42 +68,42 @@ public class ExampleAbstractFileIngestService implements IngestServiceAbstractFi
@Override
public void complete() {
logger.log(Level.INFO, "complete()");
managerProxy.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Complete"));
services.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Complete"));
//service specific cleanup due completion here
//module specific cleanup due completion here
}
@Override
public String getName() {
return "Example AbstractFile Service";
return "Example AbstractFile Module";
}
@Override
public String getDescription() {
return "Example AbstractFile Service description";
return "Example AbstractFile Module description";
}
@Override
public void init(IngestManagerProxy managerProxy) {
public void init(IngestModuleInit initContext) {
logger.log(Level.INFO, "init()");
this.managerProxy = managerProxy;
services = IngestServices.getDefault();
//service specific initialization here
//module specific initialization here
}
@Override
public void stop() {
logger.log(Level.INFO, "stop()");
managerProxy.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Stopped"));
services.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Stopped"));
//service specific cleanup due interruption here
//module specific cleanup due interruption here
}
@Override
public ServiceType getType() {
return ServiceType.AbstractFile;
public ModuleType getType() {
return ModuleType.AbstractFile;
}
@Override

View File

@ -18,36 +18,36 @@
*/
package org.sleuthkit.autopsy.ingest.example;
import java.beans.PropertyChangeListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.ingest.IngestImageWorkerController;
import org.sleuthkit.autopsy.ingest.IngestManagerProxy;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.IngestMessage;
import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType;
import org.sleuthkit.autopsy.ingest.IngestServiceImage;
import org.sleuthkit.autopsy.ingest.IngestModuleImage;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.datamodel.Image;
/**
* Example implementation of an image ingest service
*
*/
public final class ExampleImageIngestService implements IngestServiceImage {
public final class ExampleImageIngestModule implements IngestModuleImage {
private static final Logger logger = Logger.getLogger(ExampleImageIngestService.class.getName());
private static ExampleImageIngestService defaultInstance = null;
private IngestManagerProxy managerProxy;
private static final Logger logger = Logger.getLogger(ExampleImageIngestModule.class.getName());
private static ExampleImageIngestModule defaultInstance = null;
private IngestServices services;
private static int messageId = 0;
//public constructor is required
//as multiple instances are created for processing multiple images simultenously
public ExampleImageIngestService() {
public ExampleImageIngestModule() {
}
//default instance used for service registration
public static synchronized ExampleImageIngestService getDefault() {
public static synchronized ExampleImageIngestModule getDefault() {
if (defaultInstance == null) {
defaultInstance = new ExampleImageIngestService();
defaultInstance = new ExampleImageIngestModule();
}
return defaultInstance;
}
@ -56,7 +56,7 @@ public final class ExampleImageIngestService implements IngestServiceImage {
public void process(Image image, IngestImageWorkerController controller) {
logger.log(Level.INFO, "process() " + this.toString());
managerProxy.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Processing " + image.getName()));
services.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Processing " + image.getName()));
//service specific Image processing code here
//example:
@ -76,7 +76,7 @@ public final class ExampleImageIngestService implements IngestServiceImage {
//do the work
Thread.sleep(500);
//post message to user if found something interesting
managerProxy.postMessage(IngestMessage.createMessage(processedFiles, MessageType.INFO, this, "Processed " + image.getName() + ": " + Integer.toString(processedFiles)));
services.postMessage(IngestMessage.createMessage(processedFiles, MessageType.INFO, this, "Processed " + image.getName() + ": " + Integer.toString(processedFiles)));
//update progress
controller.progress(++processedFiles);
@ -92,7 +92,7 @@ public final class ExampleImageIngestService implements IngestServiceImage {
logger.log(Level.INFO, "complete() " + this.toString());
final IngestMessage msg = IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Complete");
managerProxy.postMessage(msg);
services.postMessage(msg);
//service specific cleanup due to completion here
}
@ -108,9 +108,9 @@ public final class ExampleImageIngestService implements IngestServiceImage {
}
@Override
public void init(IngestManagerProxy managerProxy) {
public void init(IngestModuleInit initContext) {
logger.log(Level.INFO, "init() " + this.toString());
this.managerProxy = managerProxy;
services = IngestServices.getDefault();
//service specific initialization here
@ -119,14 +119,14 @@ public final class ExampleImageIngestService implements IngestServiceImage {
@Override
public void stop() {
logger.log(Level.INFO, "stop()");
managerProxy.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Stopped"));
services.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Stopped"));
//service specific cleanup due to interruption here
}
@Override
public ServiceType getType() {
return ServiceType.Image;
public ModuleType getType() {
return ModuleType.Image;
}
@Override

View File

@ -14,17 +14,17 @@
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.ingest.IngestMessageTopComponent.findInstance"/>
<attr name="position" intvalue="100"/>
</file> -->
<!-- example services -->
<!-- example modules -->
<!--
<file name="org-sleuthkit-autopsy-ingest-example-ExampleImageIngestService.instance">
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.ingest.IngestServiceImage"/>
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.ingest.example.ExampleImageIngestService.getDefault"/>
<file name="org-sleuthkit-autopsy-ingest-example-ExampleImageIngestModule.instance">
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.ingest.IngestModuleImage"/>
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.ingest.example.ExampleImageIngestModule.getDefault"/>
<attr name="position" intvalue="1000"/>
</file>
<file name="org-sleuthkit-autopsy-ingest-example-ExampleAbstractFileIngestService.instance">
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.ingest.IngestServiceAbstractFile"/>
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.ingest.example.ExampleAbstractFileIngestService.getDefault"/>
<file name="org-sleuthkit-autopsy-ingest-example-ExampleAbstractFileIngestModule.instance">
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile"/>
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.ingest.example.ExampleAbstractFileIngestModule.getDefault"/>
<attr name="position" intvalue="1100"/>
</file>
-->

View File

@ -5,7 +5,7 @@
The package provides the ingest module framework. Ingest modules perform data analysis in a multi-threaded approach.
\section ingestmodue_contents Package Contents
\section ingestmodule_contents Package Contents
The following are important classes in this package:
- IngestManager
@ -31,17 +31,17 @@ Refer to org.sleuthkit.autopsy.ingest.example for sample source code.
\subsection ingestmodule_making_api Module Interface
The first step is to choose the correct module type. Image-level modules will implement the IngestServiceImage interface and file-level modules will implement the IngestServiceAbstractFile interface.
The first step is to choose the correct module type. Image-level modules will implement the IngestModuleImage interface and file-level modules will implement the IngestModuleAbstractFile interface.
There is a static getDefault() method that is not part of the interface, that every module (whether an image or a file service) needs to implement to return the registered static instance of the service. Refer to example code in example.ExampleAbstractFileIngestService.getDefault()
There is a static getDefault() method that is not part of the interface, that every module (whether an image or a file module) needs to implement to return the registered static instance of the module. Refer to example code in example.ExampleAbstractFileIngestModule.getDefault()
File-level modules need to be singleton (only a single instance at a time). To ensure this, make the constructor private. Ensure the default public file service constructor is overridden with the private one. Image-level modules require a public constructor.
File-level modules need to be singleton (only a single instance at a time). To ensure this, make the constructor private. Ensure the default public file module constructor is overridden with the private one. Image-level modules require a public constructor.
The interfaces have several standard methods that need to be implemented. See the interface methods for details.
- IngestServiceAbstract.init() is invoked every time an ingest session starts. A module should support multiple invocations of init() throughout the application life-cycle.
- IngestServiceAbstract.complete() is invoked when an ingest session completes. The module should perform any resource (files, handles, caches) cleanup in this method and submit final results and post a final ingest inbox message.
- IngestServiceAbstract.stop() is invoked on a module when an ingest session is interrupted by the user or by the system.
The method implementation should be similar to complete() in that the service should perform any cleanup work. If there is pending data to be processed or pending results to be reported by the service then the results should be rejected and ignored if stop() is invoked and the module should terminate as early as possible.
- IngestModuleAbstract.init() is invoked every time an ingest session starts. A module should support multiple invocations of init() throughout the application life-cycle.
- IngestModuleAbstract.complete() is invoked when an ingest session completes. The module should perform any resource (files, handles, caches) cleanup in this method and submit final results and post a final ingest inbox message.
- IngestModuleAbstract.stop() is invoked on a module when an ingest session is interrupted by the user or by the system.
The method implementation should be similar to complete() in that the module should perform any cleanup work. If there is pending data to be processed or pending results to be reported by the module then the results should be rejected and ignored if stop() is invoked and the module should terminate as early as possible.
- process() method is invoked to analyze the data. The specific method depends on the module type.
@ -55,7 +55,7 @@ Module developers are encouraged to use the standard java.util.logging.Logger in
\subsection ingestmodule_making_process Process Method
The process method is where the work is done in each type of module. Some notes:
- File-level modules will be called on each file in an order determined by the IngestManager. Each module is free to quickly ignore a file based on name, signature, etc. If a module wants to know the return value from a previously run module, it should use the IngestManagerProxy.getAbstractFileServiceResult() method.
- File-level modules will be called on each file in an order determined by the IngestManager. Each module is free to quickly ignore a file based on name, signature, etc. If a module wants to know the return value from a previously run module, it should use the IngestServices.getAbstractFileModuleResult() method.
- Image-level modules are expected not passed in specific files and are expected to query the database to find the files that they are interested in.
@ -65,9 +65,9 @@ Ingest modules need to be registered using the Netbeans Lookup infrastructure in
An example Image-level module is:
\verbatim
<file name="org-sleuthkit-autopsy-ingest-example-ExampleImageIngestService.instance">
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.ingest.IngestServiceImage"/>
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.ingest.example.ExampleImageIngestService.getDefault"/>
<file name="org-sleuthkit-autopsy-ingest-example-ExampleImageIngestModule.instance">
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.ingest.IngestModuleImage"/>
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.ingest.example.ExampleImageIngestModule.getDefault"/>
<attr name="position" intvalue="1000"/>
</file>
\endverbatim
@ -75,16 +75,16 @@ An example Image-level module is:
An example file-level module is:
\verbatim
<file name="org-sleuthkit-autopsy-ingest-example-ExampleAbstractFileIngestService.instance">
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.ingest.IngestServiceAbstractFile"/>
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.ingest.example.ExampleAbstractFileIngestService.getDefault"/>
<file name="org-sleuthkit-autopsy-ingest-example-ExampleAbstractFileIngestModule.instance">
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile"/>
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.ingest.example.ExampleAbstractFileIngestModule.getDefault"/>
<attr name="position" intvalue="1100"/>
</file>
\endverbatim
Note the "position" attribute. The attribute determines the ordering of the module in the ingest pipeline.
Services with lower position attribute will execute earlier.
Use high numbers (higher than 1000) for non-core services. If your module depends on results from another module, use a higher position attribute to enforce the dependency.
Modules with lower position attribute will execute earlier.
Use high numbers (higher than 1000) for non-core modules. If your module depends on results from another module, use a higher position attribute to enforce the dependency.
Note: we plan to implement a more flexible and robust module dependency system in future versions of the Autopsy ingest framework.
@ -97,11 +97,11 @@ Users will see the results from ingest modules in one of two ways:
- Results are posted to the blackboard and will be displayed in the navigation tree
- Messages are sent to the Ingest Inbox to notify a user of what has recently been found.
See the Blackboard (REFERENCE) documentation for posting results to it. Modules are free to immediately post results when they find them or they can wait. The IngestManagerProxy.getUpdateFrequency() method returns the maximum amount of time that a module can wait before it posts its results.
See the Blackboard (REFERENCE) documentation for posting results to it. Modules are free to immediately post results when they find them or they can wait. The IngestServices.getUpdateFrequency() method returns the maximum amount of time that a module can wait before it posts its results.
An example of waiting to post results is the keyword search module. It is resource intensive to commit the keyword index and do a keyword search. Therefore, when its process() method is invoked, it checks if it is close to the getUpdateFrequency() since the last time it did a keyword search. If it is, then it commits the index and performs the search.
When they add data to the blackboard, modules should notify listeners of the new data by periodically invoking IngestManagerProxy.fireServiceDataEvent() method. This allows other modules (and the main UI) to know when to query the blackboard for the latest data.
When they add data to the blackboard, modules should notify listeners of the new data by periodically invoking IngestServices.fireModuleDataEvent() method. This allows other modules (and the main UI) to know when to query the blackboard for the latest data.
Modules should post messages to the inbox when interesting data is found. The messages includes the module name, message subject, message details, a unique message id (in the context of the originating module), and a uniqueness attribute. The uniqueness attribute is used to group similar messages together and to determine the overall importance priority of the message (if the same message is seen repeatedly, it is considered lower priority).
@ -111,7 +111,7 @@ Ingest messages have different types: there are info messages, warning messages,
The data messages contain encapsulated blackboard artifacts and attributes. The passed in data is used by the ingest inbox GUI widget to navigate to the artifact view in the directory tree, if requested by the user.
Ingest message API is defined in IngestMessage class. The class also contains factory methods to create new messages.
Messages are posted using IngestManagerProxy.postMessage() method, which accepts a message object created using one of the factory methods.
Messages are posted using IngestServices.postMessage() method, which accepts a message object created using one of the factory methods.
Modules should post inbox messages to the user when stop() or complete() is invoked (refer to the examples).
It is recommended to populate the description field of the complete inbox message to provide feedback to the user
@ -134,13 +134,13 @@ Module configuration is decentralized and module-specific; every module maintain
own configuration state and is responsible for implementing the graphical interface.
The run-time configuration (also called simple configuration), is achieved by each
ingest module providing a JPanel. The IngestServiceAbstract.hasSimpleConfiguration(),
IngestServiceAbstract.getSimpleConfiguration(), and IngestServiceAbstract.saveSimpleConfiguration()
ingest module providing a JPanel. The IngestModuleAbstract.hasSimpleConfiguration(),
IngestModuleAbstract.getSimpleConfiguration(), and IngestModuleAbstract.saveSimpleConfiguration()
methods should be used for run-time configuration.
The general configuration is also achieved by the module returning a JPanel. A link will be provided to the general configuration from the ingest manager if it exists.
The IngestServiceAbstract.hasAdvancedConfiguration(),
IngestServiceAbstract.getAdvancedConfiguration(), and IngestServiceAbstract.saveAdvancedConfiguration()
The IngestModuleAbstract.hasAdvancedConfiguration(),
IngestModuleAbstract.getAdvancedConfiguration(), and IngestModuleAbstract.saveAdvancedConfiguration()
methods should be used for general configuration.
@ -152,14 +152,14 @@ methods should be used for general configuration.
Other modules and core Autopsy classes may want to get the status of the ingest manager. The IngestManager provides access to this data with the sleuthkit.autopsy.ingest.IngestManager.isIngestRunning() method.
External modules can also register themselves as ingest service event listeners and receive event notifications (when a module is started, stopped, completed or has new data).
Use the IngestManager.addPropertyChangeListener() method to register a service event listener.
External modules can also register themselves as ingest module event listeners and receive event notifications (when a module is started, stopped, completed or has new data).
Use the IngestManager.addPropertyChangeListener() method to register a module event listener.
Events types received are defined in IngestManager.IngestModuleEvent enum.
At the end of the ingest, IngestManager itself will notify all listeners of IngestModuleEvent.COMPLETED event.
The event is an indication for listeners to perform the final data refresh by quering the blackboard.
Module developers are encouraged to generate periodic IngestModuleEvent.DATA
ServiceDataEvent events when they post data to the blackboard,
ModuleDataEvent events when they post data to the blackboard,
but the IngestManager will make a final event to handle scenarios where the module did not notify listeners while it was running.
*/

View File

@ -43,7 +43,7 @@ public class AbstractFileHtmlExtract implements AbstractFileExtract {
private static final int SINGLE_READ_CHARS = 1024;
private static final int EXTRA_CHARS = 128; //for whitespace
private static final char[] TEXT_CHUNK_BUF = new char[MAX_EXTR_TEXT_CHARS];
private KeywordSearchIngestService service;
private KeywordSearchIngestModule module;
private Ingester ingester;
private AbstractFile sourceFile;
private int numChunks = 0;
@ -53,7 +53,7 @@ public class AbstractFileHtmlExtract implements AbstractFileExtract {
};
AbstractFileHtmlExtract() {
this.service = KeywordSearchIngestService.getDefault();
this.module = KeywordSearchIngestModule.getDefault();
ingester = Server.getIngester();
}
@ -161,7 +161,7 @@ public class AbstractFileHtmlExtract implements AbstractFileExtract {
//check if need invoke commit/search between chunks
//not to delay commit if timer has gone off
service.checkRunCommitSearch();
module.checkRunCommitSearch();
}
} catch (IOException ex) {
logger.log(Level.WARNING, "Unable to read content stream from " + sourceFile.getId() + ": " + sourceFile.getName(), ex);

View File

@ -39,7 +39,7 @@ import org.sleuthkit.datamodel.AbstractFile;
*/
class AbstractFileStringExtract implements AbstractFileExtract {
private KeywordSearchIngestService service;
private KeywordSearchIngestModule module;
private Ingester ingester;
private int numChunks;
private static final Logger logger = Logger.getLogger(AbstractFileStringExtract.class.getName());
@ -61,7 +61,7 @@ class AbstractFileStringExtract implements AbstractFileExtract {
}
public AbstractFileStringExtract() {
this.service = KeywordSearchIngestService.getDefault();
this.module = KeywordSearchIngestModule.getDefault();
this.ingester = Server.getIngester();
this.extractScripts.add(DEFAULT_SCRIPT);
}
@ -122,7 +122,7 @@ class AbstractFileStringExtract implements AbstractFileExtract {
//check if need invoke commit/search between chunks
//not to delay commit if timer has gone off
service.checkRunCommitSearch();
module.checkRunCommitSearch();
//debug.close();
}

View File

@ -32,7 +32,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.ingest.IngestServiceAbstractFile;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.ReadContentInputStream;
import org.apache.tika.Tika;
@ -52,7 +52,7 @@ import org.sleuthkit.autopsy.keywordsearch.Ingester.IngesterException;
*/
public class AbstractFileTikaTextExtract implements AbstractFileExtract {
private static final Logger logger = Logger.getLogger(IngestServiceAbstractFile.class.getName());
private static final Logger logger = Logger.getLogger(IngestModuleAbstractFile.class.getName());
private static final Logger tikaLogger = KeywordSearch.getTikaLogger();
private static final Charset OUTPUT_CHARSET = Server.DEFAULT_INDEXED_TEXT_CHARSET;
static final int MAX_EXTR_TEXT_CHARS = 512 * 1024;
@ -60,7 +60,7 @@ public class AbstractFileTikaTextExtract implements AbstractFileExtract {
private static final int EXTRA_CHARS = 128; //for whitespace
private static final char[] TEXT_CHUNK_BUF = new char[MAX_EXTR_TEXT_CHARS];
//private Tika tika;
private KeywordSearchIngestService service;
private KeywordSearchIngestModule module;
private static Ingester ingester;
private AbstractFile sourceFile; //currently processed file
private int numChunks = 0;
@ -74,7 +74,7 @@ public class AbstractFileTikaTextExtract implements AbstractFileExtract {
"pst", "xml", "class", "dwg", "eml", "emlx", "mbox", "mht"};
AbstractFileTikaTextExtract() {
this.service = KeywordSearchIngestService.getDefault();
this.module = KeywordSearchIngestModule.getDefault();
ingester = Server.getIngester();
}
@ -216,7 +216,7 @@ public class AbstractFileTikaTextExtract implements AbstractFileExtract {
//check if need invoke commit/search between chunks
//not to delay commit if timer has gone off
service.checkRunCommitSearch();
module.checkRunCommitSearch();
}
} catch (IOException ex) {
final String msg = "Unable to read content stream from " + sourceFile.getId() + ": " + sourceFile.getName();

View File

@ -79,8 +79,8 @@ abstract class AbstractKeywordSearchPerformer extends javax.swing.JPanel impleme
return;
}
//check if keyword search service ingest is running (indexing, etc)
if (IngestManager.getDefault().isServiceRunning(KeywordSearchIngestService.getDefault())) {
//check if keyword search module ingest is running (indexing, etc)
if (IngestManager.getDefault().isModuleRunning(KeywordSearchIngestModule.getDefault())) {
if (KeywordSearchUtil.displayConfirmDialog("Keyword Search Ingest in Progress",
"<html>Keyword Search Ingest is currently running.<br />"
+ "Not all files have been indexed and this search might yield incomplete results.<br />"

View File

@ -31,6 +31,6 @@ public final class KeywordSearchAction extends AbstractAction implements Present
@Override
public Component getToolbarPresenter() {
return new KeywordSearchPanel();
return KeywordSearchPanel.getDefault();
}
}

View File

@ -59,10 +59,10 @@ public class KeywordSearchConfigurationPanel2 extends javax.swing.JPanel {
}
private void activateWidgets() {
final KeywordSearchIngestService service = KeywordSearchIngestService.getDefault();
final KeywordSearchIngestModule service = KeywordSearchIngestModule.getDefault();
skipNSRLCheckBox.setSelected(service.getSkipKnown());
boolean enable = !IngestManager.getDefault().isIngestRunning()
&& ! IngestManager.getDefault().isServiceRunning(KeywordSearchIngestService.getDefault());
&& ! IngestManager.getDefault().isModuleRunning(KeywordSearchIngestModule.getDefault());
skipNSRLCheckBox.setEnabled(enable);
}
@ -139,7 +139,7 @@ public class KeywordSearchConfigurationPanel2 extends javax.swing.JPanel {
}// </editor-fold>//GEN-END:initComponents
private void skipNSRLCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_skipNSRLCheckBoxActionPerformed
KeywordSearchIngestService.getDefault().setSkipKnown(skipNSRLCheckBox.isSelected());
KeywordSearchIngestModule.getDefault().setSkipKnown(skipNSRLCheckBox.isSelected());
}//GEN-LAST:event_skipNSRLCheckBoxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel chunksLabel;
@ -152,7 +152,7 @@ private void skipNSRLCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//
// End of variables declaration//GEN-END:variables
private void customizeComponents() {
this.skipNSRLCheckBox.setSelected(KeywordSearchIngestService.getDefault().getSkipKnown());
this.skipNSRLCheckBox.setSelected(KeywordSearchIngestModule.getDefault().getSkipKnown());
try {
filesIndexedValue.setText(Integer.toString(KeywordSearch.getServer().queryNumIndexedFiles()));

View File

@ -64,7 +64,7 @@ public class KeywordSearchConfigurationPanel3 extends javax.swing.JPanel {
toUpdate.add(s);
}
}
KeywordSearchIngestService.getDefault().setStringExtractScripts(toUpdate);
KeywordSearchIngestModule.getDefault().setStringExtractScripts(toUpdate);
}
};
@ -104,7 +104,7 @@ public class KeywordSearchConfigurationPanel3 extends javax.swing.JPanel {
}
private void reloadScriptsCheckBoxes() {
final KeywordSearchIngestService service = KeywordSearchIngestService.getDefault();
final KeywordSearchIngestModule service = KeywordSearchIngestModule.getDefault();
final List<SCRIPT> serviceScripts = service.getStringExtractScripts();
final int components = checkPanel.getComponentCount();
for (int i = 0; i < components; ++i) {
@ -118,7 +118,7 @@ public class KeywordSearchConfigurationPanel3 extends javax.swing.JPanel {
private void activateWidgets() {
reloadScriptsCheckBoxes();
boolean enable = !IngestManager.getDefault().isIngestRunning()
&& ! IngestManager.getDefault().isServiceRunning(KeywordSearchIngestService.getDefault());;
&& ! IngestManager.getDefault().isModuleRunning(KeywordSearchIngestModule.getDefault());;
//enable / disable checboxes
activateScriptsCheckboxes(enable);
}

View File

@ -178,7 +178,7 @@ class KeywordSearchEditListPanel extends javax.swing.JPanel implements ListSelec
if (IngestManager.getDefault().isServiceRunning(KeywordSearchIngestService.getDefault())) {
if (IngestManager.getDefault().isModuleRunning(KeywordSearchIngestModule.getDefault())) {
initIngest(0);
} else {
initIngest(1);
@ -191,13 +191,13 @@ class KeywordSearchEditListPanel extends javax.swing.JPanel implements ListSelec
String changed = evt.getPropertyName();
Object oldValue = evt.getOldValue();
if (changed.equals(IngestModuleEvent.COMPLETED.toString() )
&& ((String) oldValue).equals(KeywordSearchIngestService.MODULE_NAME)) {
&& ((String) oldValue).equals(KeywordSearchIngestModule.MODULE_NAME)) {
initIngest(1);
} else if (changed.equals(IngestModuleEvent.STARTED.toString() )
&& ((String) oldValue).equals(KeywordSearchIngestService.MODULE_NAME)) {
&& ((String) oldValue).equals(KeywordSearchIngestModule.MODULE_NAME)) {
initIngest(0);
} else if (changed.equals(IngestModuleEvent.STOPPED.toString() )
&& ((String) oldValue).equals(KeywordSearchIngestService.MODULE_NAME)) {
&& ((String) oldValue).equals(KeywordSearchIngestModule.MODULE_NAME)) {
initIngest(1);
}
}
@ -249,7 +249,7 @@ class KeywordSearchEditListPanel extends javax.swing.JPanel implements ListSelec
// Certain buttons will be disabled if ingest is ongoing on this list
List<String> ingestLists = new ArrayList<String>();
if (ingestOngoing) {
ingestLists = KeywordSearchIngestService.getDefault().getKeywordLists();
ingestLists = KeywordSearchIngestModule.getDefault().getKeywordLists();
}
boolean inIngest = !listSet ? false : ingestLists.contains(currentKeywordList.getName());

View File

@ -41,11 +41,12 @@ import org.openide.util.Cancellable;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.StopWatch;
import org.sleuthkit.autopsy.coreutils.StringExtract.StringExtractUnicodeTable.SCRIPT;
import org.sleuthkit.autopsy.ingest.IngestManagerProxy;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.IngestMessage;
import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType;
import org.sleuthkit.autopsy.ingest.IngestServiceAbstractFile;
import org.sleuthkit.autopsy.ingest.ServiceDataEvent;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.autopsy.keywordsearch.Ingester.IngesterException;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
@ -60,22 +61,22 @@ import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskData.FileKnown;
/**
* An ingest service on a file level Performs indexing of allocated and Solr
* An ingest module on a file level Performs indexing of allocated and Solr
* supported files, string extraction and indexing of unallocated and not Solr
* supported files Index commit is done periodically (determined by user set
* ingest update interval) Runs a periodic keyword / regular expression search
* on currently configured lists for ingest and writes results to blackboard
* Reports interesting events to Inbox and to viewers
*
* Registered as a service in layer.xml
* Registered as a module in layer.xml
*/
public final class KeywordSearchIngestService implements IngestServiceAbstractFile {
public final class KeywordSearchIngestModule implements IngestModuleAbstractFile {
private static final Logger logger = Logger.getLogger(KeywordSearchIngestService.class.getName());
private static final Logger logger = Logger.getLogger(KeywordSearchIngestModule.class.getName());
public static final String MODULE_NAME = "Keyword Search";
public static final String MODULE_DESCRIPTION = "Performs file indexing and periodic search using keywords and regular expressions in lists.";
private static KeywordSearchIngestService instance = null;
private IngestManagerProxy managerProxy;
private static KeywordSearchIngestModule instance = null;
private IngestServices services;
private Ingester ingester = null;
private volatile boolean commitIndex = false; //whether to commit index next time
private volatile boolean runSearcher = false; //whether to run searcher next time
@ -95,7 +96,7 @@ public final class KeywordSearchIngestService implements IngestServiceAbstractFi
private volatile int messageID = 0;
private boolean processedFiles;
private volatile boolean finalSearcherDone = true; //mark as done, until it's inited
private final String hashDBServiceName = "Hash Lookup"; //NOTE this needs to match the HashDB service getName()
private final String hashDBModuleName = "Hash Lookup"; //NOTE this needs to match the HashDB module getName()
private SleuthkitCase caseHandle = null;
private boolean skipKnown = true;
private boolean initialized = false;
@ -111,20 +112,20 @@ public final class KeywordSearchIngestService implements IngestServiceAbstractFi
private Map<Long, IngestStatus> ingestStatus;
//private constructor to ensure singleton instance
private KeywordSearchIngestService() {
private KeywordSearchIngestModule() {
//set default script
stringExtractScripts.add(SCRIPT.LATIN_1);
stringExtractScripts.add(SCRIPT.LATIN_2);
}
/**
* Returns singleton instance of the service, creates one if needed
* Returns singleton instance of the module, creates one if needed
*
* @return instance of the service
* @return instance of the module
*/
public static synchronized KeywordSearchIngestService getDefault() {
public static synchronized KeywordSearchIngestModule getDefault() {
if (instance == null) {
instance = new KeywordSearchIngestService();
instance = new KeywordSearchIngestModule();
}
return instance;
}
@ -145,13 +146,13 @@ public final class KeywordSearchIngestService implements IngestServiceAbstractFi
return ProcessResult.OK;
}
//check if we should index meta-data only when 1) it is known 2) HashDb service errored on it
IngestServiceAbstractFile.ProcessResult hashDBResult = managerProxy.getAbstractFileServiceResult(hashDBServiceName);
//check if we should index meta-data only when 1) it is known 2) HashDb module errored on it
IngestModuleAbstractFile.ProcessResult hashDBResult = services.getAbstractFileModuleResult(hashDBModuleName);
//logger.log(Level.INFO, "hashdb result: " + hashDBResult + "file: " + AbstractFile.getName());
if (hashDBResult == IngestServiceAbstractFile.ProcessResult.ERROR) {
if (hashDBResult == IngestModuleAbstractFile.ProcessResult.ERROR) {
//index meta-data only
indexer.indexFile(abstractFile, false);
//notify depending service that keyword search (would) encountered error for this file
//notify depending module that keyword search (would) encountered error for this file
return ProcessResult.ERROR;
}
else if (skipKnown && abstractFile.accept(getIsFileKnown) == true) {
@ -230,7 +231,7 @@ public final class KeywordSearchIngestService implements IngestServiceAbstractFi
finalSearcher.execute();
} else {
finalSearcherDone = true;
managerProxy.postMessage(IngestMessage.createMessage(++messageID, MessageType.INFO, this, "Completed"));
services.postMessage(IngestMessage.createMessage(++messageID, MessageType.INFO, this, "Completed"));
}
//log number of files / chunks in index
@ -289,20 +290,19 @@ public final class KeywordSearchIngestService implements IngestServiceAbstractFi
}
/**
* Initializes the service for new ingest run Sets up threads, timers,
* Initializes the module for new ingest run Sets up threads, timers,
* retrieves settings, keyword lists to run on
*
* @param managerProxy
* @param services
*/
@Override
public void init(IngestManagerProxy managerProxy) {
public void init(IngestModuleInit initContext) {
logger.log(Level.INFO, "init()");
services = IngestServices.getDefault();
initialized = false;
caseHandle = Case.getCurrentCase().getSleuthkitCase();
this.managerProxy = managerProxy;
ingester = Server.getIngester();
//initialize extractors
@ -330,7 +330,7 @@ public final class KeywordSearchIngestService implements IngestServiceAbstractFi
initKeywords();
if (keywords.isEmpty() || keywordLists.isEmpty()) {
managerProxy.postMessage(IngestMessage.createWarningMessage(++messageID, instance, "No keywords in keyword list.", "Only indexing will be done and and keyword search will be skipped (it can be executed later again as ingest or using toolbar search feature)."));
services.postMessage(IngestMessage.createWarningMessage(++messageID, instance, "No keywords in keyword list.", "Only indexing will be done and and keyword search will be skipped (it can be executed later again as ingest or using toolbar search feature)."));
}
processedFiles = false;
@ -341,7 +341,7 @@ public final class KeywordSearchIngestService implements IngestServiceAbstractFi
indexer = new Indexer();
final int updateIntervalMs = managerProxy.getUpdateFrequency() * 60 * 1000;
final int updateIntervalMs = services.getUpdateFrequency() * 60 * 1000;
logger.log(Level.INFO, "Using commit interval (ms): " + updateIntervalMs);
logger.log(Level.INFO, "Using searcher interval (ms): " + updateIntervalMs);
@ -353,12 +353,12 @@ public final class KeywordSearchIngestService implements IngestServiceAbstractFi
commitTimer.start();
searchTimer.start();
managerProxy.postMessage(IngestMessage.createMessage(++messageID, MessageType.INFO, this, "Started"));
services.postMessage(IngestMessage.createMessage(++messageID, MessageType.INFO, this, "Started"));
}
@Override
public ServiceType getType() {
return ServiceType.AbstractFile;
public ModuleType getType() {
return ModuleType.AbstractFile;
}
@Override
@ -390,7 +390,7 @@ public final class KeywordSearchIngestService implements IngestServiceAbstractFi
}
/**
* The services maintains background threads, return true if background
* The modules maintains background threads, return true if background
* threads are running or there are pending tasks to be run in the future,
* such as the final search post-ingest completion
*
@ -453,7 +453,7 @@ public final class KeywordSearchIngestService implements IngestServiceAbstractFi
msg.append("<br />Skipped files: ").append(skipped).append("<br />");
String indexStats = msg.toString();
logger.log(Level.INFO, "Keyword Indexing Completed: " + indexStats);
managerProxy.postMessage(IngestMessage.createMessage(++messageID, MessageType.INFO, this, "Keyword Indexing Completed", indexStats));
services.postMessage(IngestMessage.createMessage(++messageID, MessageType.INFO, this, "Keyword Indexing Completed", indexStats));
}
@ -910,7 +910,7 @@ public final class KeywordSearchIngestService implements IngestServiceAbstractFi
//check if should send messages on hits on this list
if (list.getIngestMessages()) //post ingest inbox msg
{
managerProxy.postMessage(IngestMessage.createDataMessage(++messageID, instance, subjectSb.toString(), detailsSb.toString(), uniqueKey, written.getArtifact()));
services.postMessage(IngestMessage.createDataMessage(++messageID, instance, subjectSb.toString(), detailsSb.toString(), uniqueKey, written.getArtifact()));
}
@ -919,7 +919,7 @@ public final class KeywordSearchIngestService implements IngestServiceAbstractFi
//update artifact browser
if (!newArtifacts.isEmpty()) {
IngestManagerProxy.fireServiceDataEvent(new ServiceDataEvent(MODULE_NAME, ARTIFACT_TYPE.TSK_KEYWORD_HIT, newArtifacts));
services.fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, ARTIFACT_TYPE.TSK_KEYWORD_HIT, newArtifacts));
}
}
progress.progress(queryStr, ++numSearched);
@ -987,7 +987,7 @@ public final class KeywordSearchIngestService implements IngestServiceAbstractFi
//reset current resuls earlier to potentially garbage collect sooner
currentResults = new HashMap<Keyword, List<Long>>();
managerProxy.postMessage(IngestMessage.createMessage(++messageID, MessageType.INFO, KeywordSearchIngestService.instance, "Completed"));
services.postMessage(IngestMessage.createMessage(++messageID, MessageType.INFO, KeywordSearchIngestModule.instance, "Completed"));
} else {
//start counting time for a new searcher to start
//unless final searcher is pending
@ -1039,10 +1039,10 @@ public final class KeywordSearchIngestService implements IngestServiceAbstractFi
}
/**
* Set the skip known files setting on the service
* Set the skip known files setting on the module
*
* @param skip true if skip, otherwise, will process known files as well, as
* reported by HashDB service
* reported by HashDB module
*/
void setSkipKnown(boolean skip) {
this.skipKnown = skip;

View File

@ -163,7 +163,7 @@ public class KeywordSearchIngestSimplePanel extends javax.swing.JPanel {
private void reloadLangs() {
//TODO multiple
List<SCRIPT> scripts = KeywordSearchIngestService.getDefault().getStringExtractScripts();
List<SCRIPT> scripts = KeywordSearchIngestModule.getDefault().getStringExtractScripts();
StringBuilder langs = new StringBuilder();
langs.append("<html>");
for (SCRIPT s : scripts) {

View File

@ -159,7 +159,7 @@ class KeywordSearchListsViewerPanel extends AbstractKeywordSearchPerformer {
}
};
if(IngestManager.getDefault().isServiceRunning(KeywordSearchIngestService.getDefault())) {
if(IngestManager.getDefault().isModuleRunning(KeywordSearchIngestModule.getDefault())) {
initIngest(true);
}
else {
@ -173,15 +173,15 @@ class KeywordSearchListsViewerPanel extends AbstractKeywordSearchPerformer {
String changed = evt.getPropertyName();
Object oldValue = evt.getOldValue();
if(changed.equals(IngestModuleEvent.COMPLETED.toString() ) &&
((String) oldValue).equals(KeywordSearchIngestService.MODULE_NAME)) {
((String) oldValue).equals(KeywordSearchIngestModule.MODULE_NAME)) {
initIngest(false);
}
else if(changed.equals(IngestModuleEvent.STARTED.toString() ) &&
((String) oldValue).equals(KeywordSearchIngestService.MODULE_NAME)) {
((String) oldValue).equals(KeywordSearchIngestModule.MODULE_NAME)) {
initIngest(true);
}
else if(changed.equals(IngestModuleEvent.STOPPED.toString() ) &&
((String) oldValue).equals(KeywordSearchIngestService.MODULE_NAME)) {
((String) oldValue).equals(KeywordSearchIngestModule.MODULE_NAME)) {
initIngest(false);
}
}
@ -410,7 +410,7 @@ class KeywordSearchListsViewerPanel extends AbstractKeywordSearchPerformer {
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
List<String> locked = KeywordSearchIngestService.getDefault().getKeywordLists();
List<String> locked = KeywordSearchIngestModule.getDefault().getKeywordLists();
return (columnIndex == 0 && (!ingestRunning || !locked.contains((String)getValueAt(rowIndex, 1))));
}
@ -618,7 +618,7 @@ class KeywordSearchListsViewerPanel extends AbstractKeywordSearchPerformer {
this.setVerticalAlignment(JCheckBox.CENTER);
String name = (String) table.getModel().getValueAt(row, 1);
List<String> locked = KeywordSearchIngestService.getDefault().getKeywordLists();
List<String> locked = KeywordSearchIngestModule.getDefault().getKeywordLists();
setEnabled(!locked.contains(name) || !ingestRunning);
Boolean selected = (Boolean) table.getModel().getValueAt(row, 0);
setSelected(selected);

View File

@ -167,13 +167,28 @@ public class KeywordSearchListsXML extends KeywordSearchListsAbstract{
final String name = listEl.getAttribute(LIST_NAME_ATTR);
final String created = listEl.getAttribute(LIST_CREATE_ATTR);
final String modified = listEl.getAttribute(LIST_MOD_ATTR);
final String useForIngest = listEl.getAttribute(LIST_USE_FOR_INGEST);
final String ingestMessages = listEl.getAttribute(LIST_INGEST_MSGS);
//set these bools to true by default, if they don't exist in XML
Boolean useForIngestBool;
Boolean ingestMessagesBool;
if (listEl.hasAttribute(LIST_USE_FOR_INGEST) ) {
useForIngestBool = Boolean.parseBoolean(listEl.getAttribute(LIST_USE_FOR_INGEST));
}
else {
useForIngestBool = true;
}
if (listEl.hasAttribute(LIST_INGEST_MSGS)) {
ingestMessagesBool = Boolean.parseBoolean(listEl.getAttribute(LIST_INGEST_MSGS));
}
else {
ingestMessagesBool = true;
}
Date createdDate = dateFormatter.parse(created);
Date modDate = dateFormatter.parse(modified);
Boolean useForIngestBool = Boolean.parseBoolean(useForIngest);
Boolean ingestMessagesBool = Boolean.parseBoolean(ingestMessages);
List<Keyword> words = new ArrayList<Keyword>();
KeywordSearchList list = new KeywordSearchList(name, createdDate, modDate, useForIngestBool, ingestMessagesBool, words);

View File

@ -1,4 +1,4 @@
<?xml version="1.1" encoding="UTF-8" ?>
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<NonVisualComponents>
@ -88,10 +88,7 @@
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Component id="listsButton" max="32767" attributes="1"/>
</Group>
<Component id="listsButton" alignment="1" max="32767" attributes="1"/>
<Component id="searchBoxPanel" alignment="0" pref="27" max="32767" attributes="2"/>
</Group>
</DimensionLayout>
@ -125,9 +122,9 @@
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="searchBox" alignment="0" pref="25" max="32767" attributes="3"/>
<Component id="settingsLabel" alignment="0" pref="25" max="32767" attributes="1"/>
<Component id="searchButton" alignment="0" pref="25" max="32767" attributes="1"/>
<Component id="searchBox" alignment="0" max="32767" attributes="3"/>
<Component id="settingsLabel" alignment="0" max="32767" attributes="1"/>
<Component id="searchButton" alignment="0" max="32767" attributes="1"/>
</Group>
</DimensionLayout>
</Layout>

View File

@ -52,13 +52,24 @@ public class KeywordSearchPanel extends AbstractKeywordSearchPerformer {
private KeywordPropertyChangeListener listener;
private boolean active = false;
private boolean entered = false;
private static KeywordSearchPanel instance;
/** Creates new form KeywordSearchPanel */
public KeywordSearchPanel() {
private KeywordSearchPanel() {
initComponents();
customizeComponents();
}
/**
* @return the default instance KeywordSearchPanel
*/
public static KeywordSearchPanel getDefault() {
if (instance == null) {
instance = new KeywordSearchPanel();
}
return instance;
}
private void customizeComponents() {
listener = new KeywordPropertyChangeListener();

View File

@ -42,8 +42,8 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode;
import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode.FsContentPropertyType;
import org.sleuthkit.autopsy.datamodel.KeyValueNode;
import org.sleuthkit.autopsy.ingest.IngestManagerProxy;
import org.sleuthkit.autopsy.ingest.ServiceDataEvent;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.autopsy.keywordsearch.KeywordSearchQueryManager.Presentation;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
@ -536,7 +536,7 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueQuery> {
if (!this.isCancelled() && !na.isEmpty()) {
IngestManagerProxy.fireServiceDataEvent(new ServiceDataEvent(KeywordSearchIngestService.MODULE_NAME, ARTIFACT_TYPE.TSK_KEYWORD_HIT, na));
IngestServices.getDefault().fireModuleDataEvent(new ModuleDataEvent(KeywordSearchIngestModule.MODULE_NAME, ARTIFACT_TYPE.TSK_KEYWORD_HIT, na));
}
}

View File

@ -126,7 +126,7 @@ public class LuceneQuery implements KeywordSearchQuery {
@Override
public KeywordWriteResult writeToBlackBoard(String termHit, AbstractFile newFsHit, String snippet, String listName) {
final String MODULE_NAME = KeywordSearchIngestService.MODULE_NAME;
final String MODULE_NAME = KeywordSearchIngestModule.MODULE_NAME;
KeywordWriteResult writeResult = null;
Collection<BlackboardAttribute> attributes = new ArrayList<BlackboardAttribute>();

View File

@ -160,7 +160,7 @@ public class TermComponentQuery implements KeywordSearchQuery {
@Override
public KeywordWriteResult writeToBlackBoard(String termHit, AbstractFile newFsHit, String snippet, String listName) {
final String MODULE_NAME = KeywordSearchIngestService.MODULE_NAME;
final String MODULE_NAME = KeywordSearchIngestModule.MODULE_NAME;
//there is match actually in this file, create artifact only then
BlackboardArtifact bba = null;

View File

@ -28,9 +28,9 @@
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.keywordsearch.HighlightedMatchesSource.getDefault"/>
<attr name="position" intvalue="250"/>
</file>
<file name="org-sleuthkit-autopsy-keywordsearch-KeywordSearchIngestService.instance">
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.ingest.IngestServiceAbstractFile"/>
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.keywordsearch.KeywordSearchIngestService.getDefault"/>
<file name="org-sleuthkit-autopsy-keywordsearch-KeywordSearchIngestModule.instance">
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile"/>
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.keywordsearch.KeywordSearchIngestModule.getDefault"/>
<attr name="position" intvalue="300"/>
</file>
<!--<file name="org-sleuthkit-autopsy-keywordsearch-KeywordSearchDataExplorer.instance">

View File

@ -1,4 +1,4 @@
3.0.0 (August 29, 2012)
3.0.0b5 (September 12, 2012)
Funded by US Army Intelligence Center of Excellence (USAICoE):
New features:
@ -14,12 +14,14 @@ New features:
- Basic file bookmarks support.
- Body file report.
- Improved UI.
- Updated Ingest Module API.
Bugfixes:
- Keyword search memory usage improvements.
- Directory tree now shows which directories have no children before user clicks.
- Fixed bug when recent cases would not get updated.
- Fixed a bug when sometimes a case would get deleted.
- Fixed occasional Media View crashes.
3.0.0b4 (June 29, 2012)
Funded by US Army Intelligence Center of Excellence (USAICoE):

View File

@ -24,8 +24,7 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import javax.swing.JPanel;
import org.sleuthkit.autopsy.ingest.IngestManagerProxy;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.datamodel.FsContent;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import java.util.logging.Level;
@ -35,9 +34,9 @@ import java.io.File;
import java.io.FileReader;
import org.sleuthkit.autopsy.coreutils.DecodeUtil;
import org.sleuthkit.autopsy.ingest.IngestImageWorkerController;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.IngestServiceImage;
import org.sleuthkit.autopsy.ingest.ServiceDataEvent;
import org.sleuthkit.autopsy.ingest.IngestModuleImage;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute;
@ -45,10 +44,9 @@ import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.Image;
/**
*
* @author Alex
* Chrome recent activity extraction
*/
public class Chrome extends Extract implements IngestServiceImage {
public class Chrome extends Extract implements IngestModuleImage {
private static final String chquery = "SELECT urls.url, urls.title, urls.visit_count, urls.typed_count, "
+ "last_visit_time, urls.hidden, visits.visit_time, (SELECT urls.url FROM urls WHERE urls.id=visits.url) as from_visit, visits.transition FROM urls, visits WHERE urls.id = visits.url";
@ -59,6 +57,8 @@ public class Chrome extends Extract implements IngestServiceImage {
private final Logger logger = Logger.getLogger(this.getClass().getName());
public int ChromeCount = 0;
private IngestServices services;
public Chrome() {
moduleName = "Chrome";
}
@ -114,7 +114,8 @@ public class Chrome extends Extract implements IngestServiceImage {
j++;
dbFile.delete();
}
IngestManagerProxy.fireServiceDataEvent(new ServiceDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY));
services.fireModuleDataEvent(new ModuleDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY));
}
}
@ -174,7 +175,8 @@ public class Chrome extends Extract implements IngestServiceImage {
j++;
dbFile.delete();
}
IngestManagerProxy.fireServiceDataEvent(new ServiceDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK));
services.fireModuleDataEvent(new ModuleDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK));
}
}
@ -223,7 +225,8 @@ public class Chrome extends Extract implements IngestServiceImage {
j++;
dbFile.delete();
}
IngestManagerProxy.fireServiceDataEvent(new ServiceDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE));
services.fireModuleDataEvent(new ModuleDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE));
}
}
@ -274,7 +277,8 @@ public class Chrome extends Extract implements IngestServiceImage {
j++;
dbFile.delete();
}
IngestManagerProxy.fireServiceDataEvent(new ServiceDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD));
services.fireModuleDataEvent(new ModuleDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD));
}
}
@ -321,13 +325,14 @@ public class Chrome extends Extract implements IngestServiceImage {
j++;
dbFile.delete();
}
IngestManagerProxy.fireServiceDataEvent(new ServiceDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY));
services.fireModuleDataEvent(new ModuleDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY));
}
}
@Override
public void init(IngestManagerProxy managerProxy) {
throw new UnsupportedOperationException("Not supported yet.");
public void init(IngestModuleInit initContext) {
services = IngestServices.getDefault();
}
@Override
@ -346,8 +351,8 @@ public class Chrome extends Extract implements IngestServiceImage {
}
@Override
public ServiceType getType() {
return ServiceType.Image;
public ModuleType getType() {
return ModuleType.Image;
}
@Override

View File

@ -28,10 +28,10 @@ import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.ingest.IngestServiceImage;
import org.sleuthkit.autopsy.ingest.IngestModuleImage;
import org.sleuthkit.datamodel.*;
abstract public class Extract implements IngestServiceImage{
abstract public class Extract implements IngestModuleImage{
protected Case currentCase = Case.getCurrentCase(); // get the most updated case
protected SleuthkitCase tskCase = currentCase.getSleuthkitCase();

View File

@ -50,12 +50,10 @@ import org.sleuthkit.autopsy.coreutils.DecodeUtil;
import org.sleuthkit.autopsy.coreutils.JLNK;
import org.sleuthkit.autopsy.coreutils.JLnkParser;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.datamodel.DataConversion;
import org.sleuthkit.autopsy.datamodel.KeyValue;
import org.sleuthkit.autopsy.ingest.IngestImageWorkerController;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.IngestManagerProxy;
import org.sleuthkit.autopsy.ingest.ServiceDataEvent;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute;
@ -64,12 +62,16 @@ import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.FsContent;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.ingest.IngestServiceImage;
import org.sleuthkit.autopsy.ingest.IngestModuleImage;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.datamodel.*;
public class ExtractIE extends Extract implements IngestServiceImage {
public class ExtractIE extends Extract implements IngestModuleImage {
private static final Logger logger = Logger.getLogger(ExtractIE.class.getName());
private IngestServices services;
private String indexDatQueryStr = "select * from tsk_files where name LIKE '%index.dat%'";
private String favoriteQuery = "select * from `tsk_files` where parent_path LIKE '%/Favorites%' and name LIKE '%.url'";
private String cookiesQuery = "select * from `tsk_files` where parent_path LIKE '%/Cookies%' and name LIKE '%.txt'";
@ -142,7 +144,8 @@ public class ExtractIE extends Extract implements IngestServiceImage {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID(), "RecentActivity", "Internet Explorer"));
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN.getTypeID(), "RecentActivity", domain));
this.addArtifact(ARTIFACT_TYPE.TSK_WEB_BOOKMARK, Favorite, bbattributes);
IngestManagerProxy.fireServiceDataEvent(new ServiceDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK));
services.fireModuleDataEvent(new ModuleDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK));
} catch (Exception ex) {
logger.log(Level.WARNING, "Error while trying to read into a sqlite db.{0}", ex);
this.addErrorMessage(this.getName() + ": Error while trying to analyze file:" + Favorite.getName());
@ -195,7 +198,7 @@ public class ExtractIE extends Extract implements IngestServiceImage {
}
IngestManagerProxy.fireServiceDataEvent(new ServiceDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE));
services.fireModuleDataEvent(new ModuleDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE));
}
//Recent Documents section
@ -225,7 +228,8 @@ public class ExtractIE extends Extract implements IngestServiceImage {
}
}
IngestManagerProxy.fireServiceDataEvent(new ServiceDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_RECENT_OBJECT));
services.fireModuleDataEvent(new ModuleDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_RECENT_OBJECT));
}
@ -488,12 +492,12 @@ public class ExtractIE extends Extract implements IngestServiceImage {
}
}
IngestManagerProxy.fireServiceDataEvent(new ServiceDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY));
services.fireModuleDataEvent(new ModuleDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY));
}
@Override
public void init(IngestManagerProxy managerProxy) {
throw new UnsupportedOperationException("Not supported yet.");
public void init(IngestModuleInit initContext) {
services = IngestServices.getDefault();
}
@Override
@ -515,8 +519,8 @@ public class ExtractIE extends Extract implements IngestServiceImage {
}
@Override
public ServiceType getType() {
return ServiceType.Image;
public ModuleType getType() {
return ModuleType.Image;
}
@Override

View File

@ -28,7 +28,6 @@ import java.text.SimpleDateFormat;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JPanel;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
@ -36,8 +35,9 @@ import org.openide.modules.InstalledFileLocator;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.ingest.IngestImageWorkerController;
import org.sleuthkit.autopsy.ingest.IngestManagerProxy;
import org.sleuthkit.autopsy.ingest.IngestServiceImage;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.IngestModuleImage;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.*;
@ -45,12 +45,13 @@ import org.sleuthkit.datamodel.*;
/**
* Extracting windows registry data using regripper
*/
public class ExtractRegistry extends Extract implements IngestServiceImage {
public class ExtractRegistry extends Extract implements IngestModuleImage {
public Logger logger = Logger.getLogger(this.getClass().getName());
private String RR_PATH;
boolean rrFound = false;
private int sysid;
private IngestServices services;
ExtractRegistry() {
final File rrRoot = InstalledFileLocator.getDefault().locate("rr", ExtractRegistry.class.getPackage().getName(), false);
@ -328,8 +329,8 @@ public class ExtractRegistry extends Extract implements IngestServiceImage {
}
@Override
public void init(IngestManagerProxy managerProxy) {
throw new UnsupportedOperationException("Not supported yet.");
public void init(IngestModuleInit initContext) {
services = IngestServices.getDefault();
}
@Override
@ -355,8 +356,8 @@ public class ExtractRegistry extends Extract implements IngestServiceImage {
}
@Override
public ServiceType getType() {
return ServiceType.Image;
public ModuleType getType() {
return ModuleType.Image;
}
@Override

View File

@ -27,14 +27,13 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JPanel;
import org.sleuthkit.autopsy.coreutils.DecodeUtil;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.ingest.IngestImageWorkerController;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.IngestManagerProxy;
import org.sleuthkit.autopsy.ingest.IngestServiceImage;
import org.sleuthkit.autopsy.ingest.ServiceDataEvent;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.IngestModuleImage;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute;
@ -43,10 +42,10 @@ import org.sleuthkit.datamodel.FsContent;
import org.sleuthkit.datamodel.Image;
/**
*
* @author Alex
* Firefox recent activity extraction
*/
public class Firefox extends Extract implements IngestServiceImage {
public class Firefox extends Extract implements IngestModuleImage {
private static final String ffquery = "SELECT moz_historyvisits.id,url,title,visit_count,(visit_date/1000000) as visit_date,from_visit,(SELECT url FROM moz_places WHERE id=moz_historyvisits.from_visit) as ref FROM moz_places, moz_historyvisits WHERE moz_places.id = moz_historyvisits.place_id AND hidden = 0";
private static final String ffcookiequery = "SELECT name,value,host,expiry,(lastAccessed/1000000) as lastAccessed,(creationTime/1000000) as creationTime FROM moz_cookies";
@ -55,6 +54,8 @@ public class Firefox extends Extract implements IngestServiceImage {
private static final String ffdownloadquery = "select target, source,(startTime/1000000) as startTime, maxBytes from moz_downloads";
public int FireFoxCount = 0;
private IngestServices services;
public Firefox() {
moduleName = "FireFox";
}
@ -108,7 +109,8 @@ public class Firefox extends Extract implements IngestServiceImage {
j++;
dbFile.delete();
}
IngestManagerProxy.fireServiceDataEvent(new ServiceDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY));
services.fireModuleDataEvent(new ModuleDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY));
}
}
@ -151,7 +153,8 @@ public class Firefox extends Extract implements IngestServiceImage {
j++;
dbFile.delete();
}
IngestManagerProxy.fireServiceDataEvent(new ServiceDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK));
services.fireModuleDataEvent(new ModuleDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK));
}
}
@ -211,7 +214,8 @@ public class Firefox extends Extract implements IngestServiceImage {
j++;
dbFile.delete();
}
IngestManagerProxy.fireServiceDataEvent(new ServiceDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE));
services.fireModuleDataEvent(new ModuleDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE));
}
}
@ -259,13 +263,14 @@ public class Firefox extends Extract implements IngestServiceImage {
j++;
dbFile.delete();
}
IngestManagerProxy.fireServiceDataEvent(new ServiceDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD));
services.fireModuleDataEvent(new ModuleDataEvent("Recent Activity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD));
}
}
@Override
public void init(IngestManagerProxy managerProxy) {
throw new UnsupportedOperationException("Not supported yet.");
public void init(IngestModuleInit initContext) {
services = IngestServices.getDefault();
}
@Override
@ -284,8 +289,8 @@ public class Firefox extends Extract implements IngestServiceImage {
}
@Override
public ServiceType getType() {
return ServiceType.Image;
public ModuleType getType() {
return ModuleType.Image;
}
@Override

View File

@ -25,21 +25,22 @@ import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.ingest.IngestImageWorkerController;
import org.sleuthkit.autopsy.ingest.IngestManagerProxy;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.IngestMessage;
import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType;
import org.sleuthkit.autopsy.ingest.IngestServiceImage;
import org.sleuthkit.autopsy.ingest.IngestModuleImage;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.datamodel.Image;
/**
* Recent activity image ingest service
* Recent activity image ingest module
*
*/
public final class RAImageIngestService implements IngestServiceImage {
public final class RAImageIngestModule implements IngestModuleImage {
private static final Logger logger = Logger.getLogger(RAImageIngestService.class.getName());
private static RAImageIngestService defaultInstance = null;
private IngestManagerProxy managerProxy;
private static final Logger logger = Logger.getLogger(RAImageIngestModule.class.getName());
private static RAImageIngestModule defaultInstance = null;
private IngestServices services;
private static int messageId = 0;
private ArrayList<String> errors = new ArrayList<String>();
private StringBuilder subCompleted = new StringBuilder();
@ -51,13 +52,13 @@ public final class RAImageIngestService implements IngestServiceImage {
//public constructor is required
//as multiple instances are created for processing multiple images simultenously
public RAImageIngestService() {
public RAImageIngestModule() {
}
//default instance used for service registration
public static synchronized RAImageIngestService getDefault() {
//default instance used for module registration
public static synchronized RAImageIngestModule getDefault() {
if (defaultInstance == null) {
defaultInstance = new RAImageIngestService();
defaultInstance = new RAImageIngestModule();
}
return defaultInstance;
}
@ -71,7 +72,7 @@ public final class RAImageIngestService implements IngestServiceImage {
modules.add(chre);
modules.add(eere);
modules.add(usq);
managerProxy.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Started " + image.getName()));
services.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Started " + image.getName()));
controller.switchToDeterminate(modules.size());
controller.progress(0);
@ -101,7 +102,7 @@ public final class RAImageIngestService implements IngestServiceImage {
for (String msg : errors) {
i++;
final IngestMessage error = IngestMessage.createMessage(++messageId, MessageType.INFO, this, msg + "<br>");
managerProxy.postMessage(error);
services.postMessage(error);
}
errorsFound = i + " errors found!";
}else
@ -110,9 +111,9 @@ public final class RAImageIngestService implements IngestServiceImage {
errorsFound = "No errors reported";
}
final IngestMessage msg = IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Completed - " + errorsFound, errorMessage.toString());
managerProxy.postMessage(msg);
services.postMessage(msg);
//service specific cleanup due to completion here
//module specific cleanup due to completion here
}
@Override
@ -126,20 +127,29 @@ public final class RAImageIngestService implements IngestServiceImage {
}
@Override
public void init(IngestManagerProxy managerProxy) {
public void init(IngestModuleInit initContext) {
logger.log(Level.INFO, "init() " + this.toString());
this.managerProxy = managerProxy;
this.eere = new ExtractIE();
this.chre = new Chrome();
this.eree = new ExtractRegistry();
this.ffre = new Firefox();
this.usq = new SearchEngineURLQueryAnalyzer();
services = IngestServices.getDefault();
eere = new ExtractIE();
eere.init(initContext);
chre = new Chrome();
chre.init(initContext);
eree = new ExtractRegistry();
eree.init(initContext);
ffre = new Firefox();
ffre.init(initContext);
usq = new SearchEngineURLQueryAnalyzer();
usq.init(initContext);
}
@Override
public void stop() {
logger.log(Level.INFO, "RAImageIngetService::stop()");
logger.log(Level.INFO, "RAImageIngetModule::stop()");
//Order Matters
//ExtractRegistry stop
this.eree.stop();
@ -149,8 +159,8 @@ public final class RAImageIngestService implements IngestServiceImage {
}
@Override
public ServiceType getType() {
return ServiceType.Image;
public ModuleType getType() {
return ModuleType.Image;
}
@Override

View File

@ -24,12 +24,12 @@ import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JPanel;
import org.sleuthkit.autopsy.ingest.IngestImageWorkerController;
import org.sleuthkit.autopsy.ingest.IngestManagerProxy;
import org.sleuthkit.autopsy.ingest.IngestServiceImage;
import org.sleuthkit.autopsy.ingest.ServiceDataEvent;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.IngestModuleImage;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute;
@ -47,7 +47,9 @@ import org.sleuthkit.datamodel.Image;
* enum, getSearchEngine(), extractSearchEngineQuery()
*
*/
public class SearchEngineURLQueryAnalyzer extends Extract implements IngestServiceImage {
public class SearchEngineURLQueryAnalyzer extends Extract implements IngestModuleImage {
private IngestServices services;
static final String MODULE_NAME = "Search Engine Query Analyzer";
@ -336,7 +338,7 @@ public class SearchEngineURLQueryAnalyzer extends Extract implements IngestServi
logger.log(Level.SEVERE, "Error while add artifact.", e + " from " + fs.toString());
this.addErrorMessage(this.getName() + ": Error while adding artifact");
}
IngestManagerProxy.fireServiceDataEvent(new ServiceDataEvent("RecentActivity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY));
services.fireModuleDataEvent(new ModuleDataEvent("RecentActivity", BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY));
}
@ -368,7 +370,8 @@ public class SearchEngineURLQueryAnalyzer extends Extract implements IngestServi
}
@Override
public void init(IngestManagerProxy managerProxy) {
public void init(IngestModuleInit initContext) {
services = IngestServices.getDefault();
logger.info("running init()");
}
@ -404,8 +407,8 @@ public class SearchEngineURLQueryAnalyzer extends Extract implements IngestServi
}
@Override
public ServiceType getType() {
return ServiceType.Image;
public ModuleType getType() {
return ModuleType.Image;
}
@Override

View File

@ -2,9 +2,9 @@
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.2//EN" "http://www.netbeans.org/dtds/filesystem-1_2.dtd">
<filesystem>
<folder name="Services">
<file name="org-sleuthkit-autopsy-recentactivity-RAImageIngestService.instance">
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.ingest.IngestServiceImage"/>
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.recentactivity.RAImageIngestService.getDefault"/>
<file name="org-sleuthkit-autopsy-recentactivity-RAImageIngestModule.instance">
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.ingest.IngestModuleImage"/>
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.recentactivity.RAImageIngestModule.getDefault"/>
<attr name="position" intvalue="110"/>
</file>
</folder>

View File

@ -200,7 +200,7 @@ public class ReportHTML implements ReportModule {
if (IngestManager.getDefault().isIngestRunning()) {
formatted_Report.append(ingestwarning);
}
else if (IngestManager.getDefault().areServicesRunning()) {
else if (IngestManager.getDefault().areModulesRunning()) {
formatted_Report.append(ingestwarning);
}
formatted_Report.append("<h2>Case Summary</h2><p>HTML Report Generated by <strong>Autopsy 3</strong> on ").append(datetime).append("<ul>");

View File

@ -225,7 +225,7 @@ public class RegressionTest extends TestCase{
}
new Timeout("pausing", 15000).sleep(); // give it a second (or fifteen) to process
boolean sleep = true;
while (man.areServicesRunning()) {
while (man.areModulesRunning()) {
new Timeout("pausing", 5000).sleep(); // give it a second (or five) to process
}
logger.info("Ingest (including enqueue) took " + (System.currentTimeMillis()-start) + "ms");

View File

@ -50,7 +50,7 @@ When an item is selected from the result viewer area, it is passed to the bottom
The component is by default registered with the ingest manager as an ingest event listener.
The viewer first loads all the viewer-supported data currently in the blackboard when Autopsy starts.
During the ingest process the viewer receives events from ingest services
During the ingest process the viewer receives events from ingest modules
(relayed by ingest manager) and it selectively refreshes parts of the tree providing real-time updates to the user.
When ingest is completed, the viewer responds to the final ingest data event generated by the ingest manager,
and performs a final refresh of all viewer-supported data in the blackboard.

View File

@ -124,7 +124,7 @@ public class ThunderbirdEmailParser {
ftime = ftime / 1000;
dates = ftime;
} catch (ParseException ex) {
Logger.getLogger(ThunderbirdMboxFileIngestService.class.getName()).log(Level.WARNING, null, ex);
Logger.getLogger(ThunderbirdMboxFileIngestModule.class.getName()).log(Level.WARNING, null, ex);
}
return dates;

View File

@ -33,13 +33,12 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.IngestManagerProxy;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.IngestMessage;
import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType;
import org.sleuthkit.autopsy.ingest.IngestServiceAbstract.*;
import org.sleuthkit.autopsy.ingest.IngestServiceAbstractFile;
import org.sleuthkit.autopsy.ingest.ServiceDataEvent;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstract.*;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
@ -51,55 +50,60 @@ import org.xml.sax.SAXException;
import org.apache.commons.lang.StringEscapeUtils;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentVisitor;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskData;
public class ThunderbirdMboxFileIngestService implements IngestServiceAbstractFile {
private static final Logger logger = Logger.getLogger(ThunderbirdMboxFileIngestService.class.getName());
private static ThunderbirdMboxFileIngestService instance = null;
private IngestManagerProxy managerProxy;
public class ThunderbirdMboxFileIngestModule implements IngestModuleAbstractFile {
private static final Logger logger = Logger.getLogger(ThunderbirdMboxFileIngestModule.class.getName());
private static ThunderbirdMboxFileIngestModule instance = null;
private IngestServices services;
private static int messageId = 0;
private static final String classname = "Thunderbird Parser";
private final String hashDBServiceName = "Hash Lookup";
private final String hashDBModuleName = "Hash Lookup";
private final GetIsFileKnownVisitor getIsFileKnown = new GetIsFileKnownVisitor();
public static synchronized ThunderbirdMboxFileIngestService getDefault() {
public static synchronized ThunderbirdMboxFileIngestModule getDefault() {
if (instance == null) {
instance = new ThunderbirdMboxFileIngestService();
instance = new ThunderbirdMboxFileIngestModule();
}
return instance;
}
@Override
public ProcessResult process(AbstractFile fsContent) {
public ProcessResult process(AbstractFile abstractFile) {
ThunderbirdEmailParser mbox = new ThunderbirdEmailParser();
boolean isMbox = false;
IngestServiceAbstractFile.ProcessResult hashDBResult =
managerProxy.getAbstractFileServiceResult(hashDBServiceName);
IngestModuleAbstractFile.ProcessResult hashDBResult =
services.getAbstractFileModuleResult(hashDBModuleName);
if (hashDBResult == IngestServiceAbstractFile.ProcessResult.COND_STOP) {
if (abstractFile.accept(getIsFileKnown) == true) {
return ProcessResult.OK; //file is known, stop processing it
} else if (hashDBResult == IngestServiceAbstractFile.ProcessResult.ERROR) {
} else if (hashDBResult == IngestModuleAbstractFile.ProcessResult.ERROR) {
return ProcessResult.ERROR; //file has read error, stop processing it
}
try {
byte[] t = new byte[64];
if(fsContent.getSize() > 64) {
int byteRead = fsContent.read(t, 0, 64);
if(abstractFile.getSize() > 64) {
int byteRead = abstractFile.read(t, 0, 64);
isMbox = mbox.isValidMimeTypeMbox(t);
}
} catch (TskException ex) {
Logger.getLogger(ThunderbirdMboxFileIngestService.class.getName()).log(Level.WARNING, null, ex);
Logger.getLogger(ThunderbirdMboxFileIngestModule.class.getName()).log(Level.WARNING, null, ex);
}
if (isMbox) {
managerProxy.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Processing " + fsContent.getName()));
String mboxName = fsContent.getName();
services.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Processing " + abstractFile.getName()));
String mboxName = abstractFile.getName();
String msfName = mboxName + ".msf";
Long mboxId = fsContent.getId();
Long mboxId = abstractFile.getId();
String mboxPath = "";
Long msfId = 0L;
Case currentCase = Case.getCurrentCase(); // get the most updated case
@ -133,7 +137,7 @@ public class ThunderbirdMboxFileIngestService implements IngestServiceAbstractFi
Content msfContent = tskCase.getContentById(msfId);
ContentUtils.writeToFile(msfContent, new File(currentCase.getTempDirectory() + File.separator + msfName));
} catch (IOException ex) {
Logger.getLogger(ThunderbirdMboxFileIngestService.class.getName()).log(Level.WARNING, null, ex);
Logger.getLogger(ThunderbirdMboxFileIngestModule.class.getName()).log(Level.WARNING, null, ex);
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Unable to obtain msf file for mbox parsing:" + this.getClass().getName(), ex);
}
@ -159,7 +163,7 @@ public class ThunderbirdMboxFileIngestService implements IngestServiceAbstractFi
// try {
// reader = new FileReader(currentCase.getTempDirectory() + File.separator + msfName);
// } catch (FileNotFoundException ex) {
// Logger.getLogger(ThunderbirdMboxFileIngestService.class.getName()).log(Level.WARNING, null, ex);
// Logger.getLogger(ThunderbirdMboxFileIngestModule.class.getName()).log(Level.WARNING, null, ex);
// }
// MorkDocument morkDocument = new MorkDocument(reader);
// List<Dict> dicts = morkDocument.getDicts();
@ -177,7 +181,7 @@ public class ThunderbirdMboxFileIngestService implements IngestServiceAbstractFi
String cc = "";
String bcc = "";
try {
ReadContentInputStream contentStream = new ReadContentInputStream(fsContent);
ReadContentInputStream contentStream = new ReadContentInputStream(abstractFile);
mbox.parse(contentStream);
HashMap<String, Map<String, String>> emailMap = new HashMap<String, Map<String, String>>();
emailMap = mbox.getAllEmails();
@ -211,21 +215,21 @@ public class ThunderbirdMboxFileIngestService implements IngestServiceAbstractFi
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH.getTypeID(), classname, folderPath));
BlackboardArtifact bbart;
try {
bbart = fsContent.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG);
bbart = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG);
bbart.addAttributes(bbattributes);
} catch (TskCoreException ex) {
Logger.getLogger(ThunderbirdMboxFileIngestService.class.getName()).log(Level.WARNING, null, ex);
Logger.getLogger(ThunderbirdMboxFileIngestModule.class.getName()).log(Level.WARNING, null, ex);
}
IngestManagerProxy.fireServiceDataEvent(new ServiceDataEvent(classname, BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG));
services.fireModuleDataEvent(new ModuleDataEvent(classname, BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG));
}
} catch (FileNotFoundException ex) {
Logger.getLogger(ThunderbirdMboxFileIngestService.class.getName()).log(Level.WARNING, null, ex);
Logger.getLogger(ThunderbirdMboxFileIngestModule.class.getName()).log(Level.WARNING, null, ex);
} catch (IOException ex) {
Logger.getLogger(ThunderbirdMboxFileIngestService.class.getName()).log(Level.WARNING, null, ex);
Logger.getLogger(ThunderbirdMboxFileIngestModule.class.getName()).log(Level.WARNING, null, ex);
} catch (SAXException ex) {
Logger.getLogger(ThunderbirdMboxFileIngestService.class.getName()).log(Level.WARNING, null, ex);
Logger.getLogger(ThunderbirdMboxFileIngestModule.class.getName()).log(Level.WARNING, null, ex);
} catch (TikaException ex) {
Logger.getLogger(ThunderbirdMboxFileIngestService.class.getName()).log(Level.WARNING, null, ex);
Logger.getLogger(ThunderbirdMboxFileIngestModule.class.getName()).log(Level.WARNING, null, ex);
}
}
@ -235,9 +239,9 @@ public class ThunderbirdMboxFileIngestService implements IngestServiceAbstractFi
@Override
public void complete() {
logger.log(Level.INFO, "complete()");
managerProxy.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "COMPLETE"));
services.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "COMPLETE"));
//service specific cleanup due completion here
//module specific cleanup due completion here
}
@Override
@ -251,23 +255,23 @@ public class ThunderbirdMboxFileIngestService implements IngestServiceAbstractFi
}
@Override
public void init(IngestManagerProxy managerProxy) {
public void init(IngestModuleInit initContext) {
logger.log(Level.INFO, "init()");
this.managerProxy = managerProxy;
services = IngestServices.getDefault();
//service specific initialization here
//module specific initialization here
}
@Override
public void stop() {
logger.log(Level.INFO, "stop()");
//service specific cleanup due interruption here
//module specific cleanup due interruption here
}
@Override
public ServiceType getType() {
return ServiceType.AbstractFile;
public ModuleType getType() {
return ModuleType.AbstractFile;
}
@Override
@ -302,4 +306,21 @@ public class ThunderbirdMboxFileIngestService implements IngestServiceAbstractFi
@Override
public void saveSimpleConfiguration() {
}
/**
* Process content hierarchy and return true if content is a file and is set as known
*/
private class GetIsFileKnownVisitor extends ContentVisitor.Default<Boolean> {
@Override
protected Boolean defaultVisit(Content cntnt) {
return false;
}
@Override
public Boolean visit(org.sleuthkit.datamodel.File file) {
return file.getKnown() == TskData.FileKnown.KNOWN;
}
}
}

View File

@ -2,9 +2,9 @@
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.2//EN" "http://www.netbeans.org/dtds/filesystem-1_2.dtd">
<filesystem>
<folder name="Services">
<file name="org-sleuthkit-autopsy-thunderbirdparser-ThunderbirdMboxFilervice.instance">
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.ingest.IngestServiceAbstractFile"/>
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.thunderbirdparser.ThunderbirdMboxFileIngestService.getDefault"/>
<file name="org-sleuthkit-autopsy-thunderbirdparser-ThunderbirdMboxFileModule.instance">
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile"/>
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.thunderbirdparser.ThunderbirdMboxFileIngestModule.getDefault"/>
<attr name="position" intvalue="1050"/>
</file>
</folder>