Conflicts: (due to line ending problems)
	Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java
	build-windows.xml
	build.xml
This commit is contained in:
Jeff Wallace 2013-08-22 09:54:56 -04:00
commit 65bb4a05ed
65 changed files with 3618 additions and 3177 deletions

View File

@ -1,4 +1,5 @@
Changes to make to API when we are ready to make backward incompatible changes: Changes to make to API when we are ready to make backward incompatible changes:
- HTMLReport has special API for more context on columns and special handling in REportGenerator. Change all reports to the new API. - HTMLReport has special API for more context on columns and special handling in REportGenerator. Change all reports to the new API.
- DataaContentViewer.isPreferred does not need isSupported to be passed in - DataContentViewer.isPreferred does not need isSupported to be passed in
- DataContentViewerHex and STrings can have the public setDataView methods removed in favor of the new private ones

View File

@ -109,7 +109,7 @@ public final class AddImageAction extends CallableSystemAction implements Presen
Logger.noteAction(AddImageAction.class); Logger.noteAction(AddImageAction.class);
final IngestConfigurator ingestConfig = Lookup.getDefault().lookup(IngestConfigurator.class); final IngestConfigurator ingestConfig = Lookup.getDefault().lookup(IngestConfigurator.class);
if (ingestConfig.isIngestRunning()) { if (null != ingestConfig && ingestConfig.isIngestRunning()) {
final String msg = "<html>Ingest is ongoing on another data source. Adding a new source now might slow down the current ingest.<br />Do you want to proceed and add a new data source now?</html>"; final String msg = "<html>Ingest is ongoing on another data source. Adding a new source now might slow down the current ingest.<br />Do you want to proceed and add a new data source now?</html>";
if (JOptionPane.showConfirmDialog(null, msg, "Ingest in progress", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.NO_OPTION) { if (JOptionPane.showConfirmDialog(null, msg, "Ingest in progress", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.NO_OPTION) {
return; return;
@ -128,7 +128,6 @@ public final class AddImageAction extends CallableSystemAction implements Presen
dialog.setVisible(true); dialog.setVisible(true);
dialog.toFront(); dialog.toFront();
// Do any cleanup that needs to happen (potentially: stopping the // Do any cleanup that needs to happen (potentially: stopping the
//add-image process, reverting an image) //add-image process, reverting an image)
runCleanupTasks(); runCleanupTasks();

View File

@ -55,7 +55,7 @@ import org.sleuthkit.datamodel.TskException;
class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> { class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
private static final Logger logger = Logger.getLogger(AddImageWizardPanel3.class.getName()); private static final Logger logger = Logger.getLogger(AddImageWizardPanel3.class.getName());
private IngestConfigurator ingestConfig = Lookup.getDefault().lookup(IngestConfigurator.class); private IngestConfigurator ingestConfig;
/** /**
* The visual component that displays this panel. If you need to access the * The visual component that displays this panel. If you need to access the
* component from this class, just use getComponent(). * component from this class, just use getComponent().
@ -85,6 +85,8 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
AddImageWizardPanel3(AddImageAction action, AddImageWizardPanel2 wizPanel) { AddImageWizardPanel3(AddImageAction action, AddImageWizardPanel2 wizPanel) {
this.action = action; this.action = action;
this.wizPanel = wizPanel; this.wizPanel = wizPanel;
ingestConfig = Lookup.getDefault().lookup(IngestConfigurator.class);
ingestConfig.setContext(AddImageWizardPanel3.class.getCanonicalName());
} }
/** /**

View File

@ -326,7 +326,7 @@ public class Case implements SleuthkitCase.ErrorObserver {
* @param imgId the ID of the image that being added * @param imgId the ID of the image that being added
* @param timeZone the timeZone of the image where it's added * @param timeZone the timeZone of the image where it's added
*/ */
Image addImage(String imgPath, long imgId, String timeZone) throws CaseActionException { public Image addImage(String imgPath, long imgId, String timeZone) throws CaseActionException {
logger.log(Level.INFO, "Adding image to Case. imgPath: {0} ID: {1} TimeZone: {2}", new Object[]{imgPath, imgId, timeZone}); logger.log(Level.INFO, "Adding image to Case. imgPath: {0} ID: {1} TimeZone: {2}", new Object[]{imgPath, imgId, timeZone});
try { try {
@ -372,7 +372,7 @@ public class Case implements SleuthkitCase.ErrorObserver {
/** /**
* Closes this case. This methods close the xml and clear all the fields. * Closes this case. This methods close the xml and clear all the fields.
*/ */
void closeCase() throws CaseActionException { public void closeCase() throws CaseActionException {
changeCase(null); changeCase(null);
try { try {

View File

@ -0,0 +1,159 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 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.casemodule;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.ingest.IngestDialogPanel;
import static org.sleuthkit.autopsy.ingest.IngestDialogPanel.DISABLED_MOD;
import static org.sleuthkit.autopsy.ingest.IngestDialogPanel.PARSE_UNALLOC;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstract;
import org.sleuthkit.datamodel.Content;
@ServiceProvider(service = IngestConfigurator.class)
public class GeneralIngestConfigurator implements IngestConfigurator {
private List<Content> contentToIngest;
private IngestManager manager;
private IngestDialogPanel ingestDialogPanel;
private String moduleContext;
public GeneralIngestConfigurator() {
this.moduleContext = IngestManager.MODULE_PROPERTIES; // Hard-code this for now.
ingestDialogPanel = new IngestDialogPanel();
ingestDialogPanel.setContext(moduleContext);
manager = IngestManager.getDefault();
loadSettings();
}
@Override
public void setContext(String context) {
moduleContext = context;
ingestDialogPanel.setContext(moduleContext);
reload();
}
@Override
public JPanel getIngestConfigPanel() {
return ingestDialogPanel;
}
@Override
public void setContent(List<Content> inputContent) {
this.contentToIngest = inputContent;
}
@Override
public void start() {
// Get the list of ingest modules selected by the user.
List<IngestModuleAbstract> modulesToStart = ingestDialogPanel.getModulesToStart();
// Get the user's selection of whether or not to process unallocated space.
manager.setProcessUnallocSpace(ingestDialogPanel.processUnallocSpaceEnabled());
// Start the ingest.
if (!modulesToStart.isEmpty()) {
manager.execute(modulesToStart, contentToIngest);
}
}
@Override
public void save() {
// Save the user's configuration of the currently selected module.
IngestModuleAbstract currentModule = ingestDialogPanel.getCurrentIngestModule();
if (currentModule != null && currentModule.hasSimpleConfiguration()) {
currentModule.saveSimpleConfiguration();
}
// Create a list of the modules the user wants to be disabled.
List<IngestModuleAbstract> disabledModules = IngestManager.getDefault().enumerateAllModules();
disabledModules.removeAll(ingestDialogPanel.getModulesToStart());
String disabledModulesCsv = moduleListToCsv(disabledModules);
// Save the user's general ingest configuration.
ModuleSettings.setConfigSetting(moduleContext, DISABLED_MOD, disabledModulesCsv);
String processUnalloc = Boolean.toString(ingestDialogPanel.processUnallocSpaceEnabled());
ModuleSettings.setConfigSetting(moduleContext, PARSE_UNALLOC, processUnalloc);
}
@Override
public void reload() {
loadSettings();
}
@Override
public boolean isIngestRunning() {
return manager.isIngestRunning();
}
private static String moduleListToCsv(List<IngestModuleAbstract> lst) {
if (lst == null || lst.isEmpty()) {
return "";
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < lst.size() - 1; ++i) {
sb.append(lst.get(i).getName()).append(", ");
}
// and the last one
sb.append(lst.get(lst.size() - 1).getName());
return sb.toString();
}
private static List<IngestModuleAbstract> csvToModuleList(String csv) {
List<IngestModuleAbstract> modules = new ArrayList<>();
if (csv == null || csv.isEmpty()) {
return modules;
}
String[] moduleNames = csv.split(", ");
List<IngestModuleAbstract> allModules = IngestManager.getDefault().enumerateAllModules();
for (String moduleName : moduleNames) {
for (IngestModuleAbstract module : allModules) {
if (moduleName.equals(module.getName())) {
modules.add(module);
break;
}
}
}
return modules;
}
private void loadSettings() {
// get the csv list of disabled modules
String disabledModulesCsv = ModuleSettings.getConfigSetting(moduleContext, DISABLED_MOD);
// create a list of modules from it
List<IngestModuleAbstract> disabledModules = csvToModuleList(disabledModulesCsv);
// tell the ingestDialogPanel to unselect these modules
ingestDialogPanel.setDisabledModules(disabledModules);
boolean processUnalloc = Boolean.parseBoolean(ModuleSettings.getConfigSetting(moduleContext, PARSE_UNALLOC));
ingestDialogPanel.setProcessUnallocSpaceEnabled(processUnalloc);
}
}

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011 Basis Technology Corp. * Copyright 2011-2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -60,4 +60,10 @@ public interface IngestConfigurator {
*/ */
boolean isIngestRunning(); boolean isIngestRunning();
/**
* Set the context for the configuration.
* @param context
*/
public void setContext(String context);
} }

View File

@ -77,9 +77,11 @@ public class FileManager implements Closeable {
} }
/** /**
* @param dataSource data source Content (Image, parent-less * Finds a set of files that meets the name criteria.
* VirtualDirectory) where to find files * @param dataSource Root data source to limit search results to (Image,
* @param fileName the name of the file or directory to match * VirtualDirectory, etc.).
* @param fileName Pattern of the name of the file or directory to match (case
* insensitive, used in LIKE SQL statement).
* @return a list of AbstractFile for files/directories whose name matches * @return a list of AbstractFile for files/directories whose name matches
* the given fileName * the given fileName
*/ */
@ -90,11 +92,15 @@ public class FileManager implements Closeable {
return tskCase.findFiles(dataSource, fileName); return tskCase.findFiles(dataSource, fileName);
} }
/** /**
* @param dataSource data source Content (Image, parent-less * Finds a set of files that meets the name criteria.
* VirtualDirectory) where to find files * @param dataSource Root data source to limit search results to (Image,
* @param fileName the name of the file or directory to match * VirtualDirectory, etc.).
* @param dirName the name of a parent directory of fileName * @param fileName Pattern of the name of the file or directory to match (case
* insensitive, used in LIKE SQL statement).
* @param dirName Pattern of the name of the parent directory to use as the root
* of the search (case insensitive, used in LIKE SQL statement).
* @return a list of AbstractFile for files/directories whose name matches * @return a list of AbstractFile for files/directories whose name matches
* fileName and whose parent directory contains dirName. * fileName and whose parent directory contains dirName.
*/ */
@ -106,10 +112,12 @@ public class FileManager implements Closeable {
} }
/** /**
* @param dataSource data source Content (Image, parent-less * Finds a set of files that meets the name criteria.
* VirtualDirectory) where to find files * @param dataSource Root data source to limit search results to (Image,
* @param fileName the name of the file or directory to match * VirtualDirectory, etc.).
* @param parentFile parent file/dir of the file to find * @param fileName Pattern of the name of the file or directory to match (case
* insensitive, used in LIKE SQL statement).
* @param parentFile Object of root/parent directory to restrict search to.
* @return a list of AbstractFile for files/directories whose name matches * @return a list of AbstractFile for files/directories whose name matches
* fileName and that were inside a directory described by parentFsContent. * fileName and that were inside a directory described by parentFsContent.
*/ */

View File

@ -27,7 +27,6 @@ import org.openide.nodes.Node;
* Interface for the different viewers that show a set of nodes in the DataResult area. * Interface for the different viewers that show a set of nodes in the DataResult area.
* AbstractDataResultViewer has default implementations for the action handlers. * AbstractDataResultViewer has default implementations for the action handlers.
* *
* @author jantonius
*/ */
public interface DataResultViewer { public interface DataResultViewer {
/** /**
@ -47,7 +46,7 @@ public interface DataResultViewer {
public DataResultViewer createInstance(); public DataResultViewer createInstance();
/** /**
* Get Component to display this DataResultViewer * Get the Swing component (i.e. JPanel) for this viewer
*/ */
public Component getComponent(); public Component getComponent();
@ -74,7 +73,7 @@ public interface DataResultViewer {
public void setSelectedNodes(Node[] selected); public void setSelectedNodes(Node[] selected);
/** /**
* Checks whether the currently selected node * Checks whether the currently selected root node
* is supported by this viewer * is supported by this viewer
* @param selectedNode the selected node * @param selectedNode the selected node
* @return True if supported, else false * @return True if supported, else false

View File

@ -36,7 +36,8 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
/** /**
* Holds commonalities between all DataResultViewers * Holds commonalities between all DataResultViewers, such as:
* - Pushes selection to DataContentViewers
*/ */
public abstract class AbstractDataResultViewer extends JPanel implements public abstract class AbstractDataResultViewer extends JPanel implements
DataResultViewer, Provider { DataResultViewer, Provider {
@ -81,21 +82,17 @@ public abstract class AbstractDataResultViewer extends JPanel implements
// change the cursor to "waiting cursor" for this operation // change the cursor to "waiting cursor" for this operation
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
try { try {
Node selectedNode = getSelectedNode(); Node[] selectedNodes = getExplorerManager().getSelectedNodes();
if (selectedNodes.length == 1) {
nodeSelected(selectedNodes[0]);
nodeSelected(selectedNode);
if (selectedNode != null) {
// there's a new/changed node to display // there's a new/changed node to display
Node newSelectedNode = selectedNode; // get the selected Node on the table
// push the node to default "DataContent" // push the node to default "DataContent"
//TODO only the active viewer should be calling setNode //TODO only the active viewer should be calling setNode
//not all of them, otherwise it results in multiple setNode() invocations //not all of them, otherwise it results in multiple setNode() invocations
//alternative is to use a single instance of the event listener //alternative is to use a single instance of the event listener
//, per top component and not the tab perhaps //, per top component and not the tab perhaps
contentViewer.setNode(newSelectedNode); contentViewer.setNode(selectedNodes[0]);
} else { } else {
// clear the node viewer // clear the node viewer
contentViewer.setNode(null); contentViewer.setNode(null);
@ -131,6 +128,7 @@ public abstract class AbstractDataResultViewer extends JPanel implements
} }
} }
@Deprecated
public Node getSelectedNode() { public Node getSelectedNode() {
Node result = null; Node result = null;
Node[] selectedNodes = this.getExplorerManager().getSelectedNodes(); Node[] selectedNodes = this.getExplorerManager().getSelectedNodes();

View File

@ -178,7 +178,7 @@ public class DataContentPanel extends javax.swing.JPanel implements DataContent,
jTabbedPane1.setEnabledAt(i, true); jTabbedPane1.setEnabledAt(i, true);
// remember the viewer with the highest preference value // remember the viewer with the highest preference value
int currentPreferred = dcv.isPreferred(selectedNode, false); int currentPreferred = dcv.isPreferred(selectedNode, true);
if (currentPreferred > maxPreferred) { if (currentPreferred > maxPreferred) {
preferredViewerIndex = i; preferredViewerIndex = i;
maxPreferred = currentPreferred; maxPreferred = currentPreferred;
@ -191,7 +191,14 @@ public class DataContentPanel extends javax.swing.JPanel implements DataContent,
// set the tab to the one the user wants, then set that viewer's node. // set the tab to the one the user wants, then set that viewer's node.
jTabbedPane1.setSelectedIndex(tabIndex); jTabbedPane1.setSelectedIndex(tabIndex);
viewers.get(tabIndex).setNode(selectedNode); UpdateWrapper dcv = viewers.get(tabIndex);
// this is really only needed if no tabs were enabled
if (jTabbedPane1.isEnabledAt(tabIndex) == false) {
dcv.resetComponent();
}
else {
dcv.setNode(selectedNode);
}
} }
@Override @Override

View File

@ -231,18 +231,21 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
@Override @Override
public void setNode(Node selectedNode) { public void setNode(Node selectedNode) {
if (selectedNode == null) { if (selectedNode == null) {
this.setDataView(new ArrayList<BlackboardArtifact>(), 1); resetComponent();
return; return;
} }
Lookup lookup = selectedNode.getLookup(); Lookup lookup = selectedNode.getLookup();
Content content = lookup.lookup(Content.class); Content content = lookup.lookup(Content.class);
if (content != null) { if (content == null) {
try { resetComponent();
this.setDataView(content.getAllArtifacts(), 1); return;
} catch (TskException ex) { }
logger.log(Level.WARNING, "Couldn't get artifacts: ", ex);
} try {
this.setDataView(content.getAllArtifacts(), 1);
} catch (TskException ex) {
logger.log(Level.WARNING, "Couldn't get artifacts: ", ex);
} }
// focus on a specific artifact if it is in the node // focus on a specific artifact if it is in the node
@ -279,9 +282,11 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
this.artifacts = new ArrayList<BlackboardArtifact>(); this.artifacts = new ArrayList<BlackboardArtifact>();
currentPageLabel.setText(""); currentPageLabel.setText("");
totalPageLabel.setText(""); totalPageLabel.setText("");
outputViewPane.setText("");
prevPageButton.setEnabled(false); prevPageButton.setEnabled(false);
nextPageButton.setEnabled(false); nextPageButton.setEnabled(false);
setComponentsVisibility(false); // hides the components that not needed setComponentsVisibility(false); // hides the components that not needed
this.setCursor(null);
} }
/** /**
@ -380,9 +385,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
if(artifacts.isEmpty()){ if(artifacts.isEmpty()){
setComponentsVisibility(false); resetComponent();
this.setCursor(null);
outputViewPane.setText("");
return; return;
} }
this.artifacts = artifacts; this.artifacts = artifacts;

View File

@ -247,7 +247,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
currentOffset -= pageLength; currentOffset -= pageLength;
currentPage = currentPage - 1; currentPage = currentPage - 1;
currentPageLabel.setText(Integer.toString(currentPage)); currentPageLabel.setText(Integer.toString(currentPage));
setDataView(dataSource, currentOffset, false); setDataView(dataSource, currentOffset);
}//GEN-LAST:event_prevPageButtonActionPerformed }//GEN-LAST:event_prevPageButtonActionPerformed
private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed
@ -255,7 +255,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
currentOffset += pageLength; currentOffset += pageLength;
currentPage = currentPage + 1; currentPage = currentPage + 1;
currentPageLabel.setText(Integer.toString(currentPage)); currentPageLabel.setText(Integer.toString(currentPage));
setDataView(dataSource, currentOffset, false); setDataView(dataSource, currentOffset);
}//GEN-LAST:event_nextPageButtonActionPerformed }//GEN-LAST:event_nextPageButtonActionPerformed
private void goToPageTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_goToPageTextFieldActionPerformed private void goToPageTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_goToPageTextFieldActionPerformed
@ -275,7 +275,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
currentOffset = (pageNumber - 1) * pageLength; currentOffset = (pageNumber - 1) * pageLength;
currentPage = pageNumber; currentPage = pageNumber;
currentPageLabel.setText(Integer.toString(currentPage)); currentPageLabel.setText(Integer.toString(currentPage));
setDataView(dataSource, currentOffset, false); setDataView(dataSource, currentOffset);
}//GEN-LAST:event_goToPageTextFieldActionPerformed }//GEN-LAST:event_goToPageTextFieldActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JMenuItem copyMenuItem; private javax.swing.JMenuItem copyMenuItem;
@ -295,14 +295,23 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
private javax.swing.JLabel totalPageLabel; private javax.swing.JLabel totalPageLabel;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
@Deprecated
public void setDataView(Content dataSource, long offset, boolean reset) {
if (reset) {
resetComponent();
return;
}
setDataView(dataSource, offset);
}
/** /**
* Sets the DataView (The tabbed panel) * Sets the DataView (The tabbed panel)
* *
* @param dataSource the content that want to be shown * @param dataSource the content that want to be shown
* @param offset the starting offset * @param offset the starting offset
* @param reset whether to reset the dataView or not
*/ */
public void setDataView(Content dataSource, long offset, boolean reset) { private void setDataView(Content dataSource, long offset) {
if (dataSource == null) { if (dataSource == null) {
return; return;
} }
@ -312,14 +321,12 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
this.dataSource = dataSource; this.dataSource = dataSource;
String errorText = null; String errorText = null;
Boolean setVisible = false;
int bytesRead = 0; int bytesRead = 0;
if (!reset && dataSource.getSize() > 0) { if (dataSource.getSize() > 0) {
try { try {
bytesRead = dataSource.read(data, offset, pageLength); // read the data bytesRead = dataSource.read(data, offset, pageLength); // read the data
} catch (TskException ex) { } catch (TskException ex) {
setVisible = true;
errorText = "(offset " + currentOffset + "-" + (currentOffset + pageLength) errorText = "(offset " + currentOffset + "-" + (currentOffset + pageLength)
+ " could not be read)"; + " could not be read)";
logger.log(Level.WARNING, "Error while trying to show the hex content.", ex); logger.log(Level.WARNING, "Error while trying to show the hex content.", ex);
@ -327,73 +334,58 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
} }
// set the data on the bottom and show it // set the data on the bottom and show it
if (bytesRead > 0) { if (bytesRead <= 0) {
setVisible = true;
}
else {
errorText = "(offset " + currentOffset + "-" + (currentOffset + pageLength) errorText = "(offset " + currentOffset + "-" + (currentOffset + pageLength)
+ " could not be read)"; + " could not be read)";
setVisible = true;
} }
// disable or enable the next button // disable or enable the next button
if (!reset && offset + pageLength < dataSource.getSize()) { if ((errorText != null) && (offset + pageLength < dataSource.getSize())) {
nextPageButton.setEnabled(true); nextPageButton.setEnabled(true);
} else { } else {
nextPageButton.setEnabled(false); nextPageButton.setEnabled(false);
} }
if (offset == 0) { if ((offset == 0) || (errorText == null)) {
prevPageButton.setEnabled(false); prevPageButton.setEnabled(false);
currentPage = 1; // reset the page number currentPage = 1; // reset the page number
} else { } else {
prevPageButton.setEnabled(true); prevPageButton.setEnabled(true);
} }
if (setVisible) { int totalPage = Math.round((dataSource.getSize() - 1) / pageLength) + 1;
int totalPage = Math.round((dataSource.getSize() - 1) / pageLength) + 1; totalPageLabel.setText(Integer.toString(totalPage));
totalPageLabel.setText(Integer.toString(totalPage)); currentPageLabel.setText(Integer.toString(currentPage));
currentPageLabel.setText(Integer.toString(currentPage)); setComponentsVisibility(true); // shows the components that not needed
setComponentsVisibility(true); // shows the components that not needed
// set the output view // set the output view
if (errorText == null) {
int showLength = bytesRead < pageLength ? bytesRead : (int) pageLength; int showLength = bytesRead < pageLength ? bytesRead : (int) pageLength;
if (errorText == null) { outputViewPane.setText(DataConversion.byteArrayToHex(data, showLength, offset, outputViewPane.getFont()));
outputViewPane.setText(DataConversion.byteArrayToHex(data, showLength, offset, outputViewPane.getFont())); }
} else {
else { outputViewPane.setText(errorText);
outputViewPane.setText(errorText);
}
} else {
// reset or hide the labels
totalPageLabel.setText("");
currentPageLabel.setText("");
outputViewPane.setText(""); // reset the output view
setComponentsVisibility(false); // hides the components that not needed
} }
outputViewPane.moveCaretPosition(0); outputViewPane.moveCaretPosition(0);
this.setCursor(null); this.setCursor(null);
} }
@Override @Override
public void setNode(Node selectedNode) { public void setNode(Node selectedNode) {
if ((selectedNode == null) || (!isSupported(selectedNode))) { if ((selectedNode == null) || (!isSupported(selectedNode))) {
setDataView(null, 0, true); resetComponent();
return; return;
} }
Content content = (selectedNode).getLookup().lookup(Content.class); Content content = (selectedNode).getLookup().lookup(Content.class);
if (content == null) { if (content == null) {
this.setDataView(null, 0, true); resetComponent();
return; return;
} }
this.setDataView(content, 0, false); this.setDataView(content, 0);
} }
@Override @Override
@ -420,8 +412,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
this.dataSource = null; this.dataSource = null;
currentPageLabel.setText(""); currentPageLabel.setText("");
totalPageLabel.setText(""); totalPageLabel.setText("");
prevPageButton.setEnabled(false); outputViewPane.setText("");
nextPageButton.setEnabled(false);
setComponentsVisibility(false); // hides the components that not needed setComponentsVisibility(false); // hides the components that not needed
} }
@ -448,8 +439,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
return false; return false;
} }
Content content = node.getLookup().lookup(Content.class); Content content = node.getLookup().lookup(Content.class);
if (content != null && content.getSize() > 0) {
if (content != null && content.getSize() != 0) {
return true; return true;
} }

View File

@ -112,12 +112,13 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
public void setNode(Node selectedNode) { public void setNode(Node selectedNode) {
try { try {
if (selectedNode == null) { if (selectedNode == null) {
videoPanel.reset(); resetComponent();
return; return;
} }
AbstractFile file = selectedNode.getLookup().lookup(AbstractFile.class); AbstractFile file = selectedNode.getLookup().lookup(AbstractFile.class);
if (file == null) { if (file == null) {
resetComponent();
return; return;
} }
@ -180,15 +181,13 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
@Override @Override
public void resetComponent() { public void resetComponent() {
// we don't want this to do anything videoPanel.reset();
// because we already reset on each selected node
} }
@Override @Override
public boolean isSupported(Node node) { public boolean isSupported(Node node) {
if (node == null) { if (node == null) {
return false; return false;
} }
@ -198,13 +197,11 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
return false; return false;
} }
if (file.getSize() == 0) { if (file.getSize() == 0) {
return false; return false;
} }
String name = file.getName().toLowerCase(); String name = file.getName().toLowerCase();
if (imagePanelInited && containsExt(name, IMAGES)) { if (imagePanelInited && containsExt(name, IMAGES)) {
return true; return true;
} //for gstreamer formats, check if initialized first, then } //for gstreamer formats, check if initialized first, then

View File

@ -265,7 +265,7 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
currentOffset -= pageLength; currentOffset -= pageLength;
currentPage = currentPage - 1; currentPage = currentPage - 1;
currentPageLabel.setText(Integer.toString(currentPage)); currentPageLabel.setText(Integer.toString(currentPage));
setDataView(dataSource, currentOffset, false); setDataView(dataSource, currentOffset);
}//GEN-LAST:event_prevPageButtonActionPerformed }//GEN-LAST:event_prevPageButtonActionPerformed
private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed
@ -273,7 +273,7 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
currentOffset += pageLength; currentOffset += pageLength;
currentPage = currentPage + 1; currentPage = currentPage + 1;
currentPageLabel.setText(Integer.toString(currentPage)); currentPageLabel.setText(Integer.toString(currentPage));
setDataView(dataSource, currentOffset, false); setDataView(dataSource, currentOffset);
}//GEN-LAST:event_nextPageButtonActionPerformed }//GEN-LAST:event_nextPageButtonActionPerformed
private void goToPageTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_goToPageTextFieldActionPerformed private void goToPageTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_goToPageTextFieldActionPerformed
@ -293,13 +293,13 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
currentOffset = (pageNumber - 1) * pageLength; currentOffset = (pageNumber - 1) * pageLength;
currentPage = pageNumber; currentPage = pageNumber;
currentPageLabel.setText(Integer.toString(currentPage)); currentPageLabel.setText(Integer.toString(currentPage));
setDataView(dataSource, currentOffset, false); setDataView(dataSource, currentOffset);
}//GEN-LAST:event_goToPageTextFieldActionPerformed }//GEN-LAST:event_goToPageTextFieldActionPerformed
private void languageComboActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_languageComboActionPerformed private void languageComboActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_languageComboActionPerformed
if (dataSource != null) { if (dataSource != null) {
setDataView(dataSource, currentOffset, false); setDataView(dataSource, currentOffset);
} }
}//GEN-LAST:event_languageComboActionPerformed }//GEN-LAST:event_languageComboActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
@ -322,14 +322,22 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
private javax.swing.JLabel totalPageLabel; private javax.swing.JLabel totalPageLabel;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
@Deprecated
public void setDataView(Content dataSource, long offset, boolean reset) {
if (reset) {
resetComponent();
return;
}
setDataView(dataSource, offset);
}
/** /**
* Sets the DataView (The tabbed panel) * Sets the DataView (The tabbed panel)
* *
* @param dataSource the content that want to be shown * @param dataSource the content that want to be shown
* @param offset the starting offset * @param offset the starting offset
* @param reset whether to reset the dataView or not
*/ */
public void setDataView(Content dataSource, long offset, boolean reset) { private void setDataView(Content dataSource, long offset) {
if (dataSource == null) { if (dataSource == null) {
return; return;
} }
@ -342,14 +350,12 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
int bytesRead = 0; int bytesRead = 0;
// set the data on the bottom and show it // set the data on the bottom and show it
String text = ""; String text = "";
Boolean setVisible = false; if (dataSource.getSize() > 0) {
if (!reset && dataSource.getSize() > 0) {
try { try {
bytesRead = dataSource.read(data, offset, pageLength); // read the data bytesRead = dataSource.read(data, offset, pageLength); // read the data
} catch (TskException ex) { } catch (TskException ex) {
text = "(offset " + currentOffset + "-" + (currentOffset + pageLength) text = "(offset " + currentOffset + "-" + (currentOffset + pageLength)
+ " could not be read)"; + " could not be read)";
setVisible = true;
logger.log(Level.WARNING, "Error while trying to show the String content.", ex); logger.log(Level.WARNING, "Error while trying to show the String content.", ex);
} }
} }
@ -364,16 +370,13 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
text = "(offset " + currentOffset + "-" + (currentOffset + pageLength) text = "(offset " + currentOffset + "-" + (currentOffset + pageLength)
+ " contains no text)"; + " contains no text)";
} }
setVisible = true;
} else { } else {
text = "(offset " + currentOffset + "-" + (currentOffset + pageLength) text = "(offset " + currentOffset + "-" + (currentOffset + pageLength)
+ " could not be read)"; + " could not be read)";
setVisible = true;
} }
// disable or enable the next button // disable or enable the next button
if (!reset && offset + pageLength < dataSource.getSize()) { if (offset + pageLength < dataSource.getSize()) {
nextPageButton.setEnabled(true); nextPageButton.setEnabled(true);
} else { } else {
nextPageButton.setEnabled(false); nextPageButton.setEnabled(false);
@ -386,23 +389,15 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
prevPageButton.setEnabled(true); prevPageButton.setEnabled(true);
} }
if (setVisible) {
int totalPage = Math.round((dataSource.getSize() - 1) / pageLength) + 1; int totalPage = Math.round((dataSource.getSize() - 1) / pageLength) + 1;
totalPageLabel.setText(Integer.toString(totalPage)); totalPageLabel.setText(Integer.toString(totalPage));
currentPageLabel.setText(Integer.toString(currentPage)); currentPageLabel.setText(Integer.toString(currentPage));
outputViewPane.setText(text); // set the output view outputViewPane.setText(text); // set the output view
setComponentsVisibility(true); // shows the components that not needed setComponentsVisibility(true); // shows the components that not needed
} else {
// reset or hide the labels
totalPageLabel.setText("");
currentPageLabel.setText("");
outputViewPane.setText(""); // reset the output view
setComponentsVisibility(false); // hides the components that not needed
}
outputViewPane.moveCaretPosition(0); outputViewPane.moveCaretPosition(0);
this.setCursor(null); this.setCursor(null);
} }
/** /**
@ -422,31 +417,28 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
goToPageLabel.setVisible(isVisible); goToPageLabel.setVisible(isVisible);
languageCombo.setVisible(isVisible); languageCombo.setVisible(isVisible);
languageLabel.setVisible(isVisible); languageLabel.setVisible(isVisible);
} }
@Override @Override
public void setNode(Node selectedNode) { public void setNode(Node selectedNode) {
if (!isSupported(selectedNode)) { if ((selectedNode == null) || (!isSupported(selectedNode))) {
setDataView(null, 0, true); resetComponent();
return; return;
} }
if (selectedNode != null) {
Lookup lookup = selectedNode.getLookup(); Lookup lookup = selectedNode.getLookup();
Content content = lookup.lookup(Content.class); Content content = lookup.lookup(Content.class);
if (content if (content != null) {
!= null) { this.setDataView(content, 0);
this.setDataView(content, 0, false); return;
} else {
StringContent scontent = selectedNode.getLookup().lookup(StringContent.class);
if (scontent != null) {
this.setDataView(scontent);
return; return;
} else {
StringContent scontent = selectedNode.getLookup().lookup(StringContent.class);
if (scontent != null) {
this.setDataView(scontent);
return;
}
} }
} }
this.setDataView(null, 0, true); resetComponent();
} }
@Override @Override
@ -474,6 +466,7 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
totalPageLabel.setText(""); totalPageLabel.setText("");
prevPageButton.setEnabled(false); prevPageButton.setEnabled(false);
nextPageButton.setEnabled(false); nextPageButton.setEnabled(false);
outputViewPane.setText(""); // reset the output view
setComponentsVisibility(false); // hides the components that not needed setComponentsVisibility(false); // hides the components that not needed
} }
@ -481,14 +474,9 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
public boolean isSupported(Node node) { public boolean isSupported(Node node) {
if (node == null) { if (node == null) {
return false; return false;
} }
Content content = node.getLookup().lookup(Content.class); Content content = node.getLookup().lookup(Content.class);
if (content != null && content.getSize() > 0) {
if (content
!= null && content.getSize()
!= 0) {
return true; return true;
} }

View File

@ -23,6 +23,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataResult; import org.sleuthkit.autopsy.corecomponentinterfaces.DataResult;
import java.util.logging.Level; import java.util.logging.Level;
import org.openide.explorer.ExplorerUtils;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.windows.TopComponent; import org.openide.windows.TopComponent;
import org.openide.nodes.Node; import org.openide.nodes.Node;
@ -54,6 +55,7 @@ public class DataResultTopComponent extends TopComponent implements DataResult {
private static final Logger logger = Logger.getLogger(DataResultTopComponent.class.getName()); private static final Logger logger = Logger.getLogger(DataResultTopComponent.class.getName());
private DataResultPanel dataResultPanel; //embedded component with all the logic private DataResultPanel dataResultPanel; //embedded component with all the logic
private boolean isMain; private boolean isMain;
private boolean lookupSet = false;
private String customModeName; private String customModeName;
//keep track of tcs openeded for menu presenters //keep track of tcs openeded for menu presenters
@ -260,6 +262,21 @@ public class DataResultTopComponent extends TopComponent implements DataResult {
super.componentOpened(); super.componentOpened();
this.dataResultPanel.open(); this.dataResultPanel.open();
/* @@@ Short-term hack to associate lookup with the table view so that we can do multi-select.
* Longer-term solution is to use same explorer Manager for all viewers.
*/
if (!this.lookupSet) {
List <DataResultViewer> resultViewers = this.dataResultPanel.getViewers();
for (DataResultViewer viewer : resultViewers) {
if (viewer instanceof DataResultViewerTable) {
associateLookup(ExplorerUtils.createLookup(((DataResultViewerTable)viewer).getExplorerManager(), getActionMap()));
break;
}
}
this.lookupSet = true;
}
} }

View File

@ -62,7 +62,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
ov.setAllowedDropActions(DnDConstants.ACTION_NONE); ov.setAllowedDropActions(DnDConstants.ACTION_NONE);
// only allow one item to be selected at a time // only allow one item to be selected at a time
ov.getOutline().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); ov.getOutline().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
// don't show the root node // don't show the root node
ov.getOutline().setRootVisible(false); ov.getOutline().setRootVisible(false);

View File

@ -144,6 +144,10 @@ public class MediaViewImagePanel extends javax.swing.JPanel {
try { try {
//original input stream //original input stream
BufferedImage bi = ImageIO.read(inputStream); BufferedImage bi = ImageIO.read(inputStream);
if (bi == null) {
logger.log(Level.WARNING, "Could image reader not found for file: " + fileName);
return;
}
//scale image using Scalr //scale image using Scalr
BufferedImage biScaled = ScalrWrapper.resizeHighQuality(bi, (int) dims.getWidth(), (int) dims.getHeight()); BufferedImage biScaled = ScalrWrapper.resizeHighQuality(bi, (int) dims.getWidth(), (int) dims.getHeight());
//convert from awt imageto fx image //convert from awt imageto fx image

View File

@ -86,6 +86,9 @@ class ThumbnailViewNode extends FilterNode {
if (getFile(content.getId()).exists()) { if (getFile(content.getId()).exists()) {
try { try {
icon = ImageIO.read(getFile(content.getId())); icon = ImageIO.read(getFile(content.getId()));
if (icon == null) {
icon = ThumbnailViewNode.defaultIcon;
}
} catch (IOException ex) { } catch (IOException ex) {
icon = ThumbnailViewNode.defaultIcon; icon = ThumbnailViewNode.defaultIcon;
} }
@ -120,6 +123,10 @@ class ThumbnailViewNode extends FilterNode {
try { try {
inputStream = new ReadContentInputStream(content); inputStream = new ReadContentInputStream(content);
BufferedImage bi = ImageIO.read(inputStream); BufferedImage bi = ImageIO.read(inputStream);
if (bi == null) {
logger.log(Level.WARNING, "No image reader for file: " + content.getName());
return null;
}
BufferedImage biScaled = ScalrWrapper.resizeFast(bi, 100, 100); BufferedImage biScaled = ScalrWrapper.resizeFast(bi, 100, 100);
return biScaled; return biScaled;
}catch (OutOfMemoryError e) { }catch (OutOfMemoryError e) {

View File

@ -19,12 +19,17 @@
package org.sleuthkit.autopsy.coreutils; package org.sleuthkit.autopsy.coreutils;
import java.io.*; import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
/** /**
* This class contains the framework to read, add, update, and remove * This class contains the framework to read, add, update, and remove
* from the property files located at %USERDIR%/Config/x.properties * from the property files located at %USERDIR%/Config/x.properties
@ -33,14 +38,11 @@ public class ModuleSettings {
// The directory where the properties file is lcoated // The directory where the properties file is lcoated
private final static String moduleDirPath = PlatformUtil.getUserConfigDirectory(); private final static String moduleDirPath = PlatformUtil.getUserConfigDirectory();
public static final String MAIN_SETTINGS="Case"; public static final String DEFAULT_CONTEXT = "GeneralContext";
public static final String MAIN_SETTINGS = "Case";
/** the constructor */ /** the constructor */
private ModuleSettings() { private ModuleSettings() {}
}
/** /**
* Makes a new config file of the specified name. Do not include the extension. * Makes a new config file of the specified name. Do not include the extension.
@ -162,8 +164,6 @@ public class ModuleSettings {
} }
} }
/** /**
* Sets the given properties file to the given setting map. * Sets the given properties file to the given setting map.
* @param moduleName - The name of the module to be written to. * @param moduleName - The name of the module to be written to.
@ -216,13 +216,11 @@ public class ModuleSettings {
} }
} }
/** /**
* Removes the given key from the given properties file. * Removes the given key from the given properties file.
* @param moduleName - The name of the properties file to be modified. * @param moduleName - The name of the properties file to be modified.
* @param key - the name of the key to remove. * @param key - the name of the key to remove.
*/ */
public static synchronized void removeProperty(String moduleName, String key){ public static synchronized void removeProperty(String moduleName, String key){
try{ try{
if(getConfigSetting(moduleName, key) != null){ if(getConfigSetting(moduleName, key) != null){
@ -268,5 +266,4 @@ public class ModuleSettings {
return new File(getPropertyPath(moduleName)); return new File(getPropertyPath(moduleName));
} }
} }
} }

View File

@ -23,7 +23,7 @@ import java.util.List;
import javax.swing.Action; import javax.swing.Action;
import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.TagAction; import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
import org.sleuthkit.autopsy.directorytree.ViewContextAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Directory; import org.sleuthkit.datamodel.Directory;
@ -67,16 +67,16 @@ public class DirectoryNode extends AbstractFsContentNode<AbstractFile> {
*/ */
@Override @Override
public Action[] getActions(boolean popup) { public Action[] getActions(boolean popup) {
List<Action> actions = new ArrayList<Action>(); List<Action> actions = new ArrayList<>();
if (!getDirectoryBrowseMode()) { if (!getDirectoryBrowseMode()) {
actions.add(new ViewContextAction("View File in Directory", this)); actions.add(new ViewContextAction("View File in Directory", this));
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
} }
actions.add(new NewWindowViewAction("View in New Window", this)); actions.add(new NewWindowViewAction("View in New Window", this));
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(new ExtractAction("Extract Directory", this)); actions.add(ExtractAction.getInstance());
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(new TagAction(this)); actions.add(TagAbstractFileAction.getInstance());
return actions.toArray(new Action[0]); return actions.toArray(new Action[0]);
} }

9
Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java Normal file → Executable file
View File

@ -25,10 +25,9 @@ import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.TagAction; import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
import org.sleuthkit.autopsy.directorytree.ViewContextAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.FsContent;
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM; import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
@ -74,7 +73,7 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
*/ */
@Override @Override
public Action[] getActions(boolean popup) { public Action[] getActions(boolean popup) {
List<Action> actionsList = new ArrayList<Action>(); List<Action> actionsList = new ArrayList<>();
if (!this.getDirectoryBrowseMode()) { if (!this.getDirectoryBrowseMode()) {
actionsList.add(new ViewContextAction("View File in Directory", this)); actionsList.add(new ViewContextAction("View File in Directory", this));
actionsList.add(null); // creates a menu separator actionsList.add(null); // creates a menu separator
@ -82,10 +81,10 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
actionsList.add(new NewWindowViewAction("View in New Window", this)); actionsList.add(new NewWindowViewAction("View in New Window", this));
actionsList.add(new ExternalViewerAction("Open in External Viewer", this)); actionsList.add(new ExternalViewerAction("Open in External Viewer", this));
actionsList.add(null); // creates a menu separator actionsList.add(null); // creates a menu separator
actionsList.add(new ExtractAction("Extract File", this)); actionsList.add(ExtractAction.getInstance());
actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this));
actionsList.add(null); // creates a menu separator actionsList.add(null); // creates a menu separator
actionsList.add(new TagAction(this)); actionsList.add(TagAbstractFileAction.getInstance());
return actionsList.toArray(new Action[0]); return actionsList.toArray(new Action[0]);
} }

View File

@ -24,11 +24,10 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import javax.swing.Action; import javax.swing.Action;
import org.openide.nodes.Sheet; import org.openide.nodes.Sheet;
import org.sleuthkit.autopsy.directorytree.ExplorerNodeActionVisitor;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.TagAction; import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.LayoutFile;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
@ -104,14 +103,12 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
@Override @Override
public Action[] getActions(boolean context) { public Action[] getActions(boolean context) {
List<Action> actionsList = new ArrayList<Action>(); List<Action> actionsList = new ArrayList<Action>();
actionsList.add(new NewWindowViewAction("View in New Window", this)); actionsList.add(new NewWindowViewAction("View in New Window", this));
actionsList.add(new ExternalViewerAction("Open in External Viewer", this)); actionsList.add(new ExternalViewerAction("Open in External Viewer", this));
actionsList.add(null); // creates a menu separator actionsList.add(null); // creates a menu separator
actionsList.add(new ExtractAction("Extract File", content)); actionsList.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator actionsList.add(null); // creates a menu separator
actionsList.add(new TagAction(content)); actionsList.add(TagAbstractFileAction.getInstance());
return actionsList.toArray(new Action[0]); return actionsList.toArray(new Action[0]);
} }

View File

@ -30,9 +30,8 @@ import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.TagAction; import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.LocalFile;
/** /**
* A Node for a LocalFile or DerivedFile content object. * A Node for a LocalFile or DerivedFile content object.
@ -86,16 +85,14 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
@Override @Override
public Action[] getActions(boolean context) { public Action[] getActions(boolean context) {
List<Action> actionsList = new ArrayList<Action>(); List<Action> actionsList = new ArrayList<>();
actionsList.add(new NewWindowViewAction("View in New Window", this)); actionsList.add(new NewWindowViewAction("View in New Window", this));
actionsList.add(new ExternalViewerAction("Open in External Viewer", this)); actionsList.add(new ExternalViewerAction("Open in External Viewer", this));
actionsList.add(null); // creates a menu separator actionsList.add(null); // creates a menu separator
actionsList.add(new ExtractAction("Extract", content)); //might not need this actions - already local file actionsList.add(ExtractAction.getInstance());
actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this));
actionsList.add(null); // creates a menu separator actionsList.add(null); // creates a menu separator
actionsList.add(new TagAction(content)); actionsList.add(TagAbstractFileAction.getInstance());
return actionsList.toArray(new Action[0]); return actionsList.toArray(new Action[0]);
} }

View File

@ -22,7 +22,6 @@ import java.awt.event.ActionEvent;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -656,36 +655,4 @@ public class Tags implements AutopsyVisitableItem {
return tagNames; return tagNames;
} }
public interface Taggable {
void createTag(String name, String comment);
}
public static class TaggableFile implements Taggable {
private AbstractFile file;
public TaggableFile(AbstractFile file) {
this.file = file;
}
@Override
public void createTag(String name, String comment) {
Tags.createTag(file, name, comment);
}
}
public static class TaggableBlackboardArtifact implements Taggable {
private BlackboardArtifact bba;
public TaggableBlackboardArtifact(BlackboardArtifact bba) {
this.bba = bba;
}
@Override
public void createTag(String name, String comment) {
Tags.createTag(bba, name, comment);
}
}
} }

View File

@ -27,7 +27,7 @@ import org.openide.nodes.Sheet;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.TagAction; import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
import org.sleuthkit.datamodel.VirtualDirectory; import org.sleuthkit.datamodel.VirtualDirectory;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
@ -76,13 +76,12 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode<VirtualDirect
*/ */
@Override @Override
public Action[] getActions(boolean popup) { public Action[] getActions(boolean popup) {
List<Action> actions = new ArrayList<Action>(); List<Action> actions = new ArrayList<>();
actions.add(new NewWindowViewAction("View in New Window", this)); actions.add(new NewWindowViewAction("View in New Window", this));
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(new ExtractAction("Extract Directory", this)); actions.add(ExtractAction.getInstance());
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(new TagAction(this)); actions.add(TagAbstractFileAction.getInstance());
return actions.toArray(new Action[0]); return actions.toArray(new Action[0]);
} }

View File

@ -105,7 +105,7 @@ public class DataResultFilterNode extends FilterNode {
@Override @Override
public Action[] getActions(boolean popup) { public Action[] getActions(boolean popup) {
List<Action> actions = new ArrayList<Action>(); List<Action> actions = new ArrayList<>();
final DisplayableItemNode originalNode = (DisplayableItemNode) this.getOriginal(); final DisplayableItemNode originalNode = (DisplayableItemNode) this.getOriginal();
actions.addAll(originalNode.accept(getActionsDIV)); actions.addAll(originalNode.accept(getActionsDIV));
@ -167,7 +167,7 @@ public class DataResultFilterNode extends FilterNode {
//TODO all actions need to be consolidated in single place! //TODO all actions need to be consolidated in single place!
//they should be set in individual Node subclass and using a utility to get Actions per Content sub-type //they should be set in individual Node subclass and using a utility to get Actions per Content sub-type
List<Action> actions = new ArrayList<Action>(); List<Action> actions = new ArrayList<>();
//merge predefined specific node actions if bban subclasses have their own //merge predefined specific node actions if bban subclasses have their own
for (Action a : ban.getActions(true)) { for (Action a : ban.getActions(true)) {
@ -197,15 +197,15 @@ public class DataResultFilterNode extends FilterNode {
actions.add(new NewWindowViewAction("View in New Window", fn)); actions.add(new NewWindowViewAction("View in New Window", fn));
actions.add(new ExternalViewerAction("Open in External Viewer", fn)); actions.add(new ExternalViewerAction("Open in External Viewer", fn));
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(new ExtractAction("Extract File", new FileNode(f))); actions.add(ExtractAction.getInstance());
actions.add(new HashSearchAction("Search for files with the same MD5 hash", fn)); actions.add(new HashSearchAction("Search for files with the same MD5 hash", fn));
//add file/result tag if itself is not a tag //add file/result tag if itself is not a tag
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { && artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(new TagAction(f)); actions.add(TagAbstractFileAction.getInstance());
actions.add(new TagAction(ba)); actions.add(TagBlackboardArtifactAction.getInstance());
} }
} }
if ((d = ban.getLookup().lookup(Directory.class)) != null) { if ((d = ban.getLookup().lookup(Directory.class)) != null) {
@ -214,14 +214,14 @@ public class DataResultFilterNode extends FilterNode {
actions.add(new NewWindowViewAction("View in New Window", dn)); actions.add(new NewWindowViewAction("View in New Window", dn));
actions.add(new ExternalViewerAction("Open in External Viewer", dn)); actions.add(new ExternalViewerAction("Open in External Viewer", dn));
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(new ExtractAction("Extract Directory", dn)); actions.add(ExtractAction.getInstance());
//add file/result tag if itself is not a tag //add file/result tag if itself is not a tag
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { && artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(new TagAction(d)); actions.add(TagAbstractFileAction.getInstance());
actions.add(new TagAction(ba)); actions.add(TagBlackboardArtifactAction.getInstance());
} }
} }
if ((vd = ban.getLookup().lookup(VirtualDirectory.class)) != null) { if ((vd = ban.getLookup().lookup(VirtualDirectory.class)) != null) {
@ -230,14 +230,14 @@ public class DataResultFilterNode extends FilterNode {
actions.add(new NewWindowViewAction("View in New Window", dn)); actions.add(new NewWindowViewAction("View in New Window", dn));
actions.add(new ExternalViewerAction("Open in External Viewer", dn)); actions.add(new ExternalViewerAction("Open in External Viewer", dn));
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(new ExtractAction("Extract Directory", dn)); actions.add(ExtractAction.getInstance());
//add file/result tag if itself is not a tag //add file/result tag if itself is not a tag
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { && artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(new TagAction(d)); actions.add(TagAbstractFileAction.getInstance());
actions.add(new TagAction(ba)); actions.add(TagBlackboardArtifactAction.getInstance());
} }
} else if ((lf = ban.getLookup().lookup(LayoutFile.class)) != null) { } else if ((lf = ban.getLookup().lookup(LayoutFile.class)) != null) {
LayoutFileNode lfn = new LayoutFileNode(lf); LayoutFileNode lfn = new LayoutFileNode(lf);
@ -245,14 +245,14 @@ public class DataResultFilterNode extends FilterNode {
actions.add(new NewWindowViewAction("View in New Window", lfn)); actions.add(new NewWindowViewAction("View in New Window", lfn));
actions.add(new ExternalViewerAction("Open in External Viewer", lfn)); actions.add(new ExternalViewerAction("Open in External Viewer", lfn));
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(new ExtractAction("Extract File", lfn)); actions.add(ExtractAction.getInstance());
//add tag if itself is not a tag //add tag if itself is not a tag
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { && artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(new TagAction(lf)); actions.add(TagAbstractFileAction.getInstance());
actions.add(new TagAction(ba)); actions.add(TagBlackboardArtifactAction.getInstance());
} }
} else if ((locF = ban.getLookup().lookup(LocalFile.class)) != null } else if ((locF = ban.getLookup().lookup(LocalFile.class)) != null
|| (locF = ban.getLookup().lookup(DerivedFile.class)) != null) { || (locF = ban.getLookup().lookup(DerivedFile.class)) != null) {
@ -261,14 +261,14 @@ public class DataResultFilterNode extends FilterNode {
actions.add(new NewWindowViewAction("View in New Window", locfn)); actions.add(new NewWindowViewAction("View in New Window", locfn));
actions.add(new ExternalViewerAction("Open in External Viewer", locfn)); actions.add(new ExternalViewerAction("Open in External Viewer", locfn));
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(new ExtractAction("Extract File", locfn)); actions.add(ExtractAction.getInstance());
//add tag if itself is not a tag //add tag if itself is not a tag
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { && artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(new TagAction(lf)); actions.add(TagAbstractFileAction.getInstance());
actions.add(new TagAction(ba)); actions.add(TagBlackboardArtifactAction.getInstance());
} }
} }
@ -278,7 +278,7 @@ public class DataResultFilterNode extends FilterNode {
@Override @Override
protected List<Action> defaultVisit(DisplayableItemNode ditem) { protected List<Action> defaultVisit(DisplayableItemNode ditem) {
//preserve the default node's actions //preserve the default node's actions
List<Action> actions = new ArrayList<Action>(); List<Action> actions = new ArrayList<>();
for (Action action : ditem.getActions(true)) { for (Action action : ditem.getActions(true)) {
actions.add(action); actions.add(action);

View File

@ -99,8 +99,7 @@ class DirectoryTreeFilterNode extends FilterNode {
//extract dir action //extract dir action
Directory dir = this.getLookup().lookup(Directory.class); Directory dir = this.getLookup().lookup(Directory.class);
if (dir != null) { if (dir != null) {
actions.add(new ExtractAction("Extract Directory", actions.add(ExtractAction.getInstance());
getOriginal()));
} }
// file search action // file search action

View File

@ -101,39 +101,39 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
@Override @Override
public List<? extends Action> visit(final Directory d) { public List<? extends Action> visit(final Directory d) {
List<Action> actions = new ArrayList<Action>(); List<Action> actions = new ArrayList<Action>();
actions.add(new TagAction(d)); actions.add(TagAbstractFileAction.getInstance());
return actions; return actions;
} }
@Override @Override
public List<? extends Action> visit(final VirtualDirectory d) { public List<? extends Action> visit(final VirtualDirectory d) {
List<Action> actions = new ArrayList<Action>(); List<Action> actions = new ArrayList<Action>();
actions.add(new TagAction(d)); actions.add(ExtractAction.getInstance());
actions.add(new ExtractAction("Extract Directory", d)); actions.add(TagAbstractFileAction.getInstance());
return actions; return actions;
} }
@Override @Override
public List<? extends Action> visit(final DerivedFile d) { public List<? extends Action> visit(final DerivedFile d) {
List<Action> actions = new ArrayList<Action>(); List<Action> actions = new ArrayList<Action>();
actions.add(new ExtractAction("Extract File", d)); actions.add(ExtractAction.getInstance());
actions.add(new TagAction(d)); actions.add(TagAbstractFileAction.getInstance());
return actions; return actions;
} }
@Override @Override
public List<? extends Action> visit(final LocalFile d) { public List<? extends Action> visit(final LocalFile d) {
List<Action> actions = new ArrayList<Action>(); List<Action> actions = new ArrayList<Action>();
actions.add(new ExtractAction("Extract File", d)); actions.add(ExtractAction.getInstance());
actions.add(new TagAction(d)); actions.add(TagAbstractFileAction.getInstance());
return actions; return actions;
} }
@Override @Override
public List<? extends Action> visit(final org.sleuthkit.datamodel.File d) { public List<? extends Action> visit(final org.sleuthkit.datamodel.File d) {
List<Action> actions = new ArrayList<Action>(); List<Action> actions = new ArrayList<Action>();
actions.add(new ExtractAction("Extract File", d)); actions.add(ExtractAction.getInstance());
actions.add(new TagAction(d)); actions.add(TagAbstractFileAction.getInstance());
return actions; return actions;
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011 Basis Technology Corp. * Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.directorytree;
import java.awt.Component; import java.awt.Component;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.io.File; import java.io.File;
import java.util.Collection;
import java.util.concurrent.CancellationException; import java.util.concurrent.CancellationException;
import java.util.logging.Level; import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
@ -30,81 +31,35 @@ import javax.swing.JOptionPane;
import javax.swing.SwingWorker; import javax.swing.SwingWorker;
import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory; import org.netbeans.api.progress.ProgressHandleFactory;
import org.openide.nodes.Node;
import org.openide.util.Cancellable; import org.openide.util.Cancellable;
import org.openide.util.Utilities;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.FileUtil;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.datamodel.ContentUtils.ExtractFscContentVisitor; import org.sleuthkit.autopsy.datamodel.ContentUtils.ExtractFscContentVisitor;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentVisitor;
import org.sleuthkit.datamodel.Directory;
/** /**
* Exports files and folders * Exports files and folders
*/ */
public final class ExtractAction extends AbstractAction { public final class ExtractAction extends AbstractAction {
private static final InitializeContentVisitor initializeCV = new InitializeContentVisitor();
private AbstractFile content;
private Logger logger = Logger.getLogger(ExtractAction.class.getName()); private Logger logger = Logger.getLogger(ExtractAction.class.getName());
public ExtractAction(String title, Node contentNode) { // This class is a singleton to support multi-selection of nodes, since
super(title); // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every
Content tempContent = contentNode.getLookup().lookup(Content.class); // node in the array returns a reference to the same action object from Node.getActions(boolean).
private static ExtractAction instance;
this.content = tempContent.accept(initializeCV); public static synchronized ExtractAction getInstance() {
this.setEnabled(content != null); if (null == instance) {
instance = new ExtractAction();
}
return instance;
} }
public ExtractAction(String title, Content content) { private ExtractAction() {
super(title); super("Extract");
this.content = content.accept(initializeCV);
this.setEnabled(this.content != null);
}
/**
* Returns the FsContent if it is supported, otherwise null
*/
private static class InitializeContentVisitor extends ContentVisitor.Default<AbstractFile> {
@Override
public AbstractFile visit(org.sleuthkit.datamodel.File f) {
return f;
}
@Override
public AbstractFile visit(org.sleuthkit.datamodel.LayoutFile lf) {
return lf;
}
@Override
public AbstractFile visit(org.sleuthkit.datamodel.DerivedFile df) {
return df;
}
@Override
public AbstractFile visit(org.sleuthkit.datamodel.LocalFile lf) {
return lf;
}
@Override
public AbstractFile visit(org.sleuthkit.datamodel.VirtualDirectory vd) {
return vd;
}
@Override
public AbstractFile visit(Directory dir) {
return ContentUtils.isDotDirectory(dir) ? null : dir;
}
@Override
protected AbstractFile defaultVisit(Content cntnt) {
return null;
}
} }
/** /**
@ -114,10 +69,17 @@ public final class ExtractAction extends AbstractAction {
*/ */
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
Collection<? extends AbstractFile> selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class);
for (AbstractFile file : selectedFiles) {
extractFile(e, file);
}
}
private void extractFile(ActionEvent e, AbstractFile file) {
// Get content and check that it's okay to overwrite existing content // Get content and check that it's okay to overwrite existing content
JFileChooser fc = new JFileChooser(); JFileChooser fc = new JFileChooser();
fc.setCurrentDirectory(new File(Case.getCurrentCase().getCaseDirectory())); fc.setCurrentDirectory(new File(Case.getCurrentCase().getCaseDirectory()));
fc.setSelectedFile(new File(this.content.getName())); fc.setSelectedFile(new File(file.getName()));
int returnValue = fc.showSaveDialog((Component) e.getSource()); int returnValue = fc.showSaveDialog((Component) e.getSource());
if (returnValue == JFileChooser.APPROVE_OPTION) { if (returnValue == JFileChooser.APPROVE_OPTION) {
@ -144,7 +106,7 @@ public final class ExtractAction extends AbstractAction {
try { try {
ExtractFileThread extract = new ExtractFileThread(); ExtractFileThread extract = new ExtractFileThread();
extract.init(this.content, e, destination); extract.init(file, e, destination);
extract.execute(); extract.execute();
} catch (Exception ex) { } catch (Exception ex) {
logger.log(Level.WARNING, "Unable to start background thread.", ex); logger.log(Level.WARNING, "Unable to start background thread.", ex);
@ -231,5 +193,4 @@ public final class ExtractAction extends AbstractAction {
} }
} }
} }
} }

View File

@ -0,0 +1,70 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 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.directorytree;
import java.awt.event.ActionEvent;
import java.util.Collection;
import javax.swing.AbstractAction;
import javax.swing.JMenuItem;
import org.openide.util.Utilities;
import org.openide.util.actions.Presenter;
import org.sleuthkit.autopsy.datamodel.Tags;
import org.sleuthkit.datamodel.AbstractFile;
public class TagAbstractFileAction extends AbstractAction implements Presenter.Popup {
// This class is a singleton to support multi-selection of nodes, since
// org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every
// node in the array returns a reference to the same action object from Node.getActions(boolean).
private static TagAbstractFileAction instance;
public static synchronized TagAbstractFileAction getInstance() {
if (null == instance) {
instance = new TagAbstractFileAction();
}
return instance;
}
private TagAbstractFileAction() {
}
@Override
public JMenuItem getPopupPresenter() {
return new TagAbstractFileMenu();
}
@Override
public void actionPerformed(ActionEvent e) {
// Do nothing - this action should never be performed.
// Submenu actions are invoked instead.
}
private static class TagAbstractFileMenu extends TagMenu {
public TagAbstractFileMenu() {
super(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class).size() > 1 ? "Tag Files" : "Tag File");
}
@Override
protected void applyTag(String tagName, String comment) {
Collection<? extends AbstractFile> selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class);
for (AbstractFile file : selectedFiles) {
Tags.createTag(file, tagName, comment);
}
}
}
}

View File

@ -1,125 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 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.directorytree;
import java.awt.event.ActionEvent;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import org.openide.nodes.Node;
import org.openide.util.actions.Presenter;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentVisitor;
import org.sleuthkit.datamodel.Directory;
/**
* Action on a file or artifact that adds a tag and
* reloads the directory tree. Supports tagging of AbstractFiles and
* BlackboardArtifacts.
*
* TODO add use enters description and hierarchy (TSK_TAG_NAME with slashes)
*/
public class TagAction extends AbstractAction implements Presenter.Popup {
private static final Logger logger = Logger.getLogger(TagAction.class.getName());
private JMenu tagMenu;
private final InitializeBookmarkFileV initializer = new InitializeBookmarkFileV();
public TagAction(Node contentNode) {
AbstractFile file = contentNode.getLookup().lookup(AbstractFile.class);
if (file != null) {
tagMenu = new TagMenu(file);
return;
}
BlackboardArtifact bba = contentNode.getLookup().lookup(BlackboardArtifact.class);
if (bba != null) {
tagMenu = new TagMenu(bba);
return;
}
logger.log(Level.SEVERE, "Tried to create a " + TagAction.class.getName()
+ " using a Node whose lookup did not contain an AbstractFile or a BlackboardArtifact.");
}
public TagAction(AbstractFile file) {
tagMenu = new TagMenu(file);
}
public TagAction(BlackboardArtifact bba) {
tagMenu = new TagMenu(bba);
}
@Override
public JMenuItem getPopupPresenter() {
return tagMenu;
}
/**
* Returns the FsContent if it is supported, otherwise null
*/
private static class InitializeBookmarkFileV extends ContentVisitor.Default<AbstractFile> {
@Override
public AbstractFile visit(org.sleuthkit.datamodel.File f) {
return f;
}
@Override
public AbstractFile visit(org.sleuthkit.datamodel.LayoutFile lf) {
return lf;
}
@Override
public AbstractFile visit(org.sleuthkit.datamodel.DerivedFile lf) {
return lf;
}
@Override
public AbstractFile visit(org.sleuthkit.datamodel.LocalFile lf) {
return lf;
}
@Override
public AbstractFile visit(org.sleuthkit.datamodel.VirtualDirectory ld) {
return ld;
}
@Override
public AbstractFile visit(Directory dir) {
return ContentUtils.isDotDirectory(dir) ? null : dir;
}
@Override
protected AbstractFile defaultVisit(Content cntnt) {
return null;
}
}
@Override
public void actionPerformed(ActionEvent e) {
// Do nothing - this action should never be performed
// Submenu actions are invoked instead
}
}

View File

@ -30,28 +30,50 @@ import javax.swing.JFrame;
import javax.swing.KeyStroke; import javax.swing.KeyStroke;
import org.openide.windows.WindowManager; import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.datamodel.Tags; import org.sleuthkit.autopsy.datamodel.Tags;
import org.sleuthkit.autopsy.datamodel.Tags.Taggable;
import org.sleuthkit.datamodel.BlackboardArtifact;
/** /**
* Tag dialog for tagging files and results. User enters an optional comment. * Tag dialog for tagging files and results. User enters an optional comment.
*/ */
public class TagAndCommentDialog extends JDialog { public class TagAndCommentDialog extends JDialog {
private static final String TAG_ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png";
private static final String BOOKMARK_ICON_PATH = "org/sleuthkit/autopsy/images/star-bookmark-icon-16.png";
private static final String NO_TAG_MESSAGE = "No Tags"; private static final String NO_TAG_MESSAGE = "No Tags";
private String tagName = "";
private String comment = "";
private Taggable taggable; public static class CommentedTag {
private String name;
private String comment;
CommentedTag(String name, String comment) {
this.name = name;
this.comment = comment;
}
public String getName() {
return name;
}
public String getComment() {
return comment;
}
}
public static CommentedTag doDialog() {
TagAndCommentDialog dialog = new TagAndCommentDialog();
if (!dialog.tagName.isEmpty()) {
return new CommentedTag(dialog.tagName, dialog.comment);
}
else {
return null;
}
}
/** /**
* Creates new form TagDialog * Creates new form TagDialog
*/ */
public TagAndCommentDialog(Taggable taggable) { private TagAndCommentDialog() {
super((JFrame)WindowManager.getDefault().getMainWindow(), "Tag and Comment", true); super((JFrame)WindowManager.getDefault().getMainWindow(), "Tag and Comment", true);
this.taggable = taggable;
initComponents(); initComponents();
// Close the dialog when Esc is pressed // Close the dialog when Esc is pressed
@ -60,8 +82,8 @@ public class TagAndCommentDialog extends JDialog {
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName);
ActionMap actionMap = getRootPane().getActionMap(); ActionMap actionMap = getRootPane().getActionMap();
actionMap.put(cancelName, new AbstractAction() { actionMap.put(cancelName, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
//doClose(RET_CANCEL);
dispose(); dispose();
} }
}); });
@ -82,14 +104,9 @@ public class TagAndCommentDialog extends JDialog {
//center it //center it
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
customizeComponent();
setVisible(true); // blocks setVisible(true); // blocks
} }
private void customizeComponent() {
}
/** /**
* This method is called from within the constructor to initialize the form. * 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 * WARNING: Do NOT modify this code. The content of this method is always
@ -195,22 +212,12 @@ public class TagAndCommentDialog extends JDialog {
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
//doClose(RET_OK); tagName = (String)tagCombo.getSelectedItem();
comment = commentText.getText();
// get the selected tag and comment
String selectedTag = (String)tagCombo.getSelectedItem();
String comment = commentText.getText();
// create the tag
taggable.createTag(selectedTag, comment);
refreshDirectoryTree();
dispose(); dispose();
}//GEN-LAST:event_okButtonActionPerformed }//GEN-LAST:event_okButtonActionPerformed
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
//doClose(RET_CANCEL);
dispose(); dispose();
}//GEN-LAST:event_cancelButtonActionPerformed }//GEN-LAST:event_cancelButtonActionPerformed
@ -218,14 +225,12 @@ public class TagAndCommentDialog extends JDialog {
* Closes the dialog * Closes the dialog
*/ */
private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog
//doClose(RET_CANCEL);
dispose(); dispose();
}//GEN-LAST:event_closeDialog }//GEN-LAST:event_closeDialog
private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed
String newTagName = CreateTagDialog.getNewTagNameDialog(null); String newTagName = CreateTagDialog.getNewTagNameDialog(null);
if (newTagName != null) { if (newTagName != null) {
//tagsModel.addElement(newTagName);
tagCombo.addItem(newTagName); tagCombo.addItem(newTagName);
tagCombo.setSelectedItem(newTagName); tagCombo.setSelectedItem(newTagName);
} }
@ -240,12 +245,4 @@ public class TagAndCommentDialog extends JDialog {
private javax.swing.JComboBox tagCombo; private javax.swing.JComboBox tagCombo;
private javax.swing.JLabel tagLabel; private javax.swing.JLabel tagLabel;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
//private int returnStatus = RET_CANCEL;
private void refreshDirectoryTree() {
//TODO instead should send event to node children, which will call its refresh() / refreshKeys()
DirectoryTreeTopComponent viewer = DirectoryTreeTopComponent.findInstance();
viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE);
viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT);
}
} }

View File

@ -0,0 +1,71 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 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.directorytree;
import java.awt.event.ActionEvent;
import java.util.Collection;
import javax.swing.AbstractAction;
import javax.swing.JMenuItem;
import org.openide.util.Utilities;
import org.openide.util.actions.Presenter;
import org.sleuthkit.autopsy.datamodel.Tags;
import org.sleuthkit.datamodel.BlackboardArtifact;
public class TagBlackboardArtifactAction extends AbstractAction implements Presenter.Popup {
// This class is a singleton to support multi-selection of nodes, since
// org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every
// node in the array returns a reference to the same action object from Node.getActions(boolean).
private static TagBlackboardArtifactAction instance;
public static synchronized TagBlackboardArtifactAction getInstance() {
if (null == instance) {
instance = new TagBlackboardArtifactAction();
}
return instance;
}
private TagBlackboardArtifactAction() {
}
@Override
public JMenuItem getPopupPresenter() {
return new TagBlackboardArtifactMenu();
}
@Override
public void actionPerformed(ActionEvent e) {
// Do nothing - this action should never be performed.
// Submenu actions are invoked instead.
}
private static class TagBlackboardArtifactMenu extends TagMenu {
public TagBlackboardArtifactMenu() {
super(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class).size() > 1 ? "Tag Results" : "Tag Result");
}
@Override
protected void applyTag(String tagName, String comment) {
Collection<? extends BlackboardArtifact> selectedArtifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class);
for (BlackboardArtifact artifact : selectedArtifacts) {
Tags.createTag(artifact, tagName, comment);
}
}
}
}

View File

@ -24,38 +24,20 @@ import java.util.List;
import javax.swing.JMenu; import javax.swing.JMenu;
import javax.swing.JMenuItem; import javax.swing.JMenuItem;
import org.sleuthkit.autopsy.datamodel.Tags; import org.sleuthkit.autopsy.datamodel.Tags;
import org.sleuthkit.autopsy.datamodel.Tags.Taggable;
import org.sleuthkit.autopsy.datamodel.Tags.TaggableBlackboardArtifact;
import org.sleuthkit.autopsy.datamodel.Tags.TaggableFile;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
/** /**
* The menu that results when one right-clicks on a file or artifact. * The menu that results when one right-clicks on a file or artifact.
*/ */
public class TagMenu extends JMenu { public abstract class TagMenu extends JMenu {
public TagMenu(String menuItemText) {
super(menuItemText);
private Taggable tagCreator; // Create the 'Quick Tag' sub-menu and add it to the tag menu.
public TagMenu(AbstractFile file) {
super("Tag File");
tagCreator = new TaggableFile(file);
init();
}
public TagMenu(BlackboardArtifact bba) {
super("Tag Result");
tagCreator = new TaggableBlackboardArtifact(bba);
init();
}
private void init() {
// create the 'Quick Tag' menu and add it to the 'Tag File' menu
JMenu quickTagMenu = new JMenu("Quick Tag"); JMenu quickTagMenu = new JMenu("Quick Tag");
add(quickTagMenu); add(quickTagMenu);
// create the 'Quick Tag' sub-menu items and add them to the 'Quick Tag' menu // Get the existing tag names.
List<String> tagNames = Tags.getTagNames(); List<String> tagNames = Tags.getTagNames();
if (tagNames.isEmpty()) { if (tagNames.isEmpty()) {
JMenuItem empty = new JMenuItem("No tags"); JMenuItem empty = new JMenuItem("No tags");
@ -63,44 +45,48 @@ public class TagMenu extends JMenu {
quickTagMenu.add(empty); quickTagMenu.add(empty);
} }
// Add a menu item for each existing tag name to the 'Quick Tag' menu.
for (final String tagName : tagNames) { for (final String tagName : tagNames) {
JMenuItem tagItem = new JMenuItem(tagName); JMenuItem tagNameItem = new JMenuItem(tagName);
tagItem.addActionListener(new ActionListener() { tagNameItem.addActionListener(new ActionListener() {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
tagCreator.createTag(tagName, ""); applyTag(tagName, "");
refreshDirectoryTree(); refreshDirectoryTree();
} }
}); });
quickTagMenu.add(tagItem); quickTagMenu.add(tagNameItem);
} }
quickTagMenu.addSeparator(); quickTagMenu.addSeparator();
// create the 'New Tag' menu item // Create the 'New Tag' menu item and add it to the 'Quick Tag' menu.
JMenuItem newTagMenuItem = new JMenuItem("New Tag"); JMenuItem newTagMenuItem = new JMenuItem("New Tag");
newTagMenuItem.addActionListener(new ActionListener() { newTagMenuItem.addActionListener(new ActionListener() {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
String newTagName = CreateTagDialog.getNewTagNameDialog(null); String tagName = CreateTagDialog.getNewTagNameDialog(null);
if (newTagName != null) { if (tagName != null) {
tagCreator.createTag(newTagName, ""); applyTag(tagName, "");
refreshDirectoryTree(); refreshDirectoryTree();
} }
} }
}); });
// add the 'New Tag' menu item to the 'Quick Tag' menu
quickTagMenu.add(newTagMenuItem); quickTagMenu.add(newTagMenuItem);
JMenuItem newTagItem = new JMenuItem("Tag and Comment"); // Create the 'Tag and Comment' menu item and add it to the tag menu.
newTagItem.addActionListener(new ActionListener() { JMenuItem tagAndCommentItem = new JMenuItem("Tag and Comment");
tagAndCommentItem.addActionListener(new ActionListener() {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
new TagAndCommentDialog(tagCreator); TagAndCommentDialog.CommentedTag commentedTag = TagAndCommentDialog.doDialog();
if (null != commentedTag) {
applyTag(commentedTag.getName(), commentedTag.getComment());
refreshDirectoryTree();
}
} }
}); });
add(newTagItem); add(tagAndCommentItem);
} }
private void refreshDirectoryTree() { private void refreshDirectoryTree() {
@ -109,4 +95,6 @@ public class TagMenu extends JMenu {
viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE); viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE);
viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT); viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT);
} }
protected abstract void applyTag(String tagName, String comment);
} }

View File

@ -0,0 +1,125 @@
/*
* Sample module in the public domain. Feel free to use this as a template
* for your modules.
*
* Contact: Brian Carrier [carrier <at> sleuthkit [dot] org]
*
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package org.sleuthkit.autopsy.examples;
import java.util.List;
import org.apache.log4j.Logger;
import org.openide.util.Exceptions;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.FileManager;
import org.sleuthkit.autopsy.casemodule.services.Services;
import org.sleuthkit.autopsy.ingest.IngestDataSourceWorkerController;
import org.sleuthkit.autopsy.ingest.IngestModuleDataSource;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.autopsy.ingest.PipelineContext;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.FsContent;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Sample DataSource-level ingest module that doesn't do much at all.
* Just exists to show basic idea of these modules
*/
public class SampleDataSourceIngestModule extends org.sleuthkit.autopsy.ingest.IngestModuleDataSource {
/* Data Source modules operate on a disk or set of logical files. They
* are passed in teh data source refernce and query it for things they want.
*/
@Override
public void process(PipelineContext<IngestModuleDataSource> pipelineContext, Content dataSource, IngestDataSourceWorkerController controller) {
Case case1 = Case.getCurrentCase();
SleuthkitCase sleuthkitCase = case1.getSleuthkitCase();
Services services = new Services(sleuthkitCase);
FileManager fm = services.getFileManager();
try {
/* you can use the findFiles method in FileManager (or similar ones in
* SleuthkitCase to find files based only on their name. This
* one finds files that have a .doc extension. */
List<AbstractFile> docFiles = fm.findFiles(dataSource, "%.doc");
for (AbstractFile file : docFiles) {
// do something with each doc file
}
/* We can also do more general queries with findFilesWhere, which
* allows us to make our own WHERE clause in the database.
*/
long currentTime = System.currentTimeMillis()/1000;
// go back 2 weeks
long minTime = currentTime - (14 * 24 * 60 * 60);
List<FsContent> otherFiles = sleuthkitCase.findFilesWhere("crtime > " + minTime);
// do something with these files...
} catch (TskCoreException ex) {
Logger log = Logger.getLogger(SampleDataSourceIngestModule.class);
log.fatal("Error retrieving files from database: " + ex.getLocalizedMessage());
return;
}
}
@Override
public void init(IngestModuleInit initContext) {
// do nothing
}
@Override
public void complete() {
// do nothing
}
@Override
public void stop() {
// do nothing
}
@Override
public String getName() {
return "SampleDataSourceIngestModule";
}
@Override
public String getVersion() {
return "1.0";
}
@Override
public String getDescription() {
return "Doesn't do much";
}
@Override
public boolean hasBackgroundJobsRunning() {
return false;
}
}

View File

@ -0,0 +1,178 @@
/*
* Sample module in the public domain. Feel free to use this as a template
* for your modules.
*
* Contact: Brian Carrier [carrier <at> sleuthkit [dot] org]
*
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package org.sleuthkit.autopsy.examples;
import org.apache.log4j.Logger;
import org.openide.util.Exceptions;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.autopsy.ingest.PipelineContext;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskData;
/**
* This is a sample and simple module. It is a file-level ingest module, meaning
* that it will get called on each file in the disk image / logical file set.
* It does a stupid calculation of the number of null bytes in the beginning of the
* file in order to show the basic flow.
*
* Autopsy has been hard coded to ignore this module based on the it's package name.
* IngestModuleLoader will not load things from the org.sleuthkit.autopsy.examples package.
* Either change the package or the loading code to make this module actually run.
*/
public class SampleFileIngestModule extends org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile {
private int attrId = -1;
private static SampleFileIngestModule defaultInstance = null;
// Private to ensure Singleton status
private SampleFileIngestModule() {
}
// File-level ingest modules are currently singleton -- this is required
public static synchronized SampleFileIngestModule getDefault() {
//defaultInstance is a private static class variable
if (defaultInstance == null) {
defaultInstance = new SampleFileIngestModule();
}
return defaultInstance;
}
@Override
public void init(IngestModuleInit initContext) {
/* For this demo, we are going to make a private attribute to post our
* results to the blackbaord with. There are many standard blackboard artifact
* and attribute types and you should first consider using one of those before
* making private ones because other modules won't know about provate ones.
* Because our demo has results that have no real value, we do not have an
* official attribute for them.
*/
Case case1 = Case.getCurrentCase();
SleuthkitCase sleuthkitCase = case1.getSleuthkitCase();
// see if the type already exists in the blackboard.
try {
attrId = sleuthkitCase.getAttrTypeID("ATTR_SAMPLE");
} catch (TskCoreException ex) {
// create it if not
try {
attrId = sleuthkitCase.addAttrType("ATTR_SAMPLE", "Sample Attribute");
} catch (TskCoreException ex1) {
Logger log = Logger.getLogger(SampleFileIngestModule.class);
log.fatal("Error adding attribute type: " + ex1.getLocalizedMessage());
attrId = -1;
}
}
}
@Override
public ProcessResult process(PipelineContext<IngestModuleAbstractFile> pipelineContext, AbstractFile abstractFile) {
// skip non-files
if ((abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) ||
(abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)) {
return ProcessResult.OK;
}
// skip NSRL / known files
if (abstractFile.getKnown() == TskData.FileKnown.KNOWN) {
return ProcessResult.OK;
}
/* Do a non-sensical calculation of the number of 0x00 bytes
* in the first 1024-bytes of the file. This is for demo
* purposes only.
*/
try {
byte buffer[] = new byte[1024];
int len = abstractFile.read(buffer, 0, 1024);
int count = 0;
for (int i = 0; i < len; i++) {
if (buffer[i] == 0x00) {
count++;
}
}
if (attrId != -1) {
// Make an attribute using the ID for the private type that we previously created.
BlackboardAttribute attr = new BlackboardAttribute(attrId, getName(), count);
/* add it to the general info artifact. In real modules, you would likely have
* more complex data types and be making more specific artifacts.
*/
BlackboardArtifact art = abstractFile.getGenInfoArtifact();
art.addAttribute(attr);
}
return ProcessResult.OK;
} catch (TskCoreException ex) {
Exceptions.printStackTrace(ex);
return ProcessResult.ERROR;
}
}
@Override
public void complete() {
}
@Override
public void stop() {
}
@Override
public String getVersion() {
return "1.0";
}
@Override
public String getName() {
return "SampleFileIngestModule";
}
@Override
public String getDescription() {
return "Doesn't do much";
}
@Override
public boolean hasBackgroundJobsRunning() {
// we're single threaded...
return false;
}
}

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011 Basis Technology Corp. * Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -26,36 +26,37 @@ import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter; import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent; import java.awt.event.WindowEvent;
import java.util.List; import java.util.List;
import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.BoxLayout; import javax.swing.BoxLayout;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JDialog; import javax.swing.JDialog;
import javax.swing.JFrame; import javax.swing.JFrame;
import javax.swing.JPanel; import javax.swing.JPanel;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.casemodule.GeneralIngestConfigurator;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.autopsy.casemodule.IngestConfigurator;
/** /**
* IngestDialog shown on Case.CASE_ADD_IMAGE property change * Dialog box that allows ingest modules to be run on an image.
* Used outside of the wizards.
*/ */
public class IngestDialog extends JDialog { public class IngestDialog extends JDialog {
private static final String TITLE = "Ingest Modules"; private static final String TITLE = "Ingest Modules";
private static Dimension DIMENSIONS = new Dimension(500, 300); private static Dimension DIMENSIONS = new Dimension(500, 300);
private IngestDialogPanel panel = null; private IngestConfigurator ingestConfigurator;
private static final Logger logger = Logger.getLogger(IngestDialog.class.getName());
public IngestDialog(JFrame frame, String title, boolean modal) { public IngestDialog(JFrame frame, String title, boolean modal) {
super(frame, title, modal); super(frame, title, modal);
panel = new IngestDialogPanel(); ingestConfigurator = new GeneralIngestConfigurator();
ingestConfigurator.setContext(IngestDialog.class.getCanonicalName());
ingestConfigurator.reload();
} }
public IngestDialog(){ public IngestDialog(){
this(new JFrame(TITLE), TITLE, true); this(new JFrame(TITLE), TITLE, true);
} }
/** /**
* Shows the Ingest dialog. * Shows the Ingest dialog.
*/ */
@ -71,17 +72,15 @@ public class IngestDialog extends JDialog {
// set the location of the popUp Window on the center of the screen // set the location of the popUp Window on the center of the screen
setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2);
panel.reload(); // reload the simple panel add(ingestConfigurator.getIngestConfigPanel(), BorderLayout.PAGE_START);
add(panel, BorderLayout.PAGE_START);
JButton startButton = new JButton("Start"); JButton startButton = new JButton("Start");
JButton closeButton = new JButton("Close"); JButton closeButton = new JButton("Close");
startButton.addActionListener(new ActionListener() { startButton.addActionListener(new ActionListener() {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
ingestConfigurator.save();
panel.save(); ingestConfigurator.start();
panel.start();
close(); close();
} }
}); });
@ -89,7 +88,7 @@ public class IngestDialog extends JDialog {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
panel.save(); ingestConfigurator.save();
close(); close();
} }
}); });
@ -97,7 +96,7 @@ public class IngestDialog extends JDialog {
@Override @Override
public void windowClosing(WindowEvent e) { public void windowClosing(WindowEvent e) {
panel.save(); ingestConfigurator.save();
close(); close();
} }
}); });
@ -115,10 +114,9 @@ public class IngestDialog extends JDialog {
} }
public void setContent(List<Content> inputContent) { public void setContent(List<Content> inputContent) {
panel.setContent(inputContent); ingestConfigurator.setContent(inputContent);
} }
/** /**
* Closes the Ingest dialog * Closes the Ingest dialog
*/ */
@ -126,6 +124,4 @@ public class IngestDialog extends JDialog {
setVisible(false); setVisible(false);
dispose(); dispose();
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011 Basis Technology Corp. * Copyright 2011-2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -18,24 +18,15 @@
*/ */
package org.sleuthkit.autopsy.ingest; package org.sleuthkit.autopsy.ingest;
import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter; import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent; import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent; import java.util.AbstractMap;
import java.beans.PropertyChangeListener;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.JPanel;
import javax.swing.JTable; import javax.swing.JTable;
import javax.swing.ListSelectionModel; import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionEvent;
@ -43,80 +34,55 @@ import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel; import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn; import javax.swing.table.TableColumn;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.casemodule.IngestConfigurator;
import org.sleuthkit.autopsy.corecomponents.AdvancedConfigurationDialog; import org.sleuthkit.autopsy.corecomponents.AdvancedConfigurationDialog;
import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstract.ModuleType;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
/** /**
* main configuration panel for all ingest modules, reusable JPanel component * main configuration panel for all ingest modules, reusable JPanel component
*/ */
@ServiceProvider(service = IngestConfigurator.class) public class IngestDialogPanel extends javax.swing.JPanel {
public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfigurator {
private IngestManager manager = null;
private List<IngestModuleAbstract> modules;
private IngestModuleAbstract currentModule; private IngestModuleAbstract currentModule;
private Map<String, Boolean> moduleStates;
private ModulesTableModel tableModel; private ModulesTableModel tableModel;
private static final Logger logger = Logger.getLogger(IngestDialogPanel.class.getName());
public static final String DISABLED_MOD = "Disabled_Ingest_Modules"; public static final String DISABLED_MOD = "Disabled_Ingest_Modules";
public static final String PARSE_UNALLOC = "Process_Unallocated_Space"; public static final String PARSE_UNALLOC = "Process_Unallocated_Space";
// The input content that's just been added to the database private String context;
private List<Content> inputContent;
// private static IngestDialogPanel instance = null;
/** /**
* Creates new form IngestDialogPanel * Creates new form IngestDialogPanel
*/ */
public IngestDialogPanel() { public IngestDialogPanel() {
tableModel = new ModulesTableModel(); tableModel = new ModulesTableModel();
modules = new ArrayList<IngestModuleAbstract>(); context = ModuleSettings.DEFAULT_CONTEXT;
moduleStates = new HashMap<String, Boolean>();
initComponents(); initComponents();
customizeComponents(); customizeComponents();
} }
private void loadModules() { public void setContext(String context) {
this.modules.clear(); this.context = context;
//this.moduleStates.clear(); maintain the state }
Collection<IngestModuleDataSource> imageModules = manager.enumerateDataSourceModules();
for (final IngestModuleDataSource module : imageModules) {
addModule(module); public IngestModuleAbstract getCurrentIngestModule() {
} return currentModule;
Collection<IngestModuleAbstractFile> fsModules = manager.enumerateAbstractFileModules(); }
for (final IngestModuleAbstractFile module : fsModules) {
addModule(module); public List<IngestModuleAbstract> getModulesToStart() {
} return tableModel.getSelectedModules();
}
public boolean processUnallocSpaceEnabled() {
return processUnallocCheckbox.isSelected();
} }
private void customizeComponents() { private void customizeComponents() {
modulesTable.setModel(tableModel); modulesTable.setModel(tableModel);
this.manager = IngestManager.getDefault();
loadModules();
try {
IngestModuleLoader.getDefault().addModulesReloadedListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(IngestModuleLoader.Event.ModulesReloaded.toString())) {
loadModules();
}
}
});
} catch (IngestModuleLoaderException ex) {
logger.log(Level.SEVERE, "Could not initialize ingest module loader to listen for module config changes", ex);
}
modulesTable.setTableHeader(null); modulesTable.setTableHeader(null);
modulesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); modulesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
//custom renderer for tooltips //custom renderer for tooltips
ModulesTableRenderer renderer = new ModulesTableRenderer(); ModulesTableRenderer renderer = new ModulesTableRenderer();
//customize column witdhs //customize column witdhs
final int width = modulesScrollPane.getPreferredSize().width; final int width = modulesScrollPane.getPreferredSize().width;
TableColumn column = null; TableColumn column = null;
@ -135,40 +101,30 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
public void valueChanged(ListSelectionEvent e) { public void valueChanged(ListSelectionEvent e) {
ListSelectionModel listSelectionModel = (ListSelectionModel) e.getSource(); ListSelectionModel listSelectionModel = (ListSelectionModel) e.getSource();
if (!listSelectionModel.isSelectionEmpty()) { if (!listSelectionModel.isSelectionEmpty()) {
save();
int index = listSelectionModel.getMinSelectionIndex(); int index = listSelectionModel.getMinSelectionIndex();
currentModule = modules.get(index); currentModule = tableModel.getModule(index);
reload();
// add the module-specific configuration panel, if there is one
simplePanel.removeAll();
if (currentModule.hasSimpleConfiguration()) {
simplePanel.add(currentModule.getSimpleConfiguration(context));
}
simplePanel.revalidate();
simplePanel.repaint();
advancedButton.setEnabled(currentModule.hasAdvancedConfiguration()); advancedButton.setEnabled(currentModule.hasAdvancedConfiguration());
} else { } else {
currentModule = null; currentModule = null;
} }
} }
}); });
processUnallocCheckbox.setSelected(manager.getProcessUnallocSpace());
} }
private void setProcessUnallocSpaceEnabled(boolean enabled) { public void setProcessUnallocSpaceEnabled(final boolean enabled) {
processUnallocCheckbox.setEnabled(enabled); processUnallocCheckbox.setSelected(enabled);
} }
@Override public void setDisabledModules(List<IngestModuleAbstract> disabledModules) {
public void paint(Graphics g) { tableModel.setUnselectedModules(disabledModules);
super.paint(g);
if (manager.isIngestRunning()) {
setProcessUnallocSpaceEnabled(false);
} else {
setProcessUnallocSpaceEnabled(true);
}
}
private void addModule(IngestModuleAbstract module) {
final String moduleName = module.getName();
modules.add(module);
moduleStates.put(moduleName, true);
} }
/** /**
@ -311,22 +267,19 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
dialog.close(); dialog.close();
currentModule.saveAdvancedConfiguration(); currentModule.saveAdvancedConfiguration();
reload();
} }
}); });
dialog.addWindowListener(new WindowAdapter() { dialog.addWindowListener(new WindowAdapter() {
@Override @Override
public void windowClosing(WindowEvent e) { public void windowClosing(WindowEvent e) {
dialog.close(); dialog.close();
reload();
} }
}); });
save(); // save the simple panel dialog.display(currentModule.getAdvancedConfiguration(context));
dialog.display(currentModule.getAdvancedConfiguration(null));
}//GEN-LAST:event_advancedButtonActionPerformed }//GEN-LAST:event_advancedButtonActionPerformed
private void processUnallocCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_processUnallocCheckboxActionPerformed private void processUnallocCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_processUnallocCheckboxActionPerformed
// TODO add your handling code here: // nothing to do here
}//GEN-LAST:event_processUnallocCheckboxActionPerformed }//GEN-LAST:event_processUnallocCheckboxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton advancedButton; private javax.swing.JButton advancedButton;
@ -343,9 +296,18 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
private class ModulesTableModel extends AbstractTableModel { private class ModulesTableModel extends AbstractTableModel {
private List<Map.Entry<IngestModuleAbstract, Boolean>>moduleData = new ArrayList<>();
public ModulesTableModel() {
List<IngestModuleAbstract> modules = IngestManager.getDefault().enumerateAllModules();
for (IngestModuleAbstract ingestModuleAbstract : modules) {
moduleData.add(new AbstractMap.SimpleEntry<>(ingestModuleAbstract, Boolean.TRUE));
}
}
@Override @Override
public int getRowCount() { public int getRowCount() {
return modules.size(); return moduleData.size();
} }
@Override @Override
@ -355,11 +317,11 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
@Override @Override
public Object getValueAt(int rowIndex, int columnIndex) { public Object getValueAt(int rowIndex, int columnIndex) {
String name = modules.get(rowIndex).getName(); Map.Entry<IngestModuleAbstract, Boolean> entry = moduleData.get(rowIndex);
if (columnIndex == 0) { if (columnIndex == 0) {
return moduleStates.get(name); return entry.getValue();
} else { } else {
return name; return entry.getKey().getName();
} }
} }
@ -371,8 +333,7 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
@Override @Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) { public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (columnIndex == 0) { if (columnIndex == 0) {
moduleStates.put((String) getValueAt(rowIndex, 1), (Boolean) aValue); moduleData.get(rowIndex).setValue((Boolean)aValue);
} }
} }
@ -380,125 +341,69 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
public Class<?> getColumnClass(int c) { public Class<?> getColumnClass(int c) {
return getValueAt(0, c).getClass(); return getValueAt(0, c).getClass();
} }
}
List<IngestModuleAbstract> getModulesToStart() { public List<IngestModuleAbstract> getSelectedModules() {
List<IngestModuleAbstract> modulesToStart = new ArrayList<IngestModuleAbstract>(); List<IngestModuleAbstract> selectedModules = new ArrayList<>();
for (IngestModuleAbstract module : modules) { for (Map.Entry<IngestModuleAbstract, Boolean> entry : moduleData) {
boolean moduleEnabled = moduleStates.get(module.getName()); if (entry.getValue().booleanValue()) {
if (moduleEnabled) { selectedModules.add(entry.getKey());
modulesToStart.add(module);
}
}
return modulesToStart;
}
private boolean processUnallocSpaceEnabled() {
return processUnallocCheckbox.isEnabled();
}
/**
* To be called whenever the next, close, or start buttons are pressed.
*
*/
@Override
public void save() {
// Save the current module
if (currentModule != null && currentModule.hasSimpleConfiguration()) {
currentModule.saveSimpleConfiguration();
}
// Save this panel
List<String> modulesDisabled = new ArrayList<String>();
for (int i = 0; i < modulesTable.getRowCount(); i++) {
// Column 0 is always the module's checkbox (which is retreived as a boolean)
Boolean enabled = (Boolean) modulesTable.getValueAt(i, 0);
if (!enabled) {
// Column 1 is always the module name
String moduleName = (String) modulesTable.getValueAt(i, 1);
modulesDisabled.add(moduleName);
}
}
// Add all the enabled modules to the properties separated by a coma
String list = "";
for (int i = 0; i < modulesDisabled.size(); i++) {
list += modulesDisabled.get(i);
if (i + 1 < modulesDisabled.size()) {
list += ", ";
}
}
ModuleSettings.setConfigSetting(IngestManager.MODULE_PROPERTIES, DISABLED_MOD, list);
String processUnalloc = Boolean.toString(processUnallocCheckbox.isSelected());
ModuleSettings.setConfigSetting(IngestManager.MODULE_PROPERTIES, PARSE_UNALLOC, processUnalloc);
}
/**
* Called when the dialog needs to be reloaded. Most commonly used to
* refresh the simple panel.
*
* Called every time this panel is displayed.
*/
@Override
public void reload() {
// Reload the simple panel
if (this.modulesTable.getSelectedRow() != -1) {
simplePanel.removeAll();
if (currentModule.hasSimpleConfiguration()) {
simplePanel.add(currentModule.getSimpleConfiguration(null));
}
simplePanel.revalidate();
simplePanel.repaint();
}
// Reload this panel
String list = ModuleSettings.getConfigSetting(IngestManager.MODULE_PROPERTIES, DISABLED_MOD);
if (list != null) { // if no property is found, list will be null
List<String> modulesDisabled = new ArrayList<String>(Arrays.asList(list.split(", ")));
// For every row, see if that module name is in the ArrayList
for (int i = 0; i < modulesTable.getRowCount(); i++) {
String moduleName = (String) modulesTable.getValueAt(i, 1);
if (modulesDisabled.contains(moduleName)) {
modulesTable.setValueAt(false, i, 0); // we found it, disable the module
} else {
modulesTable.setValueAt(true, i, 0); // not on disabled list, or a new module, enable it
} }
} }
} return selectedModules;
String processUnalloc = ModuleSettings.getConfigSetting(IngestManager.MODULE_PROPERTIES, PARSE_UNALLOC);
if (processUnalloc != null) {
processUnallocCheckbox.setSelected(Boolean.parseBoolean(processUnalloc));
}
}
@Override
public JPanel getIngestConfigPanel() {
this.reload();
return this;
}
@Override
public void setContent(List<Content> inputContent) {
this.inputContent = inputContent;
}
@Override
public void start() {
//pick the modules
List<IngestModuleAbstract> modulesToStart = getModulesToStart();
//update ingest proc. unalloc space
if (processUnallocSpaceEnabled()) {
manager.setProcessUnallocSpace(processUnallocCheckbox.isSelected());
} }
if (!modulesToStart.isEmpty()) { /**
manager.execute(modulesToStart, inputContent); * Sets the given modules as selected in the modules table
* @param selectedModules
*/
public void setSelectedModules(List<IngestModuleAbstract> selectedModules) {
// unselect all modules
for (Map.Entry<IngestModuleAbstract, Boolean> entry : moduleData) {
entry.setValue(Boolean.FALSE);
}
// select only the given modules
for (IngestModuleAbstract selectedModule : selectedModules) {
getEntryForModule(selectedModule).setValue(Boolean.TRUE);
}
// tell everyone about it
fireTableDataChanged();
} }
} /**
* Sets the given modules as NOT selected in the modules table
* @param selectedModules
*/
public void setUnselectedModules(List<IngestModuleAbstract> unselectedModules) {
// select all modules
for (Map.Entry<IngestModuleAbstract, Boolean> entry : moduleData) {
entry.setValue(Boolean.TRUE);
}
@Override // unselect only the given modules
public boolean isIngestRunning() { for (IngestModuleAbstract unselectedModule : unselectedModules) {
return manager.isIngestRunning(); getEntryForModule(unselectedModule).setValue(Boolean.FALSE);
}
// tell everyone about it
fireTableDataChanged();
}
public IngestModuleAbstract getModule(int row) {
return moduleData.get(row).getKey();
}
private Map.Entry<IngestModuleAbstract, Boolean> getEntryForModule(IngestModuleAbstract module) {
Map.Entry<IngestModuleAbstract, Boolean> entry = null;
for (Map.Entry<IngestModuleAbstract, Boolean> anEntry : moduleData) {
if (anEntry.getKey().equals(module)) {
entry = anEntry;
break;
}
}
return entry;
}
} }
/** /**
@ -506,57 +411,26 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
*/ */
private class ModulesTableRenderer extends DefaultTableCellRenderer { private class ModulesTableRenderer extends DefaultTableCellRenderer {
List<String> tooltips = new ArrayList<>();
public ModulesTableRenderer() {
List<IngestModuleAbstract> modules = IngestManager.getDefault().enumerateAllModules();
for (IngestModuleAbstract ingestModuleAbstract : modules) {
tooltips.add(ingestModuleAbstract.getDescription());
}
}
@Override @Override
public Component getTableCellRendererComponent( public Component getTableCellRendererComponent(
JTable table, Object value, JTable table, Object value,
boolean isSelected, boolean hasFocus, boolean isSelected, boolean hasFocus,
int row, int column) { int row, int column) {
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
final Component cell = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (column == 1) { if (column == 1) {
//String moduleName = (String) table.getModel().getValueAt(row, column); setToolTipText(tooltips.get(row));
IngestModuleAbstract module = modules.get(row);
String moduleDescr = module.getDescription();
String toolTip = moduleDescr;
if (inputContent != null && module.getType().equals(ModuleType.DataSource)) {
//DataSource module accepts only data source, does not work on any child
//show warning to user and set fg red for that module
boolean isDataSource = true;
for (Content content : inputContent) {
try {
if (content.getParent() != null) {
isDataSource = false;
break;
}
} catch (TskCoreException e) {
logger.log(Level.SEVERE, "Error checking if module input content is parentless data source", e);
}
}
if (! isDataSource ) {
cell.setForeground(Color.red);
toolTip = toolTip + "<br />WARNING: this module will not run on current selection because it operates only on root-level data-source (such as Image, Filesets).";
}
else {
cell.setForeground(Color.black);
}
} //end data source
else {
cell.setForeground(Color.black);
}
//
setToolTipText("<html>" + toolTip+ "</html>");
} }
return this;
return cell;
} }
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2012 Basis Technology Corp. * Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -154,8 +154,6 @@ public class IngestManager {
} catch (IngestModuleLoaderException ex) { } catch (IngestModuleLoaderException ex) {
logger.log(Level.SEVERE, "Error getting module loader"); logger.log(Level.SEVERE, "Error getting module loader");
} }
} }
/** /**
@ -243,7 +241,6 @@ public class IngestManager {
if (ui != null) { if (ui != null) {
ui.restoreMessages(); ui.restoreMessages();
} }
} }
/** /**
@ -346,17 +343,15 @@ public class IngestManager {
} }
} }
} }
//}
//AbstractFile ingester //AbstractFile ingester
boolean startAbstractFileIngester = false; boolean startAbstractFileIngester = false;
if (fileScheduler.hasNext()) { if (fileScheduler.hasNext()) {
if (abstractFileIngester if (abstractFileIngester == null) {
== null) {
startAbstractFileIngester = true; startAbstractFileIngester = true;
logger.log(Level.INFO, "Starting initial AbstractFile ingester"); logger.log(Level.INFO, "Starting initial AbstractFile ingester");
} //if worker had completed, restart it in case data is still enqueued }
//if worker had completed, restart it in case data is still enqueued
else if (abstractFileIngester.isDone()) { else if (abstractFileIngester.isDone()) {
startAbstractFileIngester = true; startAbstractFileIngester = true;
logger.log(Level.INFO, "Restarting AbstractFile ingester"); logger.log(Level.INFO, "Restarting AbstractFile ingester");
@ -369,6 +364,9 @@ public class IngestManager {
stats = new IngestManagerStats(); stats = new IngestManagerStats();
abstractFileIngester = new IngestAbstractFileProcessor(); abstractFileIngester = new IngestAbstractFileProcessor();
//init all fs modules, everytime new worker starts //init all fs modules, everytime new worker starts
/* @@@ I don't understand why we do an init on each module. Should do only modules
* that we are going to be using in the pipeline
*/
for (IngestModuleAbstractFile s : abstractFileModules) { for (IngestModuleAbstractFile s : abstractFileModules) {
IngestModuleInit moduleInit = new IngestModuleInit(); IngestModuleInit moduleInit = new IngestModuleInit();
try { try {
@ -421,7 +419,6 @@ public class IngestManager {
List<IngestDataSourceThread> toStop = new ArrayList<IngestDataSourceThread>(); List<IngestDataSourceThread> toStop = new ArrayList<IngestDataSourceThread>();
toStop.addAll(dataSourceIngesters); toStop.addAll(dataSourceIngesters);
for (IngestDataSourceThread dataSourceWorker : toStop) { for (IngestDataSourceThread dataSourceWorker : toStop) {
IngestModuleDataSource s = dataSourceWorker.getModule(); IngestModuleDataSource s = dataSourceWorker.getModule();
@ -440,7 +437,6 @@ public class IngestManager {
logger.log(Level.WARNING, "Exception while stopping module: " + s.getName(), e); logger.log(Level.WARNING, "Exception while stopping module: " + s.getName(), e);
} }
} }
} }
logger.log(Level.INFO, "stopped all"); logger.log(Level.INFO, "stopped all");
@ -545,7 +541,6 @@ public class IngestManager {
return module.hasBackgroundJobsRunning(); return module.hasBackgroundJobsRunning();
} }
} else { } else {
//data source module //data source module
synchronized (this) { synchronized (this) {
@ -570,10 +565,7 @@ public class IngestManager {
return false; return false;
} }
} }
} }
} }
/** /**
@ -607,7 +599,7 @@ public class IngestManager {
* *
* @param processUnallocSpace * @param processUnallocSpace
*/ */
void setProcessUnallocSpace(boolean processUnallocSpace) { public void setProcessUnallocSpace(boolean processUnallocSpace) {
this.processUnallocSpace = processUnallocSpace; this.processUnallocSpace = processUnallocSpace;
} }
@ -672,6 +664,13 @@ public class IngestManager {
return moduleLoader.getAbstractFileIngestModules(); return moduleLoader.getAbstractFileIngestModules();
} }
public List<IngestModuleAbstract> enumerateAllModules() {
List<IngestModuleAbstract> modules = new ArrayList<>();
modules.addAll(enumerateDataSourceModules());
modules.addAll(enumerateAbstractFileModules());
return modules;
}
//data source worker to remove itself when complete or interrupted //data source worker to remove itself when complete or interrupted
void removeDataSourceIngestWorker(IngestDataSourceThread worker) { void removeDataSourceIngestWorker(IngestDataSourceThread worker) {
//remove worker //remove worker
@ -697,7 +696,6 @@ public class IngestManager {
IngestManagerStats() { IngestManagerStats() {
errors = new HashMap<IngestModuleAbstract, Integer>(); errors = new HashMap<IngestModuleAbstract, Integer>();
} }
/** /**
@ -775,19 +773,8 @@ public class IngestManager {
public String toHtmlString() { public String toHtmlString() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("<html><body>"); sb.append("<html><body>");
sb.append("Ingest time: ").append(getTotalTimeString()).append("<br />"); sb.append("Ingest time: ").append(getTotalTimeString()).append("<br />");
sb.append("Total errors: ").append(errorsTotal).append("<br />"); sb.append("Total errors: ").append(errorsTotal).append("<br />");
/*
if (errorsTotal > 0) {
sb.append("Errors per module:");
for (IngestModuleAbstract module : errors.keySet()) {
final int errorsModule = errors.get(module);
sb.append("\t").append(module.getName()).append(": ").append(errorsModule).append("<br />");
}
}
* */
sb.append("</body></html>"); sb.append("</body></html>");
return sb.toString(); return sb.toString();
} }
@ -1083,9 +1070,6 @@ public class IngestManager {
private void queueAll(List<IngestModuleAbstract> modules, final List<Content> inputs) { private void queueAll(List<IngestModuleAbstract> modules, final List<Content> inputs) {
final IngestScheduler.DataSourceScheduler dataSourceScheduler = scheduler.getDataSourceScheduler();
final IngestScheduler.FileScheduler fileScheduler = scheduler.getFileScheduler();
int processed = 0; int processed = 0;
for (Content input : inputs) { for (Content input : inputs) {
final String inputName = input.getName(); final String inputName = input.getName();
@ -1112,16 +1096,16 @@ public class IngestManager {
logger.log(Level.INFO, "Error loading module and adding input " + inputName logger.log(Level.INFO, "Error loading module and adding input " + inputName
+ " with module " + module.getName()); + " with module " + module.getName());
} }
break; break;
case AbstractFile: case AbstractFile:
//enqueue the same singleton AbstractFile module //enqueue the same singleton AbstractFile module
logger.log(Level.INFO, "Adding input " + inputName logger.log(Level.INFO, "Adding input " + inputName
+ " number of AbstractFile to module " + module.getName()); + " for AbstractFileModule " + module.getName());
fileMods.add((IngestModuleAbstractFile) module); fileMods.add((IngestModuleAbstractFile) module);
break; break;
default: default:
logger.log(Level.SEVERE, "Unexpected module type: " + module.getType().name()); logger.log(Level.SEVERE, "Unexpected module type: " + module.getType().name());
} }
@ -1138,6 +1122,7 @@ public class IngestManager {
new PipelineContext<IngestModuleDataSource>(dataSourceTask, processUnalloc); new PipelineContext<IngestModuleDataSource>(dataSourceTask, processUnalloc);
logger.log(Level.INFO, "Queing data source ingest task: " + dataSourceTask); logger.log(Level.INFO, "Queing data source ingest task: " + dataSourceTask);
progress.progress("DataSource Ingest" + " " + inputName, processed); progress.progress("DataSource Ingest" + " " + inputName, processed);
final IngestScheduler.DataSourceScheduler dataSourceScheduler = scheduler.getDataSourceScheduler();
dataSourceScheduler.schedule(dataSourcePipelineContext); dataSourceScheduler.schedule(dataSourcePipelineContext);
progress.progress("DataSource Ingest" + " " + inputName, ++processed); progress.progress("DataSource Ingest" + " " + inputName, ++processed);
@ -1148,6 +1133,7 @@ public class IngestManager {
= new PipelineContext<IngestModuleAbstractFile>(fTask, processUnalloc); = new PipelineContext<IngestModuleAbstractFile>(fTask, processUnalloc);
logger.log(Level.INFO, "Queing file ingest task: " + fTask); logger.log(Level.INFO, "Queing file ingest task: " + fTask);
progress.progress("File Ingest" + " " + inputName, processed); progress.progress("File Ingest" + " " + inputName, processed);
final IngestScheduler.FileScheduler fileScheduler = scheduler.getFileScheduler();
fileScheduler.schedule(filepipelineContext); fileScheduler.schedule(filepipelineContext);
progress.progress("File Ingest" + " " + inputName, ++processed); progress.progress("File Ingest" + " " + inputName, ++processed);

View File

@ -145,35 +145,38 @@ public abstract class IngestModuleAbstract {
*/ */
public void saveAdvancedConfiguration() {} public void saveAdvancedConfiguration() {}
/** /**
* Returns a panel that displays the simple (run-time) configuration * Returns a panel that displays the simple (run-time) configuration for the
* for the given configuration context (such as pipeline instance). * given configuration context (such as pipeline instance). This is
* This is presented to the user before ingest starts and only basic * presented to the user before ingest starts and only basic settings should
* settings should be given here. Use the advanced (general) configuration * be given here. Use the advanced (general) configuration panel for more
* panel for more in-depth interfaces. * in-depth interfaces. The module (or its configuration controller object)
* The module (or its configuration controller object) is responsible for preserving / saving its configuration state * is responsible for preserving / saving its configuration state In
* In addition, saveSimpleConfiguration() can be used as the trigger. * addition, saveSimpleConfiguration() can be used as the trigger.
* *
* @param context the configuration context to use in the panel * @param context the configuration context to use in the panel
* @return JPanel containing basic configuration widgets or null if simple configuration is not available * @return JPanel containing basic configuration widgets or null if simple
* configuration is not available
*/ */
public javax.swing.JPanel getSimpleConfiguration(String context) { public javax.swing.JPanel getSimpleConfiguration(String context) {
return null; return null;
} }
/** /**
* Returns a panel that displays the advanced (run-time) configuration * Returns a panel that displays the advanced (run-time) configuration for
* for the given configuration context (such as pipeline instance). * the given configuration context (such as pipeline instance). Implements
* Implements advanced module configuration exposed to the user before ingest starts. * advanced module configuration exposed to the user before ingest starts.
* *
* The module (or its configuration controller object) * The module (or its configuration controller object) is responsible for
* is responsible for preserving / saving its configuration state * preserving / saving its configuration state In addition,
* In addition, saveAdvancedConfiguration() can be used as the trigger. * saveAdvancedConfiguration() can be used as the trigger.
* *
* @param context the configuration context to use in the panel * @param context the configuration context to use in the panel
* @return JPanel containing advanced configuration widgets or null if advanced configuration is not available * @return JPanel containing advanced configuration widgets or null if
* advanced configuration is not available
*/ */
public javax.swing.JPanel getAdvancedConfiguration(String context) { public javax.swing.JPanel getAdvancedConfiguration(String context) {
return null; return null;
}; }
} }

View File

@ -466,10 +466,12 @@ public final class IngestModuleLoader {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void autodiscover() throws IngestModuleLoaderException { private void autodiscover() throws IngestModuleLoaderException {
// Use Lookup to find the other NBM modules. We'll later search them for ingest modules
Collection<? extends ModuleInfo> moduleInfos = Lookup.getDefault().lookupAll(ModuleInfo.class); Collection<? extends ModuleInfo> moduleInfos = Lookup.getDefault().lookupAll(ModuleInfo.class);
logger.log(Level.INFO, "Autodiscovery, found #platform modules: " + moduleInfos.size()); logger.log(Level.INFO, "Autodiscovery, found #platform modules: " + moduleInfos.size());
Set<URL> urls = getJarPaths(moduleInfos); Set<URL> urls = getJarPaths(moduleInfos);
ArrayList<Reflections> reflectionsSet = new ArrayList<>();
for (final ModuleInfo moduleInfo : moduleInfos) { for (final ModuleInfo moduleInfo : moduleInfos) {
if (moduleInfo.isEnabled()) { if (moduleInfo.isEnabled()) {
@ -489,104 +491,115 @@ public final class IngestModuleLoader {
cb.filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix(basePackageName))); cb.filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix(basePackageName)));
cb.setUrls(urls); cb.setUrls(urls);
cb.setScanners(new SubTypesScanner(), new ResourcesScanner()); cb.setScanners(new SubTypesScanner(), new ResourcesScanner());
Reflections reflections = new Reflections(cb); reflectionsSet.add(new Reflections(cb));
Set<?> fileModules = reflections.getSubTypesOf(IngestModuleAbstractFile.class);
Iterator<?> it = fileModules.iterator();
while (it.hasNext()) {
logger.log(Level.INFO, "Found file ingest module in: " + basePackageName + ": " + it.next().toString());
}
Set<?> dataSourceModules = reflections.getSubTypesOf(IngestModuleDataSource.class);
it = dataSourceModules.iterator();
while (it.hasNext()) {
logger.log(Level.INFO, "Found DataSource ingest module in: " + basePackageName + ": " + it.next().toString());
}
//find out which modules to add
//TODO check which modules to remove (which modules were uninstalled)
boolean modulesChanged = false;
it = fileModules.iterator();
while (it.hasNext()) {
boolean exists = false;
Class<IngestModuleAbstractFile> foundClass = (Class<IngestModuleAbstractFile>) it.next();
for (IngestModuleLoader.XmlPipelineRaw rawP : pipelinesXML) {
if (!rawP.type.equals(IngestModuleLoader.XmlPipelineRaw.PIPELINE_TYPE.FILE_ANALYSIS.toString())) {
continue; //skip
}
for (IngestModuleLoader.XmlModuleRaw rawM : rawP.modules) {
//logger.log(Level.INFO, "CLASS NAME : " + foundClass.getName());
if (foundClass.getName().equals(rawM.location)) {
exists = true;
break;
}
}
if (exists == true) {
break;
}
}
if (exists == false) {
logger.log(Level.INFO, "Discovered a new file module to load: " + foundClass.getName());
//ADD MODULE
addModuleToRawPipeline(foundClass, IngestModuleLoader.XmlPipelineRaw.PIPELINE_TYPE.FILE_ANALYSIS);
modulesChanged = true;
}
}
it = dataSourceModules.iterator();
while (it.hasNext()) {
boolean exists = false;
Class<IngestModuleDataSource> foundClass = (Class<IngestModuleDataSource>) it.next();
for (IngestModuleLoader.XmlPipelineRaw rawP : pipelinesXML) {
if (!rawP.type.equals(IngestModuleLoader.XmlPipelineRaw.PIPELINE_TYPE.DATA_SOURCE_ANALYSIS.toString())) {
continue; //skip
}
for (IngestModuleLoader.XmlModuleRaw rawM : rawP.modules) {
//logger.log(Level.INFO, "CLASS NAME : " + foundClass.getName());
if (foundClass.getName().equals(rawM.location)) {
exists = true;
break;
}
}
if (exists == true) {
break;
}
}
if (exists == false) {
logger.log(Level.INFO, "Discovered a new DataSource module to load: " + foundClass.getName());
//ADD MODULE
addModuleToRawPipeline(foundClass, IngestModuleLoader.XmlPipelineRaw.PIPELINE_TYPE.DATA_SOURCE_ANALYSIS);
modulesChanged = true;
}
}
if (modulesChanged) {
save();
pcs.firePropertyChange(IngestModuleLoader.Event.ModulesReloaded.toString(), 0, 1);
}
/*
//Enumeration<URL> resources = moduleClassLoader.getResources(basePackageName);
Enumeration<URL> resources = classLoader.getResources(basePackageName);
while (resources.hasMoreElements()) {
System.out.println(resources.nextElement());
} */
} else {
//logger.log(Level.INFO, "Module disabled: " + moduleInfo.getDisplayName() );
} }
} }
/* This area is used to load the example modules. They are not found via lookup since they
* are in this NBM module.
* Uncomment this section to rum the examples.
*/
/*
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix("org.sleuthkit.autopsy.examples")));
cb.setUrls(urls);
cb.setScanners(new SubTypesScanner(), new ResourcesScanner());
reflectionsSet.add(new Reflections(cb));
*/
for (Reflections reflections : reflectionsSet) {
Set<?> fileModules = reflections.getSubTypesOf(IngestModuleAbstractFile.class);
Iterator<?> it = fileModules.iterator();
while (it.hasNext()) {
logger.log(Level.INFO, "Found file ingest module in: " + reflections.getClass().getSimpleName() + ": " + it.next().toString());
}
Set<?> dataSourceModules = reflections.getSubTypesOf(IngestModuleDataSource.class);
it = dataSourceModules.iterator();
while (it.hasNext()) {
logger.log(Level.INFO, "Found DataSource ingest module in: " + reflections.getClass().getSimpleName() + ": " + it.next().toString());
}
//find out which modules to add
//TODO check which modules to remove (which modules were uninstalled)
boolean modulesChanged = false;
it = fileModules.iterator();
while (it.hasNext()) {
boolean exists = false;
Class<IngestModuleAbstractFile> foundClass = (Class<IngestModuleAbstractFile>) it.next();
for (IngestModuleLoader.XmlPipelineRaw rawP : pipelinesXML) {
if (!rawP.type.equals(IngestModuleLoader.XmlPipelineRaw.PIPELINE_TYPE.FILE_ANALYSIS.toString())) {
continue; //skip
}
for (IngestModuleLoader.XmlModuleRaw rawM : rawP.modules) {
//logger.log(Level.INFO, "CLASS NAME : " + foundClass.getName());
if (foundClass.getName().equals(rawM.location)) {
exists = true;
break;
}
}
if (exists == true) {
break;
}
}
if (exists == false) {
logger.log(Level.INFO, "Discovered a new file module to load: " + foundClass.getName());
//ADD MODULE
addModuleToRawPipeline(foundClass, IngestModuleLoader.XmlPipelineRaw.PIPELINE_TYPE.FILE_ANALYSIS);
modulesChanged = true;
}
}
it = dataSourceModules.iterator();
while (it.hasNext()) {
boolean exists = false;
Class<IngestModuleDataSource> foundClass = (Class<IngestModuleDataSource>) it.next();
for (IngestModuleLoader.XmlPipelineRaw rawP : pipelinesXML) {
if (!rawP.type.equals(IngestModuleLoader.XmlPipelineRaw.PIPELINE_TYPE.DATA_SOURCE_ANALYSIS.toString())) {
continue; //skip
}
for (IngestModuleLoader.XmlModuleRaw rawM : rawP.modules) {
//logger.log(Level.INFO, "CLASS NAME : " + foundClass.getName());
if (foundClass.getName().equals(rawM.location)) {
exists = true;
break;
}
}
if (exists == true) {
break;
}
}
if (exists == false) {
logger.log(Level.INFO, "Discovered a new DataSource module to load: " + foundClass.getName());
//ADD MODULE
addModuleToRawPipeline(foundClass, IngestModuleLoader.XmlPipelineRaw.PIPELINE_TYPE.DATA_SOURCE_ANALYSIS);
modulesChanged = true;
}
}
if (modulesChanged) {
save();
pcs.firePropertyChange(IngestModuleLoader.Event.ModulesReloaded.toString(), 0, 1);
}
/*
//Enumeration<URL> resources = moduleClassLoader.getResources(basePackageName);
Enumeration<URL> resources = classLoader.getResources(basePackageName);
while (resources.hasMoreElements()) {
System.out.println(resources.nextElement());
} */
}
} }
/** /**

View File

@ -106,6 +106,159 @@ public class ReportHTML implements TableReportModule {
out = null; out = null;
} }
/**
* Generate a file name for the given datatype, by replacing any
* undesirable chars, like /, or spaces
* @param dataType data type for which to generate a file name
*/
private String dataTypeToFileName(String dataType) {
String fileName = org.sleuthkit.autopsy.coreutils.FileUtil.escapeFileName(dataType);
// replace all ' ' with '_'
fileName = fileName.replaceAll(" ", "_");
return fileName;
}
/**
* Copies a suitable icon for the given data type in the output directory and
* returns the icon file name to use for the given data type.
*/
private String useDataTypeIcon(String dataType)
{
String iconFilePath;
String iconFileName;
InputStream in = null;
OutputStream output = null;
logger.log(Level.INFO, "useDataTypeIcon: dataType = " + dataType);
// find the artifact with matching display name
BlackboardArtifact.ARTIFACT_TYPE artifactType = null;
for (ARTIFACT_TYPE v : ARTIFACT_TYPE.values()) {
if (v.getDisplayName().equals(dataType)) {
artifactType = v;
}
}
if (null != artifactType)
{
// set the icon file name
iconFileName = dataTypeToFileName(artifactType.getDisplayName()) + ".png";
iconFilePath = path + File.separator + iconFileName;
// determine the source image to use
switch (artifactType) {
case TSK_WEB_BOOKMARK:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/bookmarks.png");
break;
case TSK_WEB_COOKIE:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/cookies.png");
break;
case TSK_WEB_HISTORY:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/history.png");
break;
case TSK_WEB_DOWNLOAD:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/downloads.png");
break;
case TSK_RECENT_OBJECT:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/recent.png");
break;
case TSK_INSTALLED_PROG:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/installed.png");
break;
case TSK_KEYWORD_HIT:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/keywords.png");
break;
case TSK_HASHSET_HIT:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/hash.png");
break;
case TSK_DEVICE_ATTACHED:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/devices.png");
break;
case TSK_WEB_SEARCH_QUERY:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/search.png");
break;
case TSK_METADATA_EXIF:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/exif.png");
break;
case TSK_TAG_FILE:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/userbookmarks.png");
break;
case TSK_TAG_ARTIFACT:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/userbookmarks.png");
break;
case TSK_SERVICE_ACCOUNT:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/account-icon-16.png");
break;
case TSK_CONTACT:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/contact.png");
break;
case TSK_MESSAGE:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/message.png");
break;
case TSK_CALLLOG:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/calllog.png");
break;
case TSK_CALENDAR_ENTRY:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/calendar.png");
break;
case TSK_SPEED_DIAL_ENTRY:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/speeddialentry.png");
break;
case TSK_BLUETOOTH_PAIRING:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/bluetooth.png");
break;
case TSK_GPS_BOOKMARK:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/gpsfav.png");
break;
case TSK_GPS_LAST_KNOWN_LOCATION:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/gps-lastlocation.png");
break;
case TSK_GPS_SEARCH:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/gps-search.png");
break;
default:
logger.log(Level.WARNING, "useDataTypeIcon: unhandled artifact type = " + dataType);
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/star.png");
iconFileName = "star.png";
iconFilePath = path + File.separator + iconFileName;
break;
}
}
else { // no defined artifact found for this dataType
logger.log(Level.WARNING, "useDataTypeIcon: no artifact found for data type = " + dataType);
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/star.png");
iconFileName = "star.png";
iconFilePath = path + File.separator + iconFileName;
}
try {
output = new FileOutputStream(iconFilePath);
FileUtil.copy(in, output);
in.close();
output.close();
} catch (IOException ex) {
logger.log(Level.SEVERE, "Failed to extract images for HTML report.", ex);
} finally {
if (output != null) {
try {
output.flush();
output.close();
} catch (IOException ex) {
}
} if (in != null) {
try {
in.close();
} catch (IOException ex) {
}
}
}
return iconFileName;
}
/** /**
* Start this report by setting the path, refreshing member variables, * Start this report by setting the path, refreshing member variables,
* and writing the skeleton for the HTML report. * and writing the skeleton for the HTML report.
@ -151,7 +304,7 @@ public class ReportHTML implements TableReportModule {
*/ */
@Override @Override
public void startDataType(String title) { public void startDataType(String title) {
String fTitle = org.sleuthkit.autopsy.coreutils.FileUtil.escapeFileName(title); String fTitle = dataTypeToFileName(title);
// Make a new out for this page // Make a new out for this page
try { try {
//escape out slashes tha that appear in title //escape out slashes tha that appear in title
@ -186,7 +339,7 @@ public class ReportHTML implements TableReportModule {
* @param comment Comment on the data type, may be the empty string * @param comment Comment on the data type, may be the empty string
*/ */
public void startDataType(String name, String comment) { public void startDataType(String name, String comment) {
String title = org.sleuthkit.autopsy.coreutils.FileUtil.escapeFileName(name); String title = dataTypeToFileName(name);
try { try {
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + title + getExtension()), "UTF-8")); out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + title + getExtension()), "UTF-8"));
} catch (FileNotFoundException ex) { } catch (FileNotFoundException ex) {
@ -614,9 +767,10 @@ public class ReportHTML implements TableReportModule {
nav.append("<li style=\"background: url(summary.png) left center no-repeat;\"><a href=\"summary.html\" target=\"content\">Case Summary</a></li>\n"); nav.append("<li style=\"background: url(summary.png) left center no-repeat;\"><a href=\"summary.html\" target=\"content\">Case Summary</a></li>\n");
for (String dataType : dataTypes.keySet()) { for (String dataType : dataTypes.keySet()) {
String dataTypeEsc = org.sleuthkit.autopsy.coreutils.FileUtil.escapeFileName(dataType); String dataTypeEsc = dataTypeToFileName(dataType);
nav.append("<li style=\"background: url('").append(dataType) String iconFileName = useDataTypeIcon(dataType);
.append(".png') left center no-repeat;\"><a href=\"") nav.append("<li style=\"background: url('").append(iconFileName)
.append("') left center no-repeat;\"><a href=\"")
.append(dataTypeEsc).append(".html\" target=\"content\">") .append(dataTypeEsc).append(".html\" target=\"content\">")
.append(dataType).append(" (").append(dataTypes.get(dataType)) .append(dataType).append(" (").append(dataTypes.get(dataType))
.append(")</a></li>\n"); .append(")</a></li>\n");
@ -668,145 +822,6 @@ public class ReportHTML implements TableReportModule {
in.close(); in.close();
output.close(); output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/bookmarks.png");
output = new FileOutputStream(new File(path + File.separator + "Bookmarks.png"));
FileUtil.copy(in, output);
in.close();
output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/cookies.png");
output = new FileOutputStream(new File(path + File.separator + "Cookies.png"));
FileUtil.copy(in, output);
in.close();
output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/history.png");
output = new FileOutputStream(new File(path + File.separator + "Web History.png"));
FileUtil.copy(in, output);
in.close();
output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/downloads.png");
output = new FileOutputStream(new File(path + File.separator + "Downloads.png"));
FileUtil.copy(in, output);
in.close();
output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/search.png");
output = new FileOutputStream(new File(path + File.separator + "Web Search Engine Queries.png"));
FileUtil.copy(in, output);
in.close();
output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/recent.png");
output = new FileOutputStream(new File(path + File.separator + "Recent Documents.png"));
FileUtil.copy(in, output);
in.close();
output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/installed.png");
output = new FileOutputStream(new File(path + File.separator + "Installed Programs.png"));
FileUtil.copy(in, output);
in.close();
output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/keywords.png");
output = new FileOutputStream(new File(path + File.separator + "Keyword Hits.png"));
FileUtil.copy(in, output);
in.close();
output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/devices.png");
output = new FileOutputStream(new File(path + File.separator + "Devices Attached.png"));
FileUtil.copy(in, output);
in.close();
output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/exif.png");
output = new FileOutputStream(new File(path + File.separator + "EXIF Metadata.png"));
FileUtil.copy(in, output);
in.close();
output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/userbookmarks.png");
output = new FileOutputStream(new File(path + File.separator + "File Tags.png"));
FileUtil.copy(in, output);
in.close();
output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/userbookmarks.png");
output = new FileOutputStream(new File(path + File.separator + "Result Tags.png"));
FileUtil.copy(in, output);
in.close();
output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/hash.png");
output = new FileOutputStream(new File(path + File.separator + "Hashset Hits.png"));
FileUtil.copy(in, output);
in.close();
output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/contact.png");
output = new FileOutputStream(new File(path + File.separator + "Contacts.png"));
FileUtil.copy(in, output);
in.close();
output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/message.png");
output = new FileOutputStream(new File(path + File.separator + "Messages.png"));
FileUtil.copy(in, output);
in.close();
output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/calllog.png");
output = new FileOutputStream(new File(path + File.separator + "Call Logs.png"));
FileUtil.copy(in, output);
in.close();
output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/calendar.png");
output = new FileOutputStream(new File(path + File.separator + "Calendar Entries.png"));
FileUtil.copy(in, output);
in.close();
output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/speeddialentry.png");
output = new FileOutputStream(new File(path + File.separator + "Speed Dial Entries.png"));
FileUtil.copy(in, output);
in.close();
output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/bluetooth.png");
output = new FileOutputStream(new File(path + File.separator + "BlueTooth.png"));
FileUtil.copy(in, output);
in.close();
output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/gpsfav.png");
output = new FileOutputStream(new File(path + File.separator + "GPS Bookmarks.png"));
FileUtil.copy(in, output);
in.close();
output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/gps-lastlocation.png");
output = new FileOutputStream(new File(path + File.separator + "GPS Last Location.png"));
FileUtil.copy(in, output);
in.close();
output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/gps-search.png");
output = new FileOutputStream(new File(path + File.separator + "GPS Search.png"));
FileUtil.copy(in, output);
in.close();
output.close();
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/account-icon-16.png");
output = new FileOutputStream(new File(path + File.separator + "Accounts.png"));
FileUtil.copy(in, output);
in.close();
output.close();
} catch (IOException ex) { } catch (IOException ex) {
logger.log(Level.SEVERE, "Failed to extract images for HTML report.", ex); logger.log(Level.SEVERE, "Failed to extract images for HTML report.", ex);

Binary file not shown.

After

Width:  |  Height:  |  Size: 674 B

View File

@ -46,6 +46,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.ReadContentInputStream;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
/** /**
@ -92,6 +93,11 @@ public final class ExifParserFileIngestModule extends IngestModuleAbstractFile {
return IngestModuleAbstractFile.ProcessResult.OK; return IngestModuleAbstractFile.ProcessResult.OK;
} }
// skip known
if (content.getKnown().equals(TskData.FileKnown.KNOWN)) {
return IngestModuleAbstractFile.ProcessResult.OK;
}
//skip unsupported //skip unsupported
if (! parsableFormat(content)) { if (! parsableFormat(content)) {
return IngestModuleAbstractFile.ProcessResult.OK; return IngestModuleAbstractFile.ProcessResult.OK;

View File

@ -504,37 +504,42 @@
when adding a document. when adding a document.
--> -->
<!-- object id of the file -->
<field name="id" type="string" indexed="true" stored="true" required="true" /> <field name="id" type="string" indexed="true" stored="true" required="true" />
<!-- use image_id to easily search a specific image only --> <!-- use image_id to easily search a specific image only -->
<field name="image_id" type="string" indexed="true" stored="true" required="true" /> <field name="image_id" type="string" indexed="true" stored="false" required="true" />
<!-- The content field holds the text extracted by SolrCell -->
<!-- Autopsy pushes text to the content field and gets the text to display from it. It is copied to other places -->
<field name="content" type="text_general" indexed="true" stored="true" termVectors="true" termPositions="true" termOffsets="true" /> <field name="content" type="text_general" indexed="true" stored="true" termVectors="true" termPositions="true" termOffsets="true" />
<!-- The strings field holds strings extracted from files that SolrCell doesn't support --> <!-- The strings field holds strings extracted from files that SolrCell doesn't support -->
<field name="strings" type="text_general" indexed="true" stored="true"/> <!--<field name="strings" type="text_general" indexed="true" stored="true"/>-->
<field name="file_name" type="text_general" indexed="true" stored="true"/>
<field name="ctime" type="tdate" indexed="true" stored="true"/> <field name="file_name" type="text_general" indexed="false" stored="true"/>
<field name="atime" type="tdate" indexed="true" stored="true"/> <field name="ctime" type="tdate" indexed="false" stored="false"/>
<field name="mtime" type="tdate" indexed="true" stored="true"/> <field name="atime" type="tdate" indexed="false" stored="false"/>
<field name="crtime" type="tdate" indexed="true" stored="true"/> <field name="mtime" type="tdate" indexed="false" stored="false"/>
<!-- file chunk-specific fields (optional for others) --> <field name="crtime" type="tdate" indexed="false" stored="false"/>
<!-- for a parent file with no content, number of chunks are specified --> <!-- file chunk-specific fields (optional for others) -->
<field name="num_chunks" type="int" indexed="true" stored="true" required="false" /> <!-- for a parent file with no content, number of chunks are specified -->
<field name="num_chunks" type="int" indexed="true" stored="true" required="false" />
<!-- Common metadata fields, named specifically to match up with <!-- Common metadata fields, named specifically to match up with
SolrCell metadata when parsing rich documents such as Word, PDF. SolrCell metadata when parsing rich documents such as Word, PDF.
Some fields are multiValued only because Tika currently may return Some fields are multiValued only because Tika currently may return
multiple values for them. multiple values for them.
--> -->
<field name="title" type="text_general" indexed="true" stored="true" multiValued="true"/> <field name="title" type="text_general" indexed="false" stored="false" multiValued="true"/>
<field name="subject" type="text_general" indexed="true" stored="true"/> <field name="subject" type="text_general" indexed="false" stored="false"/>
<field name="description" type="text_general" indexed="true" stored="true"/> <field name="description" type="text_general" indexed="false" stored="false"/>
<field name="comments" type="text_general" indexed="true" stored="true"/> <field name="comments" type="text_general" indexed="false" stored="false"/>
<field name="author" type="text_general" indexed="true" stored="true"/> <field name="author" type="text_general" indexed="false" stored="false"/>
<field name="keywords" type="text_general" indexed="true" stored="true"/> <field name="keywords" type="text_general" indexed="false" stored="false"/>
<field name="category" type="text_general" indexed="true" stored="true"/> <field name="category" type="text_general" indexed="false" stored="false"/>
<field name="content_type" type="string" indexed="true" stored="true" multiValued="true"/> <field name="content_type" type="string" indexed="false" stored="false" multiValued="true"/>
<field name="last_modified" type="date" indexed="true" stored="true"/> <field name="last_modified" type="date" indexed="false" stored="false"/>
<field name="links" type="string" indexed="true" stored="true" multiValued="true"/> <field name="links" type="string" indexed="false" stored="false" multiValued="true"/>
<!-- Tika places all metadata into a multivalued field named "meta" --> <!-- Tika places all metadata into a multivalued field named "meta" -->
<field name="meta" type="text_general" indexed="true" stored="true" multiValued="true"/> <field name="meta" type="text_general" indexed="true" stored="true" multiValued="true"/>
@ -545,10 +550,11 @@
<!-- catchall text field that indexes tokens both normally and in reverse for efficient <!-- catchall text field that indexes tokens both normally and in reverse for efficient
leading wildcard queries. --> leading wildcard queries. -->
<field name="text_rev" type="text_general_rev" indexed="true" stored="false" multiValued="true"/> <!--<field name="text_rev" type="text_general_rev" indexed="true" stored="false" multiValued="true"/>-->
<!-- field with white-space tokenized words for TermsComponent regex search (useful for fast search of IP addresses, URLs, certain phone numbers) <!-- field with white-space tokenized words for TermsComponent regex search (useful for fast search of IP addresses, URLs, certain phone numbers)
also be useful for Lucene based queries containing special characters--> also be useful for Lucene based queries containing special characters-->
<!-- populated via copyField -->
<field name="content_ws" type="text_ws" indexed="true" stored="false" /> <field name="content_ws" type="text_ws" indexed="true" stored="false" />
<!-- Uncommenting the following will create a "timestamp" field using <!-- Uncommenting the following will create a "timestamp" field using
@ -621,7 +627,7 @@
<copyField source="content" dest="text"/> <copyField source="content" dest="text"/>
<copyField source="file_name" dest="text"/> <copyField source="file_name" dest="text"/>
<copyField source="meta" dest="text"/> <copyField source="meta" dest="text"/>
<copyField source="strings" dest="text"/> <!--<copyField source="strings" dest="text"/>-->
<copyField source="content" dest="content_ws"/> <copyField source="content" dest="content_ws"/>
<!-- Above, multiple source fields are copied to the [text] field. <!-- Above, multiple source fields are copied to the [text] field.

View File

@ -120,12 +120,11 @@ public class AbstractFileTikaTextExtract implements AbstractFileExtract {
boolean success = false; boolean success = false;
Reader reader = null; Reader reader = null;
final InputStream stream = new ReadContentInputStream(sourceFile); final InputStream stream = new ReadContentInputStream(sourceFile);
try { try {
Metadata meta = new Metadata(); Metadata meta = new Metadata();
//Tika parse request with timeout
//Parse the file in a task
Tika tika = new Tika(); //new tika instance for every file, to workaround tika memory issues Tika tika = new Tika(); //new tika instance for every file, to workaround tika memory issues
ParseRequestTask parseTask = new ParseRequestTask(tika, stream, meta, sourceFile); ParseRequestTask parseTask = new ParseRequestTask(tika, stream, meta, sourceFile);
final Future<?> future = tikaParseExecutor.submit(parseTask); final Future<?> future = tikaParseExecutor.submit(parseTask);
@ -145,14 +144,16 @@ public class AbstractFileTikaTextExtract implements AbstractFileExtract {
throw new IngesterException(msg); throw new IngesterException(msg);
} }
// get the reader with the results
reader = parseTask.getReader(); reader = parseTask.getReader();
if (reader == null) { if (reader == null) {
//likely due to exception in parse() //likely due to exception in parse()
logger.log(Level.WARNING, "No reader available from Tika parse"); logger.log(Level.WARNING, "No reader available from Tika parse");
return false; return false;
} }
// break the results into chunks and index
success = true; success = true;
long readSize; long readSize;
long totalRead = 0; long totalRead = 0;
@ -180,8 +181,6 @@ public class AbstractFileTikaTextExtract implements AbstractFileExtract {
//this is the last chunk //this is the last chunk
eof = true; eof = true;
} }
} }
//logger.log(Level.INFO, "TOTAL READ SIZE: " + totalRead + " file: " + sourceFile.getName()); //logger.log(Level.INFO, "TOTAL READ SIZE: " + totalRead + " file: " + sourceFile.getName());
@ -293,8 +292,8 @@ public class AbstractFileTikaTextExtract implements AbstractFileExtract {
} }
/** /**
* Runnable and timeable task that calls tika to parse the content using * Runnable task that calls tika to parse the content using
* streaming * the input stream. Provides reader for results.
*/ */
private static class ParseRequestTask implements Runnable { private static class ParseRequestTask implements Runnable {

View File

@ -29,7 +29,8 @@ import org.sleuthkit.autopsy.keywordsearch.KeywordSearch.QueryType;
import org.sleuthkit.autopsy.keywordsearch.KeywordSearchQueryManager.Presentation; import org.sleuthkit.autopsy.keywordsearch.KeywordSearchQueryManager.Presentation;
/** /**
* Common functionality among keyword search performers / widgets * Common functionality among keyword search performers / widgets.
* This is extended by the various panels and interfaces that perform the keyword searches.
*/ */
abstract class AbstractKeywordSearchPerformer extends javax.swing.JPanel implements KeywordSearchPerformerInterface { abstract class AbstractKeywordSearchPerformer extends javax.swing.JPanel implements KeywordSearchPerformerInterface {
@ -105,7 +106,8 @@ abstract class AbstractKeywordSearchPerformer extends javax.swing.JPanel impleme
return; return;
} }
man = new KeywordSearchQueryManager(keywords, Presentation.COLLAPSE); man = new KeywordSearchQueryManager(keywords, Presentation.COLLAPSE);
} else { }
else {
QueryType queryType = null; QueryType queryType = null;
if (isLuceneQuerySelected()) { if (isLuceneQuerySelected()) {
queryType = QueryType.WORD; queryType = QueryType.WORD;

View File

@ -416,14 +416,16 @@ public class ExtractedContentViewer implements DataContentViewer {
//because we are storing extracted text in chunks only //because we are storing extracted text in chunks only
//and the non-chunk stores meta-data only //and the non-chunk stores meta-data only
String name = contentObj.getName(); String name = contentObj.getName();
String msg = "<p style='font-style:italic'>No extracted text present in the index for file: " + name + " </p>"; String msg = null;
if (contentObj instanceof AbstractFile) { if (contentObj instanceof AbstractFile) {
//we know it's AbstractFile, but do quick check to make sure if we index other objects in future //we know it's AbstractFile, but do quick check to make sure if we index other objects in future
boolean isKnown = FileKnown.KNOWN.equals(((AbstractFile)contentObj).getKnown()); boolean isKnown = FileKnown.KNOWN.equals(((AbstractFile)contentObj).getKnown());
if (isKnown && KeywordSearchSettings.getSkipKnown()) { if (isKnown && KeywordSearchSettings.getSkipKnown()) {
msg += "<p style='font-style:italic'>It is a 'known' file and the current settings opt to skip indexing 'known' files during ingest. </p>"; msg = "<p style='font-style:italic'>" + name + " is a known file (based on MD5 hash) and does not have text in the index.</p>";
} }
}
if (msg == null) {
msg = "<p style='font-style:italic'>" + name + "does not have text in the index.<br/>It may have no text, not been analyzed yet, or keyword search was not enabled during ingest.</p>";
} }
String htmlMsg = "<span style='font-style:italic'>" + msg + "</span>"; String htmlMsg = "<span style='font-style:italic'>" + msg + "</span>";
return htmlMsg; return htmlMsg;

View File

@ -17,24 +17,34 @@
* limitations under the License. * limitations under the License.
*/ */
/**
* Representation of keyword query as input by user
*/
package org.sleuthkit.autopsy.keywordsearch; package org.sleuthkit.autopsy.keywordsearch;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
/**
* Representation of single keyword to search for
*/
public class Keyword { public class Keyword {
private String keywordString; // keyword to search for
private String query; private boolean isLiteral; // false if reg exp
private boolean isLiteral;
private BlackboardAttribute.ATTRIBUTE_TYPE keywordType = null; private BlackboardAttribute.ATTRIBUTE_TYPE keywordType = null;
/**
*
* @param query Keyword to search for
* @param isLiteral false if reg exp
*/
Keyword(String query, boolean isLiteral) { Keyword(String query, boolean isLiteral) {
this.query = query; this.keywordString = query;
this.isLiteral = isLiteral; this.isLiteral = isLiteral;
} }
/**
*
* @param query Keyword to search for
* @param isLiteral false if reg exp
* @param keywordType
*/
Keyword(String query, boolean isLiteral, BlackboardAttribute.ATTRIBUTE_TYPE keywordType) { Keyword(String query, boolean isLiteral, BlackboardAttribute.ATTRIBUTE_TYPE keywordType) {
this(query, isLiteral); this(query, isLiteral);
this.keywordType = keywordType; this.keywordType = keywordType;
@ -48,8 +58,12 @@ public class Keyword {
return this.keywordType; return this.keywordType;
} }
/**
*
* @return Keyword to search for
*/
String getQuery() { String getQuery() {
return query; return keywordString;
} }
boolean isLiteral() { boolean isLiteral() {
@ -58,7 +72,7 @@ public class Keyword {
@Override @Override
public String toString() { public String toString() {
return "Keyword{" + "query=" + query + ", isLiteral=" + isLiteral + ", keywordType=" + keywordType + '}'; return "Keyword{" + "query=" + keywordString + ", isLiteral=" + isLiteral + ", keywordType=" + keywordType + '}';
} }
@ -72,7 +86,7 @@ public class Keyword {
return false; return false;
} }
final Keyword other = (Keyword) obj; final Keyword other = (Keyword) obj;
if ((this.query == null) ? (other.query != null) : !this.query.equals(other.query)) { if ((this.keywordString == null) ? (other.keywordString != null) : !this.keywordString.equals(other.keywordString)) {
return false; return false;
} }
if (this.isLiteral != other.isLiteral) { if (this.isLiteral != other.isLiteral) {
@ -84,7 +98,7 @@ public class Keyword {
@Override @Override
public int hashCode() { public int hashCode() {
int hash = 7; int hash = 7;
hash = 17 * hash + (this.query != null ? this.query.hashCode() : 0); hash = 17 * hash + (this.keywordString != null ? this.keywordString.hashCode() : 0);
hash = 17 * hash + (this.isLiteral ? 1 : 0); hash = 17 * hash + (this.isLiteral ? 1 : 0);
return hash; return hash;
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011 Basis Technology Corp. * Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -28,9 +28,9 @@ import org.openide.nodes.PropertySupport;
import org.openide.nodes.Sheet; import org.openide.nodes.Sheet;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.openide.util.lookup.ProxyLookup; import org.openide.util.lookup.ProxyLookup;
import org.sleuthkit.autopsy.directorytree.TagAction;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
@ -128,8 +128,6 @@ class KeywordSearchFilterNode extends FilterNode {
Content content = this.getOriginal().getLookup().lookup(Content.class); Content content = this.getOriginal().getLookup().lookup(Content.class);
actions.addAll(content.accept(new GetPopupActionsContentVisitor())); actions.addAll(content.accept(new GetPopupActionsContentVisitor()));
//actions.add(new IndexContentFilesAction(nodeContent, "Index"));
return actions.toArray(new Action[actions.size()]); return actions.toArray(new Action[actions.size()]);
} }
@ -137,33 +135,29 @@ class KeywordSearchFilterNode extends FilterNode {
@Override @Override
public List<Action> visit(File f) { public List<Action> visit(File f) {
List<Action> actions = new ArrayList<Action>(); return getFileActions();
actions.add(new NewWindowViewAction("View in New Window", KeywordSearchFilterNode.this));
actions.add(new ExternalViewerAction("Open in External Viewer", getOriginal()));
actions.add(null);
actions.add(new ExtractAction("Extract File", getOriginal()));
actions.add(new HashSearchAction("Search for files with the same MD5 hash", getOriginal()));
actions.add(null); // creates a menu separator
actions.add(new TagAction(getOriginal()));
return actions;
} }
@Override @Override
public List<Action> visit(DerivedFile f) { public List<Action> visit(DerivedFile f) {
List<Action> actions = new ArrayList<Action>(); return getFileActions();
}
private List<Action> getFileActions() {
List<Action> actions = new ArrayList<>();
actions.add(new NewWindowViewAction("View in New Window", KeywordSearchFilterNode.this)); actions.add(new NewWindowViewAction("View in New Window", KeywordSearchFilterNode.this));
actions.add(new ExternalViewerAction("Open in External Viewer", getOriginal())); actions.add(new ExternalViewerAction("Open in External Viewer", getOriginal()));
actions.add(null); actions.add(null);
actions.add(new ExtractAction("Extract File", getOriginal())); actions.add(ExtractAction.getInstance());
actions.add(new HashSearchAction("Search for files with the same MD5 hash", getOriginal())); actions.add(new HashSearchAction("Search for files with the same MD5 hash", getOriginal()));
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(new TagAction(getOriginal())); actions.add(TagAbstractFileAction.getInstance());
return actions; return actions;
} }
@Override @Override
protected List<Action> defaultVisit(Content c) { protected List<Action> defaultVisit(Content c) {
return new ArrayList<Action>(); return new ArrayList<>();
} }
} }
} }

View File

@ -43,7 +43,7 @@ import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent; import org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent;
/** /**
* Viewer panel widget for keyword lists * Viewer panel widget for keyword lists that is used in the ingest config and options area.
*/ */
class KeywordSearchListsViewerPanel extends AbstractKeywordSearchPerformer { class KeywordSearchListsViewerPanel extends AbstractKeywordSearchPerformer {

View File

@ -22,16 +22,46 @@ import java.util.List;
/** /**
* common methods for the KeywordSearch performers * KeywordSearchPerformers are perform different searches from
* * different interfaces and places in the application. Its
* results are then passed to a KeywordSearchQuery implementation
* to perform the actual search.
*/ */
interface KeywordSearchPerformerInterface { interface KeywordSearchPerformerInterface {
/**
* Does this interface support multi-word queries?
* @return
*/
boolean isMultiwordQuery(); boolean isMultiwordQuery();
boolean isLuceneQuerySelected();
String getQueryText();
List<Keyword> getQueryList();
void setFilesIndexed(int filesIndexed);
void search();
/**
* True if the user did not choose to do a regular expression search
* @return
*/
boolean isLuceneQuerySelected();
/**
* Returns the query/keyword string that the user entered/selected
* @return Keyword to search
*/
String getQueryText();
/**
* Returns the list of Keyword objects that the user entered/selected
* @return
*/
List<Keyword> getQueryList();
/**
* Set the number of files that have been indexed
* @param filesIndexed
*/
void setFilesIndexed(int filesIndexed);
/**
* Performs the search using the selected keywords.
* Creates a DataResultTopComponent with the results.
*/
void search();
} }

View File

@ -24,6 +24,11 @@ import java.util.Map;
import org.apache.solr.client.solrj.response.TermsResponse.Term; import org.apache.solr.client.solrj.response.TermsResponse.Term;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
/**
* Interface for a search query. Implemented by various
* engines or methods of using the same engine. One of these
* is created for each query.
*/
public interface KeywordSearchQuery { public interface KeywordSearchQuery {
/** /**
@ -51,7 +56,7 @@ public interface KeywordSearchQuery {
public void addFilter(KeywordQueryFilter filter); public void addFilter(KeywordQueryFilter filter);
/** /**
* Set an optional field to narrow down the search * Set an optional SOLR field to narrow down the search
* @param field field to set on the query * @param field field to set on the query
*/ */
public void setField(String field); public void setField(String field);
@ -75,13 +80,13 @@ public interface KeywordSearchQuery {
public boolean isLiteral(); public boolean isLiteral();
/** /**
* return original query string * return original keyword/query string
* @return the query String supplied originally * @return the query String supplied originally
*/ */
public String getQueryString(); public String getQueryString();
/** /**
* return escaped query string if escaping was done * return escaped keyword/query string if escaping was done
* @return the escaped query string, or original string if no escaping done * @return the escaped query string, or original string if no escaping done
*/ */
public String getEscapedQueryString(); public String getEscapedQueryString();

View File

@ -34,73 +34,99 @@ import org.sleuthkit.autopsy.datamodel.KeyValue;
import org.sleuthkit.autopsy.keywordsearch.KeywordSearch.QueryType; import org.sleuthkit.autopsy.keywordsearch.KeywordSearch.QueryType;
/** /**
* Query manager responsible for running appropriate queries and displaying * Responsible for running a keyword search query and displaying
* results for single, multi keyword queries, with detailed or collapsed results * the results.
*/ */
public class KeywordSearchQueryManager { public class KeywordSearchQueryManager {
// how to display the results
public enum Presentation { public enum Presentation {
COLLAPSE, DETAIL COLLAPSE, DETAIL
}; };
private List<Keyword> queries;
private List<Keyword> keywords;
private Presentation presentation; private Presentation presentation;
private List<KeywordSearchQuery> queryDelegates; private List<KeywordSearchQuery> queryDelegates;
private QueryType queryType; private QueryType queryType;
private static int resultWindowCount = 0; //keep track of unique window ids to display private static int resultWindowCount = 0; //keep track of unique window ids to display
private static Logger logger = Logger.getLogger(KeywordSearchQueryManager.class.getName()); private static Logger logger = Logger.getLogger(KeywordSearchQueryManager.class.getName());
/**
*
* @param queries Keywords to search for
* @param presentation Presentation layout
*/
public KeywordSearchQueryManager(List<Keyword> queries, Presentation presentation) { public KeywordSearchQueryManager(List<Keyword> queries, Presentation presentation) {
this.queries = queries; this.keywords = queries;
this.presentation = presentation; this.presentation = presentation;
queryType = QueryType.REGEX; queryType = QueryType.REGEX;
init(); init();
} }
/**
*
* @param query Keyword to search for
* @param qt Query type
* @param presentation Presentation Layout
*/
public KeywordSearchQueryManager(String query, QueryType qt, Presentation presentation) { public KeywordSearchQueryManager(String query, QueryType qt, Presentation presentation) {
queries = new ArrayList<Keyword>(); keywords = new ArrayList<Keyword>();
queries.add(new Keyword(query, qt == QueryType.REGEX ? false : true)); keywords.add(new Keyword(query, qt == QueryType.REGEX ? false : true));
this.presentation = presentation; this.presentation = presentation;
queryType = qt; queryType = qt;
init(); init();
} }
/**
*
* @param query Keyword to search for
* @param isLiteral false if reg-exp
* @param presentation Presentation layout
*/
public KeywordSearchQueryManager(String query, boolean isLiteral, Presentation presentation) { public KeywordSearchQueryManager(String query, boolean isLiteral, Presentation presentation) {
queries = new ArrayList<Keyword>(); keywords = new ArrayList<Keyword>();
queries.add(new Keyword(query, isLiteral)); keywords.add(new Keyword(query, isLiteral));
this.presentation = presentation; this.presentation = presentation;
queryType = isLiteral ? QueryType.WORD : QueryType.REGEX; queryType = isLiteral ? QueryType.WORD : QueryType.REGEX;
init(); init();
} }
/**
* Initialize internal settings based on constructor arguments.
* Create a list of queries to later run
*/
private void init() { private void init() {
queryDelegates = new ArrayList<KeywordSearchQuery>(); queryDelegates = new ArrayList<KeywordSearchQuery>();
for (Keyword query : queries) { for (Keyword keyword : keywords) {
KeywordSearchQuery del = null; KeywordSearchQuery query = null;
switch (queryType) { switch (queryType) {
case WORD: case WORD:
del = new LuceneQuery(query); query = new LuceneQuery(keyword);
break; break;
case REGEX: case REGEX:
if (query.isLiteral()) { if (keyword.isLiteral()) {
del = new LuceneQuery(query); query = new LuceneQuery(keyword);
} else { } else {
del = new TermComponentQuery(query); query = new TermComponentQuery(keyword);
} }
break; break;
default: default:
; ;
} }
if (query.isLiteral()) { if (query != null) {
del.escape(); if (keyword.isLiteral()) {
query.escape();
}
queryDelegates.add(query);
} }
queryDelegates.add(del);
} }
//escape();
} }
/**
* Execute the keyword search based on keywords passed into constructor.
* Post results into a new DataResultViewer.
*/
public void execute() { public void execute() {
//execute and present the query //execute and present the query
//delegate query to query objects and presentation child factories //delegate query to query objects and presentation child factories
@ -109,10 +135,11 @@ public class KeywordSearchQueryManager {
// q.execute(); // q.execute();
// } // }
// } else { // } else {
//Collapsed view //Collapsed view
Collection<KeyValueQuery> things = new ArrayList<KeyValueQuery>(); Collection<KeyValueQuery> things = new ArrayList<KeyValueQuery>();
int queryID = 0; int queryID = 0;
StringBuilder queryConcat = new StringBuilder(); StringBuilder queryConcat = new StringBuilder(); // concatenation of all query strings
for (KeywordSearchQuery q : queryDelegates) { for (KeywordSearchQuery q : queryDelegates) {
Map<String, Object> kvs = new LinkedHashMap<String, Object>(); Map<String, Object> kvs = new LinkedHashMap<String, Object>();
final String queryStr = q.getQueryString(); final String queryStr = q.getQueryString();
@ -129,7 +156,7 @@ public class KeywordSearchQueryManager {
DataResultTopComponent searchResultWin = DataResultTopComponent.createInstance(windowTitle); DataResultTopComponent searchResultWin = DataResultTopComponent.createInstance(windowTitle);
if (things.size() > 0) { if (things.size() > 0) {
Children childThingNodes = Children childThingNodes =
Children.create(new KeywordSearchResultFactory(queries, things, Presentation.COLLAPSE, searchResultWin), true); Children.create(new KeywordSearchResultFactory(keywords, things, Presentation.COLLAPSE, searchResultWin), true);
rootNode = new AbstractNode(childThingNodes); rootNode = new AbstractNode(childThingNodes);
} else { } else {
@ -144,6 +171,10 @@ public class KeywordSearchQueryManager {
// } // }
} }
/**
* validate the queries before they are run
* @return false if any are invalid
*/
public boolean validate() { public boolean validate() {
boolean allValid = true; boolean allValid = true;
for (KeywordSearchQuery tcq : queryDelegates) { for (KeywordSearchQuery tcq : queryDelegates) {

View File

@ -42,11 +42,15 @@ import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskException; import org.sleuthkit.datamodel.TskException;
/**
* Performs a normal string (i.e. non-regexp) query to SOLR/Lucene.
* By default, matches in all fields.
*/
public class LuceneQuery implements KeywordSearchQuery { public class LuceneQuery implements KeywordSearchQuery {
private static final Logger logger = Logger.getLogger(LuceneQuery.class.getName()); private static final Logger logger = Logger.getLogger(LuceneQuery.class.getName());
private String query; //original unescaped query private String keywordString; //original unescaped query
private String queryEscaped; private String keywordStringEscaped;
private boolean isEscaped; private boolean isEscaped;
private Keyword keywordQuery = null; private Keyword keywordQuery = null;
private final List <KeywordQueryFilter> filters = new ArrayList<KeywordQueryFilter>(); private final List <KeywordQueryFilter> filters = new ArrayList<KeywordQueryFilter>();
@ -61,14 +65,22 @@ public class LuceneQuery implements KeywordSearchQuery {
private static final boolean DEBUG = (Version.getBuildType() == Version.Type.DEVELOPMENT); private static final boolean DEBUG = (Version.getBuildType() == Version.Type.DEVELOPMENT);
/**
* Constructor with query to process.
* @param keywordQuery
*/
public LuceneQuery(Keyword keywordQuery) { public LuceneQuery(Keyword keywordQuery) {
this(keywordQuery.getQuery()); this(keywordQuery.getQuery());
this.keywordQuery = keywordQuery; this.keywordQuery = keywordQuery;
} }
/**
* Constructor with keyword string to process
* @param queryStr Keyword to search for
*/
public LuceneQuery(String queryStr) { public LuceneQuery(String queryStr) {
this.query = queryStr; this.keywordString = queryStr;
this.queryEscaped = queryStr; this.keywordStringEscaped = queryStr;
isEscaped = false; isEscaped = false;
} }
@ -84,7 +96,7 @@ public class LuceneQuery implements KeywordSearchQuery {
@Override @Override
public void escape() { public void escape() {
queryEscaped = KeywordSearchUtil.escapeLuceneQuery(query); keywordStringEscaped = KeywordSearchUtil.escapeLuceneQuery(keywordString);
isEscaped = true; isEscaped = true;
} }
@ -100,12 +112,12 @@ public class LuceneQuery implements KeywordSearchQuery {
@Override @Override
public String getEscapedQueryString() { public String getEscapedQueryString() {
return this.queryEscaped; return this.keywordStringEscaped;
} }
@Override @Override
public String getQueryString() { public String getQueryString() {
return this.query; return this.keywordString;
} }
@Override @Override
@ -117,7 +129,7 @@ public class LuceneQuery implements KeywordSearchQuery {
public Map<String, List<ContentHit>> performQuery() throws NoOpenCoreException { public Map<String, List<ContentHit>> performQuery() throws NoOpenCoreException {
Map<String, List<ContentHit>> results = new HashMap<String, List<ContentHit>>(); Map<String, List<ContentHit>> results = new HashMap<String, List<ContentHit>>();
//in case of single term literal query there is only 1 term //in case of single term literal query there is only 1 term
results.put(query, performLuceneQuery()); results.put(keywordString, performLuceneQuery());
return results; return results;
} }
@ -125,7 +137,7 @@ public class LuceneQuery implements KeywordSearchQuery {
@Override @Override
public boolean validate() { public boolean validate() {
return query != null && !query.equals(""); return keywordString != null && !keywordString.equals("");
} }
@Override @Override
@ -192,7 +204,7 @@ public class LuceneQuery implements KeywordSearchQuery {
q.setShowDebugInfo(DEBUG); //debug q.setShowDebugInfo(DEBUG); //debug
//set query, force quotes/grouping around all literal queries //set query, force quotes/grouping around all literal queries
final String groupedQuery = KeywordSearchUtil.quoteQuery(queryEscaped); final String groupedQuery = KeywordSearchUtil.quoteQuery(keywordStringEscaped);
String theQueryStr = groupedQuery; String theQueryStr = groupedQuery;
if (field != null) { if (field != null) {
//use the optional field //use the optional field
@ -262,10 +274,10 @@ public class LuceneQuery implements KeywordSearchQuery {
} catch (NoOpenCoreException ex) { } catch (NoOpenCoreException ex) {
logger.log(Level.WARNING, "Error executing Lucene Solr Query: " + query, ex); logger.log(Level.WARNING, "Error executing Lucene Solr Query: " + keywordString, ex);
throw ex; throw ex;
} catch (KeywordSearchModuleException ex) { } catch (KeywordSearchModuleException ex) {
logger.log(Level.WARNING, "Error executing Lucene Solr Query: " + query, ex); logger.log(Level.WARNING, "Error executing Lucene Solr Query: " + keywordString, ex);
} }
} }

View File

@ -67,8 +67,8 @@ import org.apache.solr.client.solrj.impl.XMLResponseParser;
*/ */
public class Server { public class Server {
// field names that are used in SOLR schema
public static enum Schema { public static enum Schema {
ID { ID {
@Override @Override
public String toString() { public String toString() {
@ -99,24 +99,28 @@ public class Server {
return "file_name"; return "file_name";
} }
}, },
// note that we no longer index this field
CTIME { CTIME {
@Override @Override
public String toString() { public String toString() {
return "ctime"; return "ctime";
} }
}, },
// note that we no longer index this field
ATIME { ATIME {
@Override @Override
public String toString() { public String toString() {
return "atime"; return "atime";
} }
}, },
// note that we no longer index this field
MTIME { MTIME {
@Override @Override
public String toString() { public String toString() {
return "mtime"; return "mtime";
} }
}, },
// note that we no longer index this field
CRTIME { CRTIME {
@Override @Override
public String toString() { public String toString() {
@ -151,7 +155,7 @@ public class Server {
static final int DEFAULT_SOLR_STOP_PORT = 34343; static final int DEFAULT_SOLR_STOP_PORT = 34343;
private int currentSolrServerPort = 0; private int currentSolrServerPort = 0;
private int currentSolrStopPort = 0; private int currentSolrStopPort = 0;
private static final boolean DEBUG = (Version.getBuildType() == Version.Type.DEVELOPMENT); private static final boolean DEBUG = false;//(Version.getBuildType() == Version.Type.DEVELOPMENT);
public enum CORE_EVT_STATES { public enum CORE_EVT_STATES {
@ -802,7 +806,7 @@ public class Server {
} }
/** /**
* Execute Solr query to get content text * Get the text contents of the given file as stored in SOLR.
* *
* @param content to get the text for * @param content to get the text for
* @return content text string or null on error * @return content text string or null on error
@ -816,7 +820,7 @@ public class Server {
} }
/** /**
* Execute Solr query to get content text from content chunk * Get the text contents of a single chunk for the given file as stored in SOLR.
* *
* @param content to get the text for * @param content to get the text for
* @param chunkID chunk number to query (starting at 1), or 0 if there is no * @param chunkID chunk number to query (starting at 1), or 0 if there is no
@ -962,6 +966,12 @@ public class Server {
} }
} }
/**
* get the text from the content field for the given file
* @param contentID
* @param chunkID
* @return
*/
private String getSolrContent(long contentID, int chunkID) { private String getSolrContent(long contentID, int chunkID) {
final SolrQuery q = new SolrQuery(); final SolrQuery q = new SolrQuery();
q.setQuery("*:*"); q.setQuery("*:*");

View File

@ -41,6 +41,10 @@ import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.TskException; import org.sleuthkit.datamodel.TskException;
/**
* Performs a regular expression query to the SOLR/Lucene instance.
*/
public class TermComponentQuery implements KeywordSearchQuery { public class TermComponentQuery implements KeywordSearchQuery {
private static final int TERMS_UNLIMITED = -1; private static final int TERMS_UNLIMITED = -1;

View File

@ -58,6 +58,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.DerivedFile; import org.sleuthkit.datamodel.DerivedFile;
import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.ReadContentInputStream;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
/** /**
* 7Zip ingest module Extracts supported archives, adds extracted DerivedFiles, * 7Zip ingest module Extracts supported archives, adds extracted DerivedFiles,
@ -165,6 +166,16 @@ public final class SevenZipIngestModule extends IngestModuleAbstractFile {
return ProcessResult.OK; return ProcessResult.OK;
} }
//skip unalloc
if(abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) {
return IngestModuleAbstractFile.ProcessResult.OK;
}
// skip known
if (abstractFile.getKnown().equals(TskData.FileKnown.KNOWN)) {
return IngestModuleAbstractFile.ProcessResult.OK;
}
if (abstractFile.isFile() == false || !isSupported(abstractFile)) { if (abstractFile.isFile() == false || !isSupported(abstractFile)) {
//do not process dirs and files that are not supported //do not process dirs and files that are not supported
return ProcessResult.OK; return ProcessResult.OK;

View File

@ -4,20 +4,21 @@
<property name="TSK_BUILD_TYPE">Release</property> <property name="TSK_BUILD_TYPE">Release</property>
<target name="autoAIPath" > <target name="autoAIPath" >
<property name="AI.path">C:\Program Files (x86)\Caphyon\Advanced Installer 10.2\bin\x86\AdvancedInstaller.com</property> <property name="AI.path">C:\Program Files (x86)\Caphyon\Advanced Installer 10.3\bin\x86\AdvancedInstaller.com</property>
<available file="${AI.path}" <available file="${AI.path}"
property="aiPath" property="ai-exe-path"
value="${AI.path}"/> value="${AI.path}"/>
</target> </target>
<target name="inputAIPath" unless="aiPath"> <target name="inputAIPath" unless="ai-exe-path">
<input addProperty="aiPath" <input addProperty="ai-exe-path"
message="Enter the location of AdvancedInstaller.com"/> message="Enter the location of AdvancedInstaller.com"/>
</target> </target>
<target name="run-advanced-installer" depends="autoAIPath,inputAIPath"> <target name="run-advanced-installer" depends="autoAIPath,inputAIPath">
<fail unless="aiPath" message="Could not locate Advanced Installer."/> <fail unless="ai-exe-path" message="Could not locate Advanced Installer."/>
<copy file="${basedir}/installer_${app.name}/installer_${app.name}.aip" tofile="${nbdist.dir}/installer_${app.name}.aip"/> <!-- Copy the template file to add details to -->
<copy file="${basedir}/installer_${app.name}/installer_${app.name}.aip" tofile="${nbdist.dir}/installer_${app.name}.aip" overwrite="true"/>
<scriptdef name="generateguid" language="javascript"> <scriptdef name="generateguid" language="javascript">
<attribute name="property" /> <attribute name="property" />
<![CDATA[ <![CDATA[
@ -28,87 +29,93 @@
</scriptdef> </scriptdef>
<generateguid property="guid1" /> <generateguid property="guid1" />
<property name="inst-path" value="${nbdist.dir}\${app.name}-installer"/> <property name="inst-path" value="${nbdist.dir}\${app.name}-installer"/>
<property name="proj-path" value="${nbdist.dir}\installer_${app.name}.aip"/> <property name="aip-path" value="${nbdist.dir}\installer_${app.name}.aip"/>
<!-- automatically replace version name and productcode in the .aip file --> <!-- automatically replace version name and productcode in the .aip file -->
<echo>Product Code: ${guid1}</echo> <echo>Product Code: ${guid1}</echo>
<replaceregexp file="${proj-path}" <echo>Product Version: ${app.version}</echo>
<!-- Edit the API file to update versions: manual approach allows us to use non-X.Y.Z versions -->
<replaceregexp file="${aip-path}"
match="ProductCode&quot; Value=&quot;(\d{4}+:.)\w{8}+-\w{4}+-\w{4}+-\w{4}+-\w{12}+" match="ProductCode&quot; Value=&quot;(\d{4}+:.)\w{8}+-\w{4}+-\w{4}+-\w{4}+-\w{12}+"
replace="ProductCode&quot; Value=&quot;\1${guid1}" /> replace="ProductCode&quot; Value=&quot;\1${guid1}" />
<echo>Product Version: ${app.version}</echo>
<replaceregexp file="${proj-path}" <replaceregexp file="${aip-path}"
match="ProductVersion&quot; Value=&quot;\d+\.{1}\d+\.{1}\d+" match="ProductVersion&quot; Value=&quot;\d+\.{1}\d+\.{1}\d+"
replace="ProductVersion&quot; Value=&quot;${app.version}" /> replace="ProductVersion&quot; Value=&quot;${app.version}" />
<!-- Use Advanced Installer to configure files to add -->
<echo message="Adding files to installer..."/> <echo message="Adding files to installer..."/>
<exec executable="${aiPath}"> <exec executable="${ai-exe-path}">
<arg line="/edit ${proj-path} /AddFolder APPDIR ${inst-path}\bin"/> <arg line="/edit ${aip-path} /AddFolder APPDIR ${inst-path}\bin"/>
</exec> </exec>
<exec executable="${aiPath}"> <exec executable="${ai-exe-path}">
<arg line="/edit ${proj-path} /AddFolder APPDIR ${inst-path}\etc"/> <arg line="/edit ${aip-path} /AddFolder APPDIR ${inst-path}\etc"/>
</exec> </exec>
<exec executable="${aiPath}"> <exec executable="${ai-exe-path}">
<arg line="/edit ${proj-path} /AddFolder APPDIR ${inst-path}\gstreamer"/> <arg line="/edit ${aip-path} /AddFolder APPDIR ${inst-path}\gstreamer"/>
</exec> </exec>
<exec executable="${aiPath}"> <exec executable="${ai-exe-path}">
<arg line="/edit ${proj-path} /AddFolder APPDIR ${inst-path}\harness"/> <arg line="/edit ${aip-path} /AddFolder APPDIR ${inst-path}\harness"/>
</exec> </exec>
<exec executable="${aiPath}"> <exec executable="${ai-exe-path}">
<arg line="/edit ${proj-path} /AddFolder APPDIR ${inst-path}\java"/> <arg line="/edit ${aip-path} /AddFolder APPDIR ${inst-path}\java"/>
</exec> </exec>
<exec executable="${aiPath}"> <exec executable="${ai-exe-path}">
<arg line="/edit ${proj-path} /AddFolder APPDIR ${inst-path}\jre"/> <arg line="/edit ${aip-path} /AddFolder APPDIR ${inst-path}\jre"/>
</exec> </exec>
<exec executable="${aiPath}"> <exec executable="${ai-exe-path}">
<arg line="/edit ${proj-path} /AddFolder APPDIR ${inst-path}\platform"/> <arg line="/edit ${aip-path} /AddFolder APPDIR ${inst-path}\platform"/>
</exec> </exec>
<exec executable="${aiPath}"> <exec executable="${ai-exe-path}">
<arg line="/edit ${proj-path} /AddFolder APPDIR ${inst-path}\${app.name}"/> <arg line="/edit ${aip-path} /AddFolder APPDIR ${inst-path}\${app.name}"/>
</exec> </exec>
<exec executable="${aiPath}"> <exec executable="${ai-exe-path}">
<arg line="/edit ${proj-path} /AddFile APPDIR ${inst-path}\icon.ico"/> <arg line="/edit ${aip-path} /AddFile APPDIR ${inst-path}\icon.ico"/>
</exec> </exec>
<exec executable="${aiPath}"> <exec executable="${ai-exe-path}">
<arg line="/edit ${proj-path} /AddFile APPDIR ${inst-path}\KNOWN_ISSUES.txt"/> <arg line="/edit ${aip-path} /AddFile APPDIR ${inst-path}\KNOWN_ISSUES.txt"/>
</exec> </exec>
<exec executable="${aiPath}"> <exec executable="${ai-exe-path}">
<arg line="/edit ${proj-path} /AddFile APPDIR ${inst-path}\LICENSE-2.0.txt"/> <arg line="/edit ${aip-path} /AddFile APPDIR ${inst-path}\LICENSE-2.0.txt"/>
</exec> </exec>
<exec executable="${aiPath}"> <exec executable="${ai-exe-path}">
<arg line="/edit ${proj-path} /AddFile APPDIR ${inst-path}\NEWS.txt"/> <arg line="/edit ${aip-path} /AddFile APPDIR ${inst-path}\NEWS.txt"/>
</exec> </exec>
<exec executable="${aiPath}"> <exec executable="${ai-exe-path}">
<arg line="/edit ${proj-path} /AddFile APPDIR ${inst-path}\README.txt"/> <arg line="/edit ${aip-path} /AddFile APPDIR ${inst-path}\README.txt"/>
</exec> </exec>
<!-- Need to find a way to deal with beta version --> <!-- Need to find a way to deal with beta version -->
<!--<echo message="Setting ${app.name} version to ${app.version}..."/> <!--<echo message="Setting ${app.name} version to ${app.version}..."/>
<exec executable="${aiPath}"> <exec executable="${ai-exe-path}">
<arg line="/edit ${proj-path} /SetVersion ${app.version}"/> <arg line="/edit ${aip-path} /SetVersion ${app.version}"/>
</exec>--> </exec>-->
<echo message="Adding desktop/menu shortcuts..."/> <echo message="Adding desktop/menu shortcuts..."/>
<exec executable="${aiPath}"> <exec executable="${ai-exe-path}">
<arg line="/edit ${proj-path} /NewShortcut -name ${app.title} -dir DesktopFolder -target APPDIR\bin\${app.name}.exe -icon ${inst-path}\icon.ico"/> <arg line="/edit ${aip-path} /NewShortcut -name ${app.title} -dir DesktopFolder -target APPDIR\bin\${app.name}.exe -icon ${inst-path}\icon.ico"/>
</exec> </exec>
<exec executable="${aiPath}"> <exec executable="${ai-exe-path}">
<arg line="/edit ${proj-path} /NewShortcut -name ${app.title} -dir SHORTCUTDIR -target APPDIR\bin\${app.name}.exe -icon ${inst-path}\icon.ico"/> <arg line="/edit ${aip-path} /NewShortcut -name ${app.title} -dir SHORTCUTDIR -target APPDIR\bin\${app.name}.exe -icon ${inst-path}\icon.ico"/>
</exec> </exec>
<echo message="Setting environment variables..."/> <echo message="Setting environment variables..."/>
<exec executable="${aiPath}"> <exec executable="${ai-exe-path}">
<arg line="/edit ${proj-path} /NewEnvironment -name GSTREAMER_PATH -value [APPDIR]gstreamer\bin -install_operation CreateUpdate -behavior Append -system_variable"/> <arg line="/edit ${aip-path} /NewEnvironment -name GSTREAMER_PATH -value [APPDIR]gstreamer\bin -install_operation CreateUpdate -behavior Append -system_variable"/>
</exec> </exec>
<exec executable="${aiPath}"> <exec executable="${ai-exe-path}">
<arg line="/edit ${proj-path} /NewEnvironment -name GSTREAMER_PATH -value [APPDIR]gstreamer\lib\gstreamer-0.10 -install_operation CreateUpdate -behavior Append -system_variable"/> <arg line="/edit ${aip-path} /NewEnvironment -name GSTREAMER_PATH -value [APPDIR]gstreamer\lib\gstreamer-0.10 -install_operation CreateUpdate -behavior Append -system_variable"/>
</exec> </exec>
<exec executable="${aiPath}"> <exec executable="${ai-exe-path}">
<arg line="/edit ${proj-path} /NewEnvironment -name PATH -value %GSTREAMER_PATH% -install_operation CreateUpdate -behavior Append -system_variable"/> <arg line="/edit ${aip-path} /NewEnvironment -name PATH -value %GSTREAMER_PATH% -install_operation CreateUpdate -behavior Append -system_variable"/>
</exec> </exec>
<exec executable="${aiPath}"> <exec executable="${ai-exe-path}">
<arg line="/build ${proj-path}"/> <arg line="/build ${aip-path}"/>
</exec> </exec>
<delete file="${proj-path}"/> <!--<delete file="${aip-path}"/>-->
</target> </target>
<!-- Makes an installer from the opened ZIP file -->
<target name="build-installer-windows"> <target name="build-installer-windows">
<antcall target="run-advanced-installer" /> <antcall target="run-advanced-installer" />
<!--<delete dir="${nbdist.dir}/${app.name}-installer"/>--> <!--<delete dir="${nbdist.dir}/${app.name}-installer"/>-->

View File

@ -4,8 +4,6 @@
any type of module. Information about specific types of modules should any type of module. Information about specific types of modules should
go into the page for that module type. --> go into the page for that module type. -->
<!-- @@@ Update -->
This page describes the basic concepts and setup that are needed regardless of the module type that you are building. This page describes the basic concepts and setup that are needed regardless of the module type that you are building.
\section mod_dev_setup Basic Setup \section mod_dev_setup Basic Setup
@ -66,11 +64,7 @@ You now have a NetBeans module that is using Autopsy as its build platform. Tha
There are several optional things in the Properties section. You can add a description and specify the version. You can do all of this later though and it does not need to be done before you start development. There are several optional things in the Properties section. You can add a description and specify the version. You can do all of this later though and it does not need to be done before you start development.
A link about the NetBeans versioning scheme can be found here http://wiki.netbeans.org/VersioningPolicy. A link about the NetBeans versioning scheme can be found here http://wiki.netbeans.org/VersioningPolicy.
Autopsy follows this scheme and we will make a wiki page about it. Autopsy follows this scheme and a link to the details can be found at http://wiki.sleuthkit.org/index.php?title=Autopsy_3_Module_Versions.
TODO: @@@ Add link to our wiki with Autopsy's versioning scheme
\subsection mod_dev_mod_other Other Links \subsection mod_dev_mod_other Other Links

View File

@ -48,6 +48,7 @@ blackboard and with inbox messages to the user.
\section ingest_datasrc Data Source-level Modules \section ingest_datasrc Data Source-level Modules
To make a data source-level module, make a new Java class either manually or using the NetBeans wizards. Edit the class to extend "org.sleuthkit.autopsy.ingest.IngestModuleDataSource". NetBeans will likely complain that you have not implemented the necessary methods and you can use its "hints" to automatically generate stubs for them. Use the documentation for the org.sleuthkit.autopsy.ingest.IngestModuleDataSource class for details on what each needs to do. To make a data source-level module, make a new Java class either manually or using the NetBeans wizards. Edit the class to extend "org.sleuthkit.autopsy.ingest.IngestModuleDataSource". NetBeans will likely complain that you have not implemented the necessary methods and you can use its "hints" to automatically generate stubs for them. Use the documentation for the org.sleuthkit.autopsy.ingest.IngestModuleDataSource class for details on what each needs to do.
You can also refer to org.sleuthkit.autopsy.examples.SampleDataSourceIngestModule as an example module.
Example snippet of an ingest-level module process() method: Example snippet of an ingest-level module process() method:
@ -87,6 +88,7 @@ public void process(Content dataSource, IngestDataSourceWorkerController control
\section ingest_file File-level Modules \section ingest_file File-level Modules
To make a File-level module, make a new Java class either manually or using the NetBeans wizards. Edit the class to extend "org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile". NetBeans will likely complain that you have not implemented the necessary methods and you can use its "hints" to automatically generate stubs for them. Use the method documentation in the org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile class to fill in the details. To make a File-level module, make a new Java class either manually or using the NetBeans wizards. Edit the class to extend "org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile". NetBeans will likely complain that you have not implemented the necessary methods and you can use its "hints" to automatically generate stubs for them. Use the method documentation in the org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile class to fill in the details.
You can also refer to org.sleuthkit.autopsy.examples.SampleFileIngestModule as an example module.
Unlike Data Source-level modules, file-level modules are singletons. Only a single instance is created for all files. Unlike Data Source-level modules, file-level modules are singletons. Only a single instance is created for all files.
The same file-level module instance will be used for files in different images and even different cases if new cases are opened. The same file-level module instance will be used for files in different images and even different cases if new cases are opened.

View File

@ -1,31 +1,51 @@
/*! \page mod_result_page Developing Result Viewer Modules /*! \page mod_result_page Developing Result Viewer Modules
NOTE: This has been moved from a package-level description and needs cleanup and updating. \section result_overview Overview
DataResultViewer modules exist in the upper-right area of the default Autopsy interface, as shown below.
<h3>Creating a DataResultViewer</h3> \image html viewer_image.jpg "Module Viewer Areas"
<p>DataResultTopComponent is the high-level window in the DataResult area. The DataResult area is in the upper right of Autopsy and shows a set of nodes (i.e. in table form or thumbnail, by default). You will want to create a new module in this area if you have a new way to display a set of files or nodes. For example, in a graph form or different layout beyond the simple table.
<ol> They display a set of files that are passed into the viewer from the tree on the left, keyword searching, or other searches. The main idea is that the same set of files can be viewed in table form, thumbnail form, or any other form that you can think of. Once a file is selected from the DataResult area, it is passed to the DataContent area for display.
<li>Create a module from within NetBeans. It must be dependent on these modules:
<ul>
<li>Case
<li>CoreComponentInterfaces
<li>CoreComponents
<li>DataModel
<li>DialogsAPI (if pop-ups and such are going to be used)
<li>Explorer & Property Sheet API
<li>Lookup
<li>Nodes API
<li>Setting API
<li>UI Utilities API
<li>Utilities API
<li>Window System API
</ul>
<li>Make a class that extends org.sleuthkit.autopsy.corecomponents.AbstractDataResultViewer and is registered as a service provider for the org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer class by specifying "@ServiceProvider(service = DataResultViewer.class)" or by using layer.xml. This class will extend JPanel. </li> \section result_dataflow Data Flow
This section provides some basics on DataResult viewers. DataResult viewers are created as needed. The directory tree on the left creates one when it loads and uses it for the life of the application. The keyword search module creates on each time it performs a keyword search. Data is explicitly passed into it.
<li>See the previous sections on default actions. (note that this refers to the CoreComponentINterfaces package-level description).</li> By default, when a node is selected, it is then passed to the default DataContent viewer (this is done in org.sleuthkit.autopsy.corecomponents.AbstractDataResultViewer). There can be many data content viewers, but only one default one exists.
</ol> The org.sleuthkit.autopsy.corecomponents.DataResultViewerTopComponent class is the NetBeans TopComponent that encapsulates the various DataResult viewer modules. It creates tabs for each DataResult viewer module.
\section result_nb NetBeans Module Configuration
The rest of the document assumes that you have already created your NetBeans module, as outlined in \ref mod_dev_module.
DataResultViewer modules will have additional NetBeans dependencies. Right click on the module, choose "Properties" -> "Libraries" -> "Module Dependencies". Add "Lookup API" and "Nodes API".
\section result_mod Module Development
You will need a class that extends org.sleuthkit.autopsy.corecomponents.AbstractDataResultViewer. You can use NetBeans to make a class, manually extend it, and then let NetBeans complain about missing methods. It will provide default implementations for them if you click on the error messages in the UI.
Refer to the documentation in org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer on what each method should do. Note that AbstractDataResultViewer extends JPanel.
Autopsy will find your module using the NetBeans Lookup infrastructure. To be found, you will need to register as a service provider for DataResultViewer.class by annotating your class as follows:
\code
@ServiceProvider(service = DataResultViewer.class)
public class DataResultViewerTable extends AbstractDataResultViewer {
\endcode
If you get errors about not knowing about ServiceProviders and such, ensure that you configured your NetBeans module to depend on the Nodes and Lookup APIs as outlined in the previous section.
The current modules in this viewer area heavily use the NetBeans ExplorerManger and Node concepts. You do not need to use ExplorerManager concepts, but you will need to use Node concepts to identify the set of nodes to display and to extract the datamodel objects from each Node object. Refer to \ref content_hints_objects for hints on getting the datamodel objects from the Node.
\section result_examples Example Modules
You can refer to the org.sleuthkit.autopsy.corecomponents.DataResultViewerTable and org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail modules to follow as examples.
\section result_hint Hints
Note that we have made the least number of these types of modules, so some work could be done to make the framework and infrastuture for them better.
These modules are currently the most challenging to develop because they require the most NetBeans knowledge about Nodes and ExplorerManagers. Make sure you read some of the tutorials (or books) first:
- NetBeans Nodes API Tutorial (https://platform.netbeans.org/tutorials/nbm-nodesapi2.html)
- NetBeans Nodes, Explorer Manager, and Component Palette Tutorial (https://platform.netbeans.org/tutorials/nbm-nodesapi3.html)
We have plans to change the design a bit in the future so that an ExplorerManager is created for each DataResultViewerTopComponent instance and each individual module does not need to make one. Instead, one will be given to it.
*/ */

View File

@ -52,6 +52,7 @@ services are provided:
- FileManager: the org.sleuthkit.autopsy.casemodule.services.FileManager service provides an API to access any file in the case. You can access FileManager by calling org.sleuthkit.autopsy.casemodule.services.Services.getFileManager(). Data Source-level Ingest modules and Report modules typically use this service because the other modules are passed in a reference to a specific file to do something with. - FileManager: the org.sleuthkit.autopsy.casemodule.services.FileManager service provides an API to access any file in the case. You can access FileManager by calling org.sleuthkit.autopsy.casemodule.services.Services.getFileManager(). Data Source-level Ingest modules and Report modules typically use this service because the other modules are passed in a reference to a specific file to do something with.
- org.sleuthkit.autopsy.coreutils.Logger - for adding log messages to central logger - org.sleuthkit.autopsy.coreutils.Logger - for adding log messages to central logger
- IngestModules also have a class that provides additional services. See \ref ingestmodule_services. - IngestModules also have a class that provides additional services. See \ref ingestmodule_services.
- MessageNotifyUtil.Notify.show() can be used to send messages to the user in the lower right-hand area.
\subsection mod_dev_other_utilities Framework Utilities \subsection mod_dev_other_utilities Framework Utilities

View File

@ -820,18 +820,16 @@ def usage():
return \ return \
""" """
USAGE: USAGE:
Run this script to generate a jdiff XML summary for every module Compares the API of the current Autopsy source code with a previous
in the current Autopsy source and in a previous source specified tagged version. By default, it will detect the previous tag from
by the given tag. Then, compare the XML files to see which modules the NEWS file and will not update the versions in the source code.
need updated version numbers. If the dry run tag is not given, the
module numbers will be automatically updated.
OPTIONAL FLAGS: OPTIONAL FLAGS:
-t --tag The tag name in git. Otherwise the NEWS file in source -t --tag Specify a previous tag to compare to.
will be used to determine the previous tag. Otherwise the NEWS file will be used.
-d --dir The output directory for the jdiff JavaDocs. If no -d --dir The output directory for the jdiff JavaDocs. If no
directory is given, the default is /javadocs/{module}. directory is given, the default is jdiff-javadocs/{module}.
-s --source The directory containing Autopsy's source code. -s --source The directory containing Autopsy's source code.
@ -904,6 +902,7 @@ def main():
printt("Comparing jdiff outputs...") printt("Comparing jdiff outputs...")
for module in similar_modules: for module in similar_modules:
module.set_ret(compare_xml(module, apiname_tag, apiname_cur)) module.set_ret(compare_xml(module, apiname_tag, apiname_cur))
print("Refer to the jdiff-javadocs folder for more details")
# ------------------------------------------------------------ # ------------------------------------------------------------
# 1) Do versioning # 1) Do versioning