mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
Conflicts: (due to line ending problems) Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java build-windows.xml build.xml
This commit is contained in:
commit
65bb4a05ed
@ -1,4 +1,5 @@
|
||||
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.
|
||||
- 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
|
@ -109,7 +109,7 @@ public final class AddImageAction extends CallableSystemAction implements Presen
|
||||
Logger.noteAction(AddImageAction.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>";
|
||||
if (JOptionPane.showConfirmDialog(null, msg, "Ingest in progress", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.NO_OPTION) {
|
||||
return;
|
||||
@ -128,7 +128,6 @@ public final class AddImageAction extends CallableSystemAction implements Presen
|
||||
dialog.setVisible(true);
|
||||
dialog.toFront();
|
||||
|
||||
|
||||
// Do any cleanup that needs to happen (potentially: stopping the
|
||||
//add-image process, reverting an image)
|
||||
runCleanupTasks();
|
||||
|
@ -55,7 +55,7 @@ import org.sleuthkit.datamodel.TskException;
|
||||
class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
|
||||
|
||||
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
|
||||
* component from this class, just use getComponent().
|
||||
@ -85,6 +85,8 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
|
||||
AddImageWizardPanel3(AddImageAction action, AddImageWizardPanel2 wizPanel) {
|
||||
this.action = action;
|
||||
this.wizPanel = wizPanel;
|
||||
ingestConfig = Lookup.getDefault().lookup(IngestConfigurator.class);
|
||||
ingestConfig.setContext(AddImageWizardPanel3.class.getCanonicalName());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -326,7 +326,7 @@ public class Case implements SleuthkitCase.ErrorObserver {
|
||||
* @param imgId the ID of the image that being 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});
|
||||
|
||||
try {
|
||||
@ -372,7 +372,7 @@ public class Case implements SleuthkitCase.ErrorObserver {
|
||||
/**
|
||||
* Closes this case. This methods close the xml and clear all the fields.
|
||||
*/
|
||||
void closeCase() throws CaseActionException {
|
||||
public void closeCase() throws CaseActionException {
|
||||
changeCase(null);
|
||||
|
||||
try {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2011-2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -60,4 +60,10 @@ public interface IngestConfigurator {
|
||||
*/
|
||||
boolean isIngestRunning();
|
||||
|
||||
/**
|
||||
* Set the context for the configuration.
|
||||
* @param context
|
||||
*/
|
||||
public void setContext(String context);
|
||||
|
||||
}
|
||||
|
@ -77,9 +77,11 @@ public class FileManager implements Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dataSource data source Content (Image, parent-less
|
||||
* VirtualDirectory) where to find files
|
||||
* @param fileName the name of the file or directory to match
|
||||
* Finds a set of files that meets the name criteria.
|
||||
* @param dataSource Root data source to limit search results to (Image,
|
||||
* 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
|
||||
* the given fileName
|
||||
*/
|
||||
@ -90,11 +92,15 @@ public class FileManager implements Closeable {
|
||||
return tskCase.findFiles(dataSource, fileName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param dataSource data source Content (Image, parent-less
|
||||
* VirtualDirectory) where to find files
|
||||
* @param fileName the name of the file or directory to match
|
||||
* @param dirName the name of a parent directory of fileName
|
||||
* Finds a set of files that meets the name criteria.
|
||||
* @param dataSource Root data source to limit search results to (Image,
|
||||
* VirtualDirectory, etc.).
|
||||
* @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
|
||||
* fileName and whose parent directory contains dirName.
|
||||
*/
|
||||
@ -106,10 +112,12 @@ public class FileManager implements Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dataSource data source Content (Image, parent-less
|
||||
* VirtualDirectory) where to find files
|
||||
* @param fileName the name of the file or directory to match
|
||||
* @param parentFile parent file/dir of the file to find
|
||||
* Finds a set of files that meets the name criteria.
|
||||
* @param dataSource Root data source to limit search results to (Image,
|
||||
* VirtualDirectory, etc.).
|
||||
* @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
|
||||
* fileName and that were inside a directory described by parentFsContent.
|
||||
*/
|
||||
|
@ -27,7 +27,6 @@ import org.openide.nodes.Node;
|
||||
* Interface for the different viewers that show a set of nodes in the DataResult area.
|
||||
* AbstractDataResultViewer has default implementations for the action handlers.
|
||||
*
|
||||
* @author jantonius
|
||||
*/
|
||||
public interface DataResultViewer {
|
||||
/**
|
||||
@ -47,7 +46,7 @@ public interface DataResultViewer {
|
||||
public DataResultViewer createInstance();
|
||||
|
||||
/**
|
||||
* Get Component to display this DataResultViewer
|
||||
* Get the Swing component (i.e. JPanel) for this viewer
|
||||
*/
|
||||
public Component getComponent();
|
||||
|
||||
@ -74,7 +73,7 @@ public interface DataResultViewer {
|
||||
public void setSelectedNodes(Node[] selected);
|
||||
|
||||
/**
|
||||
* Checks whether the currently selected node
|
||||
* Checks whether the currently selected root node
|
||||
* is supported by this viewer
|
||||
* @param selectedNode the selected node
|
||||
* @return True if supported, else false
|
||||
|
@ -36,7 +36,8 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
|
||||
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
|
||||
DataResultViewer, Provider {
|
||||
@ -81,21 +82,17 @@ public abstract class AbstractDataResultViewer extends JPanel implements
|
||||
// change the cursor to "waiting cursor" for this operation
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
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
|
||||
Node newSelectedNode = selectedNode; // get the selected Node on the table
|
||||
// push the node to default "DataContent"
|
||||
//TODO only the active viewer should be calling setNode
|
||||
//not all of them, otherwise it results in multiple setNode() invocations
|
||||
//alternative is to use a single instance of the event listener
|
||||
//, per top component and not the tab perhaps
|
||||
contentViewer.setNode(newSelectedNode);
|
||||
contentViewer.setNode(selectedNodes[0]);
|
||||
} else {
|
||||
// clear the node viewer
|
||||
contentViewer.setNode(null);
|
||||
@ -131,6 +128,7 @@ public abstract class AbstractDataResultViewer extends JPanel implements
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Node getSelectedNode() {
|
||||
Node result = null;
|
||||
Node[] selectedNodes = this.getExplorerManager().getSelectedNodes();
|
||||
|
@ -178,7 +178,7 @@ public class DataContentPanel extends javax.swing.JPanel implements DataContent,
|
||||
jTabbedPane1.setEnabledAt(i, true);
|
||||
|
||||
// remember the viewer with the highest preference value
|
||||
int currentPreferred = dcv.isPreferred(selectedNode, false);
|
||||
int currentPreferred = dcv.isPreferred(selectedNode, true);
|
||||
if (currentPreferred > maxPreferred) {
|
||||
preferredViewerIndex = i;
|
||||
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.
|
||||
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
|
||||
|
@ -231,18 +231,21 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
|
||||
@Override
|
||||
public void setNode(Node selectedNode) {
|
||||
if (selectedNode == null) {
|
||||
this.setDataView(new ArrayList<BlackboardArtifact>(), 1);
|
||||
resetComponent();
|
||||
return;
|
||||
}
|
||||
|
||||
Lookup lookup = selectedNode.getLookup();
|
||||
Content content = lookup.lookup(Content.class);
|
||||
if (content != null) {
|
||||
try {
|
||||
this.setDataView(content.getAllArtifacts(), 1);
|
||||
} catch (TskException ex) {
|
||||
logger.log(Level.WARNING, "Couldn't get artifacts: ", ex);
|
||||
}
|
||||
if (content == null) {
|
||||
resetComponent();
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
@ -279,9 +282,11 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
|
||||
this.artifacts = new ArrayList<BlackboardArtifact>();
|
||||
currentPageLabel.setText("");
|
||||
totalPageLabel.setText("");
|
||||
outputViewPane.setText("");
|
||||
prevPageButton.setEnabled(false);
|
||||
nextPageButton.setEnabled(false);
|
||||
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));
|
||||
|
||||
if(artifacts.isEmpty()){
|
||||
setComponentsVisibility(false);
|
||||
this.setCursor(null);
|
||||
outputViewPane.setText("");
|
||||
resetComponent();
|
||||
return;
|
||||
}
|
||||
this.artifacts = artifacts;
|
||||
|
@ -247,7 +247,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
|
||||
currentOffset -= pageLength;
|
||||
currentPage = currentPage - 1;
|
||||
currentPageLabel.setText(Integer.toString(currentPage));
|
||||
setDataView(dataSource, currentOffset, false);
|
||||
setDataView(dataSource, currentOffset);
|
||||
}//GEN-LAST:event_prevPageButtonActionPerformed
|
||||
|
||||
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;
|
||||
currentPage = currentPage + 1;
|
||||
currentPageLabel.setText(Integer.toString(currentPage));
|
||||
setDataView(dataSource, currentOffset, false);
|
||||
setDataView(dataSource, currentOffset);
|
||||
}//GEN-LAST:event_nextPageButtonActionPerformed
|
||||
|
||||
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;
|
||||
currentPage = pageNumber;
|
||||
currentPageLabel.setText(Integer.toString(currentPage));
|
||||
setDataView(dataSource, currentOffset, false);
|
||||
setDataView(dataSource, currentOffset);
|
||||
}//GEN-LAST:event_goToPageTextFieldActionPerformed
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JMenuItem copyMenuItem;
|
||||
@ -295,14 +295,23 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
|
||||
private javax.swing.JLabel totalPageLabel;
|
||||
// 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)
|
||||
*
|
||||
* @param dataSource the content that want to be shown
|
||||
* @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) {
|
||||
return;
|
||||
}
|
||||
@ -312,14 +321,12 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
|
||||
|
||||
this.dataSource = dataSource;
|
||||
String errorText = null;
|
||||
Boolean setVisible = false;
|
||||
|
||||
int bytesRead = 0;
|
||||
if (!reset && dataSource.getSize() > 0) {
|
||||
if (dataSource.getSize() > 0) {
|
||||
try {
|
||||
bytesRead = dataSource.read(data, offset, pageLength); // read the data
|
||||
} catch (TskException ex) {
|
||||
setVisible = true;
|
||||
errorText = "(offset " + currentOffset + "-" + (currentOffset + pageLength)
|
||||
+ " could not be read)";
|
||||
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
|
||||
if (bytesRead > 0) {
|
||||
setVisible = true;
|
||||
}
|
||||
else {
|
||||
if (bytesRead <= 0) {
|
||||
errorText = "(offset " + currentOffset + "-" + (currentOffset + pageLength)
|
||||
+ " could not be read)";
|
||||
setVisible = true;
|
||||
}
|
||||
|
||||
|
||||
// disable or enable the next button
|
||||
if (!reset && offset + pageLength < dataSource.getSize()) {
|
||||
if ((errorText != null) && (offset + pageLength < dataSource.getSize())) {
|
||||
nextPageButton.setEnabled(true);
|
||||
} else {
|
||||
nextPageButton.setEnabled(false);
|
||||
}
|
||||
|
||||
if (offset == 0) {
|
||||
if ((offset == 0) || (errorText == null)) {
|
||||
prevPageButton.setEnabled(false);
|
||||
currentPage = 1; // reset the page number
|
||||
} else {
|
||||
prevPageButton.setEnabled(true);
|
||||
}
|
||||
|
||||
if (setVisible) {
|
||||
int totalPage = Math.round((dataSource.getSize() - 1) / pageLength) + 1;
|
||||
totalPageLabel.setText(Integer.toString(totalPage));
|
||||
currentPageLabel.setText(Integer.toString(currentPage));
|
||||
setComponentsVisibility(true); // shows the components that not needed
|
||||
int totalPage = Math.round((dataSource.getSize() - 1) / pageLength) + 1;
|
||||
totalPageLabel.setText(Integer.toString(totalPage));
|
||||
currentPageLabel.setText(Integer.toString(currentPage));
|
||||
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;
|
||||
if (errorText == null) {
|
||||
outputViewPane.setText(DataConversion.byteArrayToHex(data, showLength, offset, outputViewPane.getFont()));
|
||||
}
|
||||
else {
|
||||
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.setText(DataConversion.byteArrayToHex(data, showLength, offset, outputViewPane.getFont()));
|
||||
}
|
||||
else {
|
||||
outputViewPane.setText(errorText);
|
||||
}
|
||||
|
||||
outputViewPane.moveCaretPosition(0);
|
||||
|
||||
this.setCursor(null);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNode(Node selectedNode) {
|
||||
if ((selectedNode == null) || (!isSupported(selectedNode))) {
|
||||
setDataView(null, 0, true);
|
||||
resetComponent();
|
||||
return;
|
||||
}
|
||||
|
||||
Content content = (selectedNode).getLookup().lookup(Content.class);
|
||||
if (content == null) {
|
||||
this.setDataView(null, 0, true);
|
||||
resetComponent();
|
||||
return;
|
||||
}
|
||||
|
||||
this.setDataView(content, 0, false);
|
||||
this.setDataView(content, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -420,8 +412,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
|
||||
this.dataSource = null;
|
||||
currentPageLabel.setText("");
|
||||
totalPageLabel.setText("");
|
||||
prevPageButton.setEnabled(false);
|
||||
nextPageButton.setEnabled(false);
|
||||
outputViewPane.setText("");
|
||||
setComponentsVisibility(false); // hides the components that not needed
|
||||
}
|
||||
|
||||
@ -448,8 +439,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
|
||||
return false;
|
||||
}
|
||||
Content content = node.getLookup().lookup(Content.class);
|
||||
|
||||
if (content != null && content.getSize() != 0) {
|
||||
if (content != null && content.getSize() > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -112,12 +112,13 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
|
||||
public void setNode(Node selectedNode) {
|
||||
try {
|
||||
if (selectedNode == null) {
|
||||
videoPanel.reset();
|
||||
resetComponent();
|
||||
return;
|
||||
}
|
||||
|
||||
AbstractFile file = selectedNode.getLookup().lookup(AbstractFile.class);
|
||||
if (file == null) {
|
||||
resetComponent();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -180,15 +181,13 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
|
||||
|
||||
@Override
|
||||
public void resetComponent() {
|
||||
// we don't want this to do anything
|
||||
// because we already reset on each selected node
|
||||
videoPanel.reset();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isSupported(Node node) {
|
||||
|
||||
if (node == null) {
|
||||
return false;
|
||||
}
|
||||
@ -198,13 +197,11 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (file.getSize() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String name = file.getName().toLowerCase();
|
||||
|
||||
if (imagePanelInited && containsExt(name, IMAGES)) {
|
||||
return true;
|
||||
} //for gstreamer formats, check if initialized first, then
|
||||
|
@ -265,7 +265,7 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
|
||||
currentOffset -= pageLength;
|
||||
currentPage = currentPage - 1;
|
||||
currentPageLabel.setText(Integer.toString(currentPage));
|
||||
setDataView(dataSource, currentOffset, false);
|
||||
setDataView(dataSource, currentOffset);
|
||||
}//GEN-LAST:event_prevPageButtonActionPerformed
|
||||
|
||||
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;
|
||||
currentPage = currentPage + 1;
|
||||
currentPageLabel.setText(Integer.toString(currentPage));
|
||||
setDataView(dataSource, currentOffset, false);
|
||||
setDataView(dataSource, currentOffset);
|
||||
}//GEN-LAST:event_nextPageButtonActionPerformed
|
||||
|
||||
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;
|
||||
currentPage = pageNumber;
|
||||
currentPageLabel.setText(Integer.toString(currentPage));
|
||||
setDataView(dataSource, currentOffset, false);
|
||||
setDataView(dataSource, currentOffset);
|
||||
}//GEN-LAST:event_goToPageTextFieldActionPerformed
|
||||
|
||||
private void languageComboActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_languageComboActionPerformed
|
||||
|
||||
if (dataSource != null) {
|
||||
setDataView(dataSource, currentOffset, false);
|
||||
setDataView(dataSource, currentOffset);
|
||||
}
|
||||
}//GEN-LAST:event_languageComboActionPerformed
|
||||
// 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;
|
||||
// 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)
|
||||
*
|
||||
* @param dataSource the content that want to be shown
|
||||
* @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) {
|
||||
return;
|
||||
}
|
||||
@ -342,14 +350,12 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
|
||||
int bytesRead = 0;
|
||||
// set the data on the bottom and show it
|
||||
String text = "";
|
||||
Boolean setVisible = false;
|
||||
if (!reset && dataSource.getSize() > 0) {
|
||||
if (dataSource.getSize() > 0) {
|
||||
try {
|
||||
bytesRead = dataSource.read(data, offset, pageLength); // read the data
|
||||
} catch (TskException ex) {
|
||||
text = "(offset " + currentOffset + "-" + (currentOffset + pageLength)
|
||||
+ " could not be read)";
|
||||
setVisible = true;
|
||||
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)
|
||||
+ " contains no text)";
|
||||
}
|
||||
|
||||
setVisible = true;
|
||||
} else {
|
||||
text = "(offset " + currentOffset + "-" + (currentOffset + pageLength)
|
||||
+ " could not be read)";
|
||||
setVisible = true;
|
||||
}
|
||||
|
||||
// disable or enable the next button
|
||||
if (!reset && offset + pageLength < dataSource.getSize()) {
|
||||
if (offset + pageLength < dataSource.getSize()) {
|
||||
nextPageButton.setEnabled(true);
|
||||
} else {
|
||||
nextPageButton.setEnabled(false);
|
||||
@ -386,23 +389,15 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
|
||||
prevPageButton.setEnabled(true);
|
||||
}
|
||||
|
||||
if (setVisible) {
|
||||
int totalPage = Math.round((dataSource.getSize() - 1) / pageLength) + 1;
|
||||
totalPageLabel.setText(Integer.toString(totalPage));
|
||||
currentPageLabel.setText(Integer.toString(currentPage));
|
||||
outputViewPane.setText(text); // set the output view
|
||||
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
|
||||
}
|
||||
|
||||
int totalPage = Math.round((dataSource.getSize() - 1) / pageLength) + 1;
|
||||
totalPageLabel.setText(Integer.toString(totalPage));
|
||||
currentPageLabel.setText(Integer.toString(currentPage));
|
||||
outputViewPane.setText(text); // set the output view
|
||||
setComponentsVisibility(true); // shows the components that not needed
|
||||
outputViewPane.moveCaretPosition(0);
|
||||
|
||||
this.setCursor(null);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -422,31 +417,28 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
|
||||
goToPageLabel.setVisible(isVisible);
|
||||
languageCombo.setVisible(isVisible);
|
||||
languageLabel.setVisible(isVisible);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNode(Node selectedNode) {
|
||||
if (!isSupported(selectedNode)) {
|
||||
setDataView(null, 0, true);
|
||||
if ((selectedNode == null) || (!isSupported(selectedNode))) {
|
||||
resetComponent();
|
||||
return;
|
||||
}
|
||||
if (selectedNode != null) {
|
||||
Lookup lookup = selectedNode.getLookup();
|
||||
Content content = lookup.lookup(Content.class);
|
||||
if (content
|
||||
!= null) {
|
||||
this.setDataView(content, 0, false);
|
||||
|
||||
Lookup lookup = selectedNode.getLookup();
|
||||
Content content = lookup.lookup(Content.class);
|
||||
if (content != null) {
|
||||
this.setDataView(content, 0);
|
||||
return;
|
||||
} else {
|
||||
StringContent scontent = selectedNode.getLookup().lookup(StringContent.class);
|
||||
if (scontent != null) {
|
||||
this.setDataView(scontent);
|
||||
return;
|
||||
} else {
|
||||
StringContent scontent = selectedNode.getLookup().lookup(StringContent.class);
|
||||
if (scontent != null) {
|
||||
this.setDataView(scontent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.setDataView(null, 0, true);
|
||||
resetComponent();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -474,6 +466,7 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC
|
||||
totalPageLabel.setText("");
|
||||
prevPageButton.setEnabled(false);
|
||||
nextPageButton.setEnabled(false);
|
||||
outputViewPane.setText(""); // reset the output view
|
||||
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) {
|
||||
if (node == null) {
|
||||
return false;
|
||||
|
||||
|
||||
}
|
||||
Content content = node.getLookup().lookup(Content.class);
|
||||
|
||||
if (content
|
||||
!= null && content.getSize()
|
||||
!= 0) {
|
||||
if (content != null && content.getSize() > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataResult;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.explorer.ExplorerUtils;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.windows.TopComponent;
|
||||
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 DataResultPanel dataResultPanel; //embedded component with all the logic
|
||||
private boolean isMain;
|
||||
private boolean lookupSet = false;
|
||||
private String customModeName;
|
||||
|
||||
//keep track of tcs openeded for menu presenters
|
||||
@ -260,6 +262,21 @@ public class DataResultTopComponent extends TopComponent implements DataResult {
|
||||
super.componentOpened();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -62,7 +62,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
ov.setAllowedDropActions(DnDConstants.ACTION_NONE);
|
||||
|
||||
// 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
|
||||
ov.getOutline().setRootVisible(false);
|
||||
|
@ -144,6 +144,10 @@ public class MediaViewImagePanel extends javax.swing.JPanel {
|
||||
try {
|
||||
//original input stream
|
||||
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
|
||||
BufferedImage biScaled = ScalrWrapper.resizeHighQuality(bi, (int) dims.getWidth(), (int) dims.getHeight());
|
||||
//convert from awt imageto fx image
|
||||
|
@ -86,6 +86,9 @@ class ThumbnailViewNode extends FilterNode {
|
||||
if (getFile(content.getId()).exists()) {
|
||||
try {
|
||||
icon = ImageIO.read(getFile(content.getId()));
|
||||
if (icon == null) {
|
||||
icon = ThumbnailViewNode.defaultIcon;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
icon = ThumbnailViewNode.defaultIcon;
|
||||
}
|
||||
@ -120,6 +123,10 @@ class ThumbnailViewNode extends FilterNode {
|
||||
try {
|
||||
inputStream = new ReadContentInputStream(content);
|
||||
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);
|
||||
return biScaled;
|
||||
}catch (OutOfMemoryError e) {
|
||||
|
@ -19,12 +19,17 @@
|
||||
|
||||
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.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
|
||||
/**
|
||||
* This class contains the framework to read, add, update, and remove
|
||||
* 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
|
||||
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 */
|
||||
private ModuleSettings() {
|
||||
|
||||
}
|
||||
|
||||
private ModuleSettings() {}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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.
|
||||
* @param moduleName - The name of the properties file to be modified.
|
||||
* @param key - the name of the key to remove.
|
||||
*/
|
||||
|
||||
public static synchronized void removeProperty(String moduleName, String key){
|
||||
try{
|
||||
if(getConfigSetting(moduleName, key) != null){
|
||||
@ -268,5 +266,4 @@ public class ModuleSettings {
|
||||
return new File(getPropertyPath(moduleName));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
8
Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java
Normal file → Executable file
8
Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java
Normal file → Executable file
@ -23,7 +23,7 @@ import java.util.List;
|
||||
import javax.swing.Action;
|
||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
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.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Directory;
|
||||
@ -67,16 +67,16 @@ public class DirectoryNode extends AbstractFsContentNode<AbstractFile> {
|
||||
*/
|
||||
@Override
|
||||
public Action[] getActions(boolean popup) {
|
||||
List<Action> actions = new ArrayList<Action>();
|
||||
List<Action> actions = new ArrayList<>();
|
||||
if (!getDirectoryBrowseMode()) {
|
||||
actions.add(new ViewContextAction("View File in Directory", this));
|
||||
actions.add(null); // creates a menu separator
|
||||
}
|
||||
actions.add(new NewWindowViewAction("View in New Window", this));
|
||||
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(new TagAction(this));
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
return actions.toArray(new Action[0]);
|
||||
}
|
||||
|
||||
|
9
Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java
Normal file → Executable file
9
Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java
Normal file → Executable file
@ -25,10 +25,9 @@ import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
||||
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.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.FsContent;
|
||||
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
|
||||
import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
|
||||
|
||||
@ -74,7 +73,7 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
|
||||
*/
|
||||
@Override
|
||||
public Action[] getActions(boolean popup) {
|
||||
List<Action> actionsList = new ArrayList<Action>();
|
||||
List<Action> actionsList = new ArrayList<>();
|
||||
if (!this.getDirectoryBrowseMode()) {
|
||||
actionsList.add(new ViewContextAction("View File in Directory", this));
|
||||
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 ExternalViewerAction("Open in External Viewer", this));
|
||||
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(null); // creates a menu separator
|
||||
actionsList.add(new TagAction(this));
|
||||
actionsList.add(TagAbstractFileAction.getInstance());
|
||||
return actionsList.toArray(new Action[0]);
|
||||
}
|
||||
|
||||
|
@ -24,11 +24,10 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.swing.Action;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.sleuthkit.autopsy.directorytree.ExplorerNodeActionVisitor;
|
||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
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.TskData;
|
||||
|
||||
@ -104,14 +103,12 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
|
||||
@Override
|
||||
public Action[] getActions(boolean context) {
|
||||
List<Action> actionsList = new ArrayList<Action>();
|
||||
|
||||
actionsList.add(new NewWindowViewAction("View in New Window", this));
|
||||
actionsList.add(new ExternalViewerAction("Open in External Viewer", this));
|
||||
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(new TagAction(content));
|
||||
|
||||
actionsList.add(TagAbstractFileAction.getInstance());
|
||||
return actionsList.toArray(new Action[0]);
|
||||
}
|
||||
|
||||
|
@ -30,9 +30,8 @@ import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
||||
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.LocalFile;
|
||||
|
||||
/**
|
||||
* A Node for a LocalFile or DerivedFile content object.
|
||||
@ -86,16 +85,14 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
|
||||
|
||||
@Override
|
||||
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 ExternalViewerAction("Open in External Viewer", this));
|
||||
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(null); // creates a menu separator
|
||||
actionsList.add(new TagAction(content));
|
||||
|
||||
actionsList.add(TagAbstractFileAction.getInstance());
|
||||
return actionsList.toArray(new Action[0]);
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,6 @@ import java.awt.event.ActionEvent;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@ -656,36 +655,4 @@ public class Tags implements AutopsyVisitableItem {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ import org.openide.nodes.Sheet;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
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.TskData;
|
||||
|
||||
@ -76,13 +76,12 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode<VirtualDirect
|
||||
*/
|
||||
@Override
|
||||
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(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(new TagAction(this));
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
return actions.toArray(new Action[0]);
|
||||
}
|
||||
|
||||
|
36
Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java
Normal file → Executable file
36
Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java
Normal file → Executable file
@ -105,7 +105,7 @@ public class DataResultFilterNode extends FilterNode {
|
||||
@Override
|
||||
public Action[] getActions(boolean popup) {
|
||||
|
||||
List<Action> actions = new ArrayList<Action>();
|
||||
List<Action> actions = new ArrayList<>();
|
||||
|
||||
final DisplayableItemNode originalNode = (DisplayableItemNode) this.getOriginal();
|
||||
actions.addAll(originalNode.accept(getActionsDIV));
|
||||
@ -167,7 +167,7 @@ public class DataResultFilterNode extends FilterNode {
|
||||
//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
|
||||
|
||||
List<Action> actions = new ArrayList<Action>();
|
||||
List<Action> actions = new ArrayList<>();
|
||||
|
||||
//merge predefined specific node actions if bban subclasses have their own
|
||||
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 ExternalViewerAction("Open in External Viewer", fn));
|
||||
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));
|
||||
|
||||
//add file/result tag if itself is not a tag
|
||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(new TagAction(f));
|
||||
actions.add(new TagAction(ba));
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(TagBlackboardArtifactAction.getInstance());
|
||||
}
|
||||
}
|
||||
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 ExternalViewerAction("Open in External Viewer", dn));
|
||||
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
|
||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(new TagAction(d));
|
||||
actions.add(new TagAction(ba));
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(TagBlackboardArtifactAction.getInstance());
|
||||
}
|
||||
}
|
||||
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 ExternalViewerAction("Open in External Viewer", dn));
|
||||
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
|
||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(new TagAction(d));
|
||||
actions.add(new TagAction(ba));
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(TagBlackboardArtifactAction.getInstance());
|
||||
}
|
||||
} else if ((lf = ban.getLookup().lookup(LayoutFile.class)) != null) {
|
||||
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 ExternalViewerAction("Open in External Viewer", lfn));
|
||||
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
|
||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(new TagAction(lf));
|
||||
actions.add(new TagAction(ba));
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(TagBlackboardArtifactAction.getInstance());
|
||||
}
|
||||
} else if ((locF = ban.getLookup().lookup(LocalFile.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 ExternalViewerAction("Open in External Viewer", locfn));
|
||||
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
|
||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(new TagAction(lf));
|
||||
actions.add(new TagAction(ba));
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(TagBlackboardArtifactAction.getInstance());
|
||||
}
|
||||
}
|
||||
|
||||
@ -278,7 +278,7 @@ public class DataResultFilterNode extends FilterNode {
|
||||
@Override
|
||||
protected List<Action> defaultVisit(DisplayableItemNode ditem) {
|
||||
//preserve the default node's actions
|
||||
List<Action> actions = new ArrayList<Action>();
|
||||
List<Action> actions = new ArrayList<>();
|
||||
|
||||
for (Action action : ditem.getActions(true)) {
|
||||
actions.add(action);
|
||||
|
3
Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java
Normal file → Executable file
3
Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java
Normal file → Executable file
@ -99,8 +99,7 @@ class DirectoryTreeFilterNode extends FilterNode {
|
||||
//extract dir action
|
||||
Directory dir = this.getLookup().lookup(Directory.class);
|
||||
if (dir != null) {
|
||||
actions.add(new ExtractAction("Extract Directory",
|
||||
getOriginal()));
|
||||
actions.add(ExtractAction.getInstance());
|
||||
}
|
||||
|
||||
// file search action
|
||||
|
18
Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java
Normal file → Executable file
18
Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java
Normal file → Executable file
@ -101,39 +101,39 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
|
||||
@Override
|
||||
public List<? extends Action> visit(final Directory d) {
|
||||
List<Action> actions = new ArrayList<Action>();
|
||||
actions.add(new TagAction(d));
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
return actions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Action> visit(final VirtualDirectory d) {
|
||||
List<Action> actions = new ArrayList<Action>();
|
||||
actions.add(new TagAction(d));
|
||||
actions.add(new ExtractAction("Extract Directory", d));
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
return actions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Action> visit(final DerivedFile d) {
|
||||
List<Action> actions = new ArrayList<Action>();
|
||||
actions.add(new ExtractAction("Extract File", d));
|
||||
actions.add(new TagAction(d));
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
return actions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Action> visit(final LocalFile d) {
|
||||
List<Action> actions = new ArrayList<Action>();
|
||||
actions.add(new ExtractAction("Extract File", d));
|
||||
actions.add(new TagAction(d));
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
return actions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Action> visit(final org.sleuthkit.datamodel.File d) {
|
||||
List<Action> actions = new ArrayList<Action>();
|
||||
actions.add(new ExtractAction("Extract File", d));
|
||||
actions.add(new TagAction(d));
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
return actions;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* 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.event.ActionEvent;
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
@ -30,81 +31,35 @@ import javax.swing.JOptionPane;
|
||||
import javax.swing.SwingWorker;
|
||||
import org.netbeans.api.progress.ProgressHandle;
|
||||
import org.netbeans.api.progress.ProgressHandleFactory;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.Cancellable;
|
||||
import org.openide.util.Utilities;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.FileUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||
import org.sleuthkit.autopsy.datamodel.ContentUtils.ExtractFscContentVisitor;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.ContentVisitor;
|
||||
import org.sleuthkit.datamodel.Directory;
|
||||
|
||||
/**
|
||||
* Exports files and folders
|
||||
*/
|
||||
public final class ExtractAction extends AbstractAction {
|
||||
|
||||
private static final InitializeContentVisitor initializeCV = new InitializeContentVisitor();
|
||||
private AbstractFile content;
|
||||
private Logger logger = Logger.getLogger(ExtractAction.class.getName());
|
||||
|
||||
public ExtractAction(String title, Node contentNode) {
|
||||
super(title);
|
||||
Content tempContent = contentNode.getLookup().lookup(Content.class);
|
||||
// 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 ExtractAction instance;
|
||||
|
||||
this.content = tempContent.accept(initializeCV);
|
||||
this.setEnabled(content != null);
|
||||
public static synchronized ExtractAction getInstance() {
|
||||
if (null == instance) {
|
||||
instance = new ExtractAction();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public ExtractAction(String title, Content content) {
|
||||
super(title);
|
||||
|
||||
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;
|
||||
}
|
||||
private ExtractAction() {
|
||||
super("Extract");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -114,10 +69,17 @@ public final class ExtractAction extends AbstractAction {
|
||||
*/
|
||||
@Override
|
||||
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
|
||||
JFileChooser fc = new JFileChooser();
|
||||
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());
|
||||
|
||||
if (returnValue == JFileChooser.APPROVE_OPTION) {
|
||||
@ -144,7 +106,7 @@ public final class ExtractAction extends AbstractAction {
|
||||
|
||||
try {
|
||||
ExtractFileThread extract = new ExtractFileThread();
|
||||
extract.init(this.content, e, destination);
|
||||
extract.init(file, e, destination);
|
||||
extract.execute();
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.WARNING, "Unable to start background thread.", ex);
|
||||
@ -231,5 +193,4 @@ public final class ExtractAction extends AbstractAction {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
70
Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java
Executable file
70
Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java
Executable 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -30,28 +30,50 @@ import javax.swing.JFrame;
|
||||
import javax.swing.KeyStroke;
|
||||
import org.openide.windows.WindowManager;
|
||||
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.
|
||||
*/
|
||||
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 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
|
||||
*/
|
||||
public TagAndCommentDialog(Taggable taggable) {
|
||||
private TagAndCommentDialog() {
|
||||
super((JFrame)WindowManager.getDefault().getMainWindow(), "Tag and Comment", true);
|
||||
|
||||
this.taggable = taggable;
|
||||
|
||||
initComponents();
|
||||
|
||||
// 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);
|
||||
ActionMap actionMap = getRootPane().getActionMap();
|
||||
actionMap.put(cancelName, new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
//doClose(RET_CANCEL);
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
@ -82,14 +104,9 @@ public class TagAndCommentDialog extends JDialog {
|
||||
//center it
|
||||
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
|
||||
|
||||
customizeComponent();
|
||||
|
||||
setVisible(true); // blocks
|
||||
}
|
||||
|
||||
private void customizeComponent() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -195,22 +212,12 @@ public class TagAndCommentDialog extends JDialog {
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
|
||||
//doClose(RET_OK);
|
||||
|
||||
// get the selected tag and comment
|
||||
String selectedTag = (String)tagCombo.getSelectedItem();
|
||||
String comment = commentText.getText();
|
||||
|
||||
// create the tag
|
||||
taggable.createTag(selectedTag, comment);
|
||||
|
||||
refreshDirectoryTree();
|
||||
|
||||
tagName = (String)tagCombo.getSelectedItem();
|
||||
comment = commentText.getText();
|
||||
dispose();
|
||||
}//GEN-LAST:event_okButtonActionPerformed
|
||||
|
||||
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
|
||||
//doClose(RET_CANCEL);
|
||||
dispose();
|
||||
}//GEN-LAST:event_cancelButtonActionPerformed
|
||||
|
||||
@ -218,14 +225,12 @@ public class TagAndCommentDialog extends JDialog {
|
||||
* Closes the dialog
|
||||
*/
|
||||
private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog
|
||||
//doClose(RET_CANCEL);
|
||||
dispose();
|
||||
}//GEN-LAST:event_closeDialog
|
||||
|
||||
private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed
|
||||
String newTagName = CreateTagDialog.getNewTagNameDialog(null);
|
||||
if (newTagName != null) {
|
||||
//tagsModel.addElement(newTagName);
|
||||
tagCombo.addItem(newTagName);
|
||||
tagCombo.setSelectedItem(newTagName);
|
||||
}
|
||||
@ -240,12 +245,4 @@ public class TagAndCommentDialog extends JDialog {
|
||||
private javax.swing.JComboBox tagCombo;
|
||||
private javax.swing.JLabel tagLabel;
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -24,38 +24,20 @@ import java.util.List;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
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
|
||||
// Create the 'Quick Tag' sub-menu and add it to the tag menu.
|
||||
JMenu quickTagMenu = new JMenu("Quick Tag");
|
||||
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();
|
||||
if (tagNames.isEmpty()) {
|
||||
JMenuItem empty = new JMenuItem("No tags");
|
||||
@ -63,44 +45,48 @@ public class TagMenu extends JMenu {
|
||||
quickTagMenu.add(empty);
|
||||
}
|
||||
|
||||
// Add a menu item for each existing tag name to the 'Quick Tag' menu.
|
||||
for (final String tagName : tagNames) {
|
||||
JMenuItem tagItem = new JMenuItem(tagName);
|
||||
tagItem.addActionListener(new ActionListener() {
|
||||
JMenuItem tagNameItem = new JMenuItem(tagName);
|
||||
tagNameItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
tagCreator.createTag(tagName, "");
|
||||
applyTag(tagName, "");
|
||||
refreshDirectoryTree();
|
||||
}
|
||||
});
|
||||
quickTagMenu.add(tagItem);
|
||||
quickTagMenu.add(tagNameItem);
|
||||
}
|
||||
|
||||
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");
|
||||
newTagMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String newTagName = CreateTagDialog.getNewTagNameDialog(null);
|
||||
if (newTagName != null) {
|
||||
tagCreator.createTag(newTagName, "");
|
||||
String tagName = CreateTagDialog.getNewTagNameDialog(null);
|
||||
if (tagName != null) {
|
||||
applyTag(tagName, "");
|
||||
refreshDirectoryTree();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// add the 'New Tag' menu item to the 'Quick Tag' menu
|
||||
quickTagMenu.add(newTagMenuItem);
|
||||
|
||||
JMenuItem newTagItem = new JMenuItem("Tag and Comment");
|
||||
newTagItem.addActionListener(new ActionListener() {
|
||||
// Create the 'Tag and Comment' menu item and add it to the tag menu.
|
||||
JMenuItem tagAndCommentItem = new JMenuItem("Tag and Comment");
|
||||
tagAndCommentItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
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() {
|
||||
@ -109,4 +95,6 @@ public class TagMenu extends JMenu {
|
||||
viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE);
|
||||
viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT);
|
||||
}
|
||||
|
||||
protected abstract void applyTag(String tagName, String comment);
|
||||
}
|
||||
|
125
Core/src/org/sleuthkit/autopsy/examples/SampleDataSourceIngestModule.java
Executable file
125
Core/src/org/sleuthkit/autopsy/examples/SampleDataSourceIngestModule.java
Executable 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;
|
||||
}
|
||||
}
|
178
Core/src/org/sleuthkit/autopsy/examples/SampleFileIngestModule.java
Executable file
178
Core/src/org/sleuthkit/autopsy/examples/SampleFileIngestModule.java
Executable 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;
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* 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.WindowEvent;
|
||||
import java.util.List;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import org.openide.util.Lookup;
|
||||
import org.sleuthkit.autopsy.casemodule.GeneralIngestConfigurator;
|
||||
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 {
|
||||
|
||||
private static final String TITLE = "Ingest Modules";
|
||||
private static Dimension DIMENSIONS = new Dimension(500, 300);
|
||||
private IngestDialogPanel panel = null;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(IngestDialog.class.getName());
|
||||
private IngestConfigurator ingestConfigurator;
|
||||
|
||||
public IngestDialog(JFrame frame, String title, boolean modal) {
|
||||
super(frame, title, modal);
|
||||
panel = new IngestDialogPanel();
|
||||
ingestConfigurator = new GeneralIngestConfigurator();
|
||||
ingestConfigurator.setContext(IngestDialog.class.getCanonicalName());
|
||||
ingestConfigurator.reload();
|
||||
}
|
||||
|
||||
public IngestDialog(){
|
||||
this(new JFrame(TITLE), TITLE, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2);
|
||||
|
||||
panel.reload(); // reload the simple panel
|
||||
add(panel, BorderLayout.PAGE_START);
|
||||
add(ingestConfigurator.getIngestConfigPanel(), BorderLayout.PAGE_START);
|
||||
JButton startButton = new JButton("Start");
|
||||
JButton closeButton = new JButton("Close");
|
||||
startButton.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
|
||||
panel.save();
|
||||
panel.start();
|
||||
ingestConfigurator.save();
|
||||
ingestConfigurator.start();
|
||||
close();
|
||||
}
|
||||
});
|
||||
@ -89,7 +88,7 @@ public class IngestDialog extends JDialog {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
panel.save();
|
||||
ingestConfigurator.save();
|
||||
close();
|
||||
}
|
||||
});
|
||||
@ -97,7 +96,7 @@ public class IngestDialog extends JDialog {
|
||||
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
panel.save();
|
||||
ingestConfigurator.save();
|
||||
close();
|
||||
}
|
||||
});
|
||||
@ -115,10 +114,9 @@ public class IngestDialog extends JDialog {
|
||||
}
|
||||
|
||||
public void setContent(List<Content> inputContent) {
|
||||
panel.setContent(inputContent);
|
||||
ingestConfigurator.setContent(inputContent);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Closes the Ingest dialog
|
||||
*/
|
||||
@ -126,6 +124,4 @@ public class IngestDialog extends JDialog {
|
||||
setVisible(false);
|
||||
dispose();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2011-2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -18,24 +18,15 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.ingest;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
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.ListSelectionModel;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
@ -43,80 +34,55 @@ import javax.swing.event.ListSelectionListener;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
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.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
|
||||
*/
|
||||
@ServiceProvider(service = IngestConfigurator.class)
|
||||
public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfigurator {
|
||||
public class IngestDialogPanel extends javax.swing.JPanel {
|
||||
|
||||
private IngestManager manager = null;
|
||||
private List<IngestModuleAbstract> modules;
|
||||
private IngestModuleAbstract currentModule;
|
||||
private Map<String, Boolean> moduleStates;
|
||||
private ModulesTableModel tableModel;
|
||||
private static final Logger logger = Logger.getLogger(IngestDialogPanel.class.getName());
|
||||
public static final String DISABLED_MOD = "Disabled_Ingest_Modules";
|
||||
public static final String PARSE_UNALLOC = "Process_Unallocated_Space";
|
||||
// The input content that's just been added to the database
|
||||
private List<Content> inputContent;
|
||||
// private static IngestDialogPanel instance = null;
|
||||
private String context;
|
||||
|
||||
/**
|
||||
* Creates new form IngestDialogPanel
|
||||
*/
|
||||
public IngestDialogPanel() {
|
||||
tableModel = new ModulesTableModel();
|
||||
modules = new ArrayList<IngestModuleAbstract>();
|
||||
moduleStates = new HashMap<String, Boolean>();
|
||||
context = ModuleSettings.DEFAULT_CONTEXT;
|
||||
initComponents();
|
||||
customizeComponents();
|
||||
}
|
||||
|
||||
private void loadModules() {
|
||||
this.modules.clear();
|
||||
//this.moduleStates.clear(); maintain the state
|
||||
Collection<IngestModuleDataSource> imageModules = manager.enumerateDataSourceModules();
|
||||
for (final IngestModuleDataSource module : imageModules) {
|
||||
addModule(module);
|
||||
}
|
||||
Collection<IngestModuleAbstractFile> fsModules = manager.enumerateAbstractFileModules();
|
||||
for (final IngestModuleAbstractFile module : fsModules) {
|
||||
addModule(module);
|
||||
}
|
||||
public void setContext(String context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
|
||||
public IngestModuleAbstract getCurrentIngestModule() {
|
||||
return currentModule;
|
||||
}
|
||||
|
||||
public List<IngestModuleAbstract> getModulesToStart() {
|
||||
return tableModel.getSelectedModules();
|
||||
}
|
||||
|
||||
public boolean processUnallocSpaceEnabled() {
|
||||
return processUnallocCheckbox.isSelected();
|
||||
}
|
||||
|
||||
private void customizeComponents() {
|
||||
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.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
|
||||
//custom renderer for tooltips
|
||||
|
||||
ModulesTableRenderer renderer = new ModulesTableRenderer();
|
||||
|
||||
//customize column witdhs
|
||||
final int width = modulesScrollPane.getPreferredSize().width;
|
||||
TableColumn column = null;
|
||||
@ -135,40 +101,30 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
ListSelectionModel listSelectionModel = (ListSelectionModel) e.getSource();
|
||||
if (!listSelectionModel.isSelectionEmpty()) {
|
||||
save();
|
||||
int index = listSelectionModel.getMinSelectionIndex();
|
||||
currentModule = modules.get(index);
|
||||
reload();
|
||||
currentModule = tableModel.getModule(index);
|
||||
|
||||
// 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());
|
||||
} else {
|
||||
currentModule = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
processUnallocCheckbox.setSelected(manager.getProcessUnallocSpace());
|
||||
|
||||
}
|
||||
|
||||
private void setProcessUnallocSpaceEnabled(boolean enabled) {
|
||||
processUnallocCheckbox.setEnabled(enabled);
|
||||
public void setProcessUnallocSpaceEnabled(final boolean enabled) {
|
||||
processUnallocCheckbox.setSelected(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
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);
|
||||
public void setDisabledModules(List<IngestModuleAbstract> disabledModules) {
|
||||
tableModel.setUnselectedModules(disabledModules);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -311,22 +267,19 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
dialog.close();
|
||||
currentModule.saveAdvancedConfiguration();
|
||||
reload();
|
||||
}
|
||||
});
|
||||
dialog.addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
dialog.close();
|
||||
reload();
|
||||
}
|
||||
});
|
||||
save(); // save the simple panel
|
||||
dialog.display(currentModule.getAdvancedConfiguration(null));
|
||||
dialog.display(currentModule.getAdvancedConfiguration(context));
|
||||
}//GEN-LAST:event_advancedButtonActionPerformed
|
||||
|
||||
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
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JButton advancedButton;
|
||||
@ -343,9 +296,18 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
|
||||
|
||||
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
|
||||
public int getRowCount() {
|
||||
return modules.size();
|
||||
return moduleData.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -355,11 +317,11 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||
String name = modules.get(rowIndex).getName();
|
||||
Map.Entry<IngestModuleAbstract, Boolean> entry = moduleData.get(rowIndex);
|
||||
if (columnIndex == 0) {
|
||||
return moduleStates.get(name);
|
||||
return entry.getValue();
|
||||
} else {
|
||||
return name;
|
||||
return entry.getKey().getName();
|
||||
}
|
||||
}
|
||||
|
||||
@ -371,8 +333,7 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi
|
||||
@Override
|
||||
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
|
||||
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) {
|
||||
return getValueAt(0, c).getClass();
|
||||
}
|
||||
}
|
||||
|
||||
List<IngestModuleAbstract> getModulesToStart() {
|
||||
List<IngestModuleAbstract> modulesToStart = new ArrayList<IngestModuleAbstract>();
|
||||
for (IngestModuleAbstract module : modules) {
|
||||
boolean moduleEnabled = moduleStates.get(module.getName());
|
||||
if (moduleEnabled) {
|
||||
modulesToStart.add(module);
|
||||
}
|
||||
}
|
||||
return 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
|
||||
public List<IngestModuleAbstract> getSelectedModules() {
|
||||
List<IngestModuleAbstract> selectedModules = new ArrayList<>();
|
||||
for (Map.Entry<IngestModuleAbstract, Boolean> entry : moduleData) {
|
||||
if (entry.getValue().booleanValue()) {
|
||||
selectedModules.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
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());
|
||||
return selectedModules;
|
||||
}
|
||||
|
||||
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
|
||||
public boolean isIngestRunning() {
|
||||
return manager.isIngestRunning();
|
||||
// unselect only the given modules
|
||||
for (IngestModuleAbstract unselectedModule : unselectedModules) {
|
||||
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 {
|
||||
|
||||
List<String> tooltips = new ArrayList<>();
|
||||
|
||||
public ModulesTableRenderer() {
|
||||
List<IngestModuleAbstract> modules = IngestManager.getDefault().enumerateAllModules();
|
||||
for (IngestModuleAbstract ingestModuleAbstract : modules) {
|
||||
tooltips.add(ingestModuleAbstract.getDescription());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTableCellRendererComponent(
|
||||
JTable table, Object value,
|
||||
boolean isSelected, boolean hasFocus,
|
||||
int row, int column) {
|
||||
|
||||
final Component cell = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
|
||||
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
|
||||
|
||||
if (column == 1) {
|
||||
//String moduleName = (String) table.getModel().getValueAt(row, column);
|
||||
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>");
|
||||
setToolTipText(tooltips.get(row));
|
||||
}
|
||||
|
||||
return cell;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2012 Basis Technology Corp.
|
||||
* Copyright 2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -154,8 +154,6 @@ public class IngestManager {
|
||||
} catch (IngestModuleLoaderException ex) {
|
||||
logger.log(Level.SEVERE, "Error getting module loader");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -243,7 +241,6 @@ public class IngestManager {
|
||||
if (ui != null) {
|
||||
ui.restoreMessages();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -346,17 +343,15 @@ public class IngestManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
//}
|
||||
|
||||
|
||||
//AbstractFile ingester
|
||||
boolean startAbstractFileIngester = false;
|
||||
if (fileScheduler.hasNext()) {
|
||||
if (abstractFileIngester
|
||||
== null) {
|
||||
if (abstractFileIngester == null) {
|
||||
startAbstractFileIngester = true;
|
||||
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()) {
|
||||
startAbstractFileIngester = true;
|
||||
logger.log(Level.INFO, "Restarting AbstractFile ingester");
|
||||
@ -369,6 +364,9 @@ public class IngestManager {
|
||||
stats = new IngestManagerStats();
|
||||
abstractFileIngester = new IngestAbstractFileProcessor();
|
||||
//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) {
|
||||
IngestModuleInit moduleInit = new IngestModuleInit();
|
||||
try {
|
||||
@ -421,7 +419,6 @@ public class IngestManager {
|
||||
List<IngestDataSourceThread> toStop = new ArrayList<IngestDataSourceThread>();
|
||||
toStop.addAll(dataSourceIngesters);
|
||||
|
||||
|
||||
for (IngestDataSourceThread dataSourceWorker : toStop) {
|
||||
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.INFO, "stopped all");
|
||||
@ -545,7 +541,6 @@ public class IngestManager {
|
||||
return module.hasBackgroundJobsRunning();
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
//data source module
|
||||
synchronized (this) {
|
||||
@ -570,10 +565,7 @@ public class IngestManager {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -607,7 +599,7 @@ public class IngestManager {
|
||||
*
|
||||
* @param processUnallocSpace
|
||||
*/
|
||||
void setProcessUnallocSpace(boolean processUnallocSpace) {
|
||||
public void setProcessUnallocSpace(boolean processUnallocSpace) {
|
||||
this.processUnallocSpace = processUnallocSpace;
|
||||
}
|
||||
|
||||
@ -672,6 +664,13 @@ public class IngestManager {
|
||||
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
|
||||
void removeDataSourceIngestWorker(IngestDataSourceThread worker) {
|
||||
//remove worker
|
||||
@ -697,7 +696,6 @@ public class IngestManager {
|
||||
|
||||
IngestManagerStats() {
|
||||
errors = new HashMap<IngestModuleAbstract, Integer>();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -775,19 +773,8 @@ public class IngestManager {
|
||||
public String toHtmlString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("<html><body>");
|
||||
|
||||
sb.append("Ingest time: ").append(getTotalTimeString()).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>");
|
||||
return sb.toString();
|
||||
}
|
||||
@ -1083,9 +1070,6 @@ public class IngestManager {
|
||||
|
||||
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;
|
||||
for (Content input : inputs) {
|
||||
final String inputName = input.getName();
|
||||
@ -1112,16 +1096,16 @@ public class IngestManager {
|
||||
logger.log(Level.INFO, "Error loading module and adding input " + inputName
|
||||
+ " with module " + module.getName());
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case AbstractFile:
|
||||
//enqueue the same singleton AbstractFile module
|
||||
logger.log(Level.INFO, "Adding input " + inputName
|
||||
+ " number of AbstractFile to module " + module.getName());
|
||||
+ " for AbstractFileModule " + module.getName());
|
||||
|
||||
fileMods.add((IngestModuleAbstractFile) module);
|
||||
break;
|
||||
|
||||
default:
|
||||
logger.log(Level.SEVERE, "Unexpected module type: " + module.getType().name());
|
||||
}
|
||||
@ -1138,6 +1122,7 @@ public class IngestManager {
|
||||
new PipelineContext<IngestModuleDataSource>(dataSourceTask, processUnalloc);
|
||||
logger.log(Level.INFO, "Queing data source ingest task: " + dataSourceTask);
|
||||
progress.progress("DataSource Ingest" + " " + inputName, processed);
|
||||
final IngestScheduler.DataSourceScheduler dataSourceScheduler = scheduler.getDataSourceScheduler();
|
||||
dataSourceScheduler.schedule(dataSourcePipelineContext);
|
||||
progress.progress("DataSource Ingest" + " " + inputName, ++processed);
|
||||
|
||||
@ -1148,6 +1133,7 @@ public class IngestManager {
|
||||
= new PipelineContext<IngestModuleAbstractFile>(fTask, processUnalloc);
|
||||
logger.log(Level.INFO, "Queing file ingest task: " + fTask);
|
||||
progress.progress("File Ingest" + " " + inputName, processed);
|
||||
final IngestScheduler.FileScheduler fileScheduler = scheduler.getFileScheduler();
|
||||
fileScheduler.schedule(filepipelineContext);
|
||||
progress.progress("File Ingest" + " " + inputName, ++processed);
|
||||
|
||||
|
@ -145,35 +145,38 @@ public abstract class IngestModuleAbstract {
|
||||
*/
|
||||
public void saveAdvancedConfiguration() {}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a panel that displays the simple (run-time) configuration
|
||||
* for the given configuration context (such as pipeline instance).
|
||||
* This is presented to the user before ingest starts and only basic
|
||||
* settings should be given here. Use the advanced (general) configuration
|
||||
* panel for more in-depth interfaces.
|
||||
* The module (or its configuration controller object) is responsible for preserving / saving its configuration state
|
||||
* In addition, saveSimpleConfiguration() can be used as the trigger.
|
||||
* Returns a panel that displays the simple (run-time) configuration for the
|
||||
* given configuration context (such as pipeline instance). This is
|
||||
* presented to the user before ingest starts and only basic settings should
|
||||
* be given here. Use the advanced (general) configuration panel for more
|
||||
* in-depth interfaces. The module (or its configuration controller object)
|
||||
* is responsible for preserving / saving its configuration state In
|
||||
* addition, saveSimpleConfiguration() can be used as the trigger.
|
||||
*
|
||||
* @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) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a panel that displays the advanced (run-time) configuration
|
||||
* for the given configuration context (such as pipeline instance).
|
||||
* Implements advanced module configuration exposed to the user before ingest starts.
|
||||
/**
|
||||
* Returns a panel that displays the advanced (run-time) configuration for
|
||||
* the given configuration context (such as pipeline instance). Implements
|
||||
* advanced module configuration exposed to the user before ingest starts.
|
||||
*
|
||||
* The module (or its configuration controller object)
|
||||
* is responsible for preserving / saving its configuration state
|
||||
* In addition, saveAdvancedConfiguration() can be used as the trigger.
|
||||
* The module (or its configuration controller object) is responsible for
|
||||
* preserving / saving its configuration state In addition,
|
||||
* saveAdvancedConfiguration() can be used as the trigger.
|
||||
*
|
||||
* @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) {
|
||||
return null;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -466,10 +466,12 @@ public final class IngestModuleLoader {
|
||||
@SuppressWarnings("unchecked")
|
||||
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);
|
||||
logger.log(Level.INFO, "Autodiscovery, found #platform modules: " + moduleInfos.size());
|
||||
|
||||
Set<URL> urls = getJarPaths(moduleInfos);
|
||||
ArrayList<Reflections> reflectionsSet = new ArrayList<>();
|
||||
|
||||
for (final ModuleInfo moduleInfo : moduleInfos) {
|
||||
if (moduleInfo.isEnabled()) {
|
||||
@ -489,104 +491,115 @@ public final class IngestModuleLoader {
|
||||
cb.filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix(basePackageName)));
|
||||
cb.setUrls(urls);
|
||||
cb.setScanners(new SubTypesScanner(), new ResourcesScanner());
|
||||
Reflections reflections = 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() );
|
||||
reflectionsSet.add(new Reflections(cb));
|
||||
}
|
||||
}
|
||||
|
||||
/* 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());
|
||||
} */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -106,6 +106,159 @@ public class ReportHTML implements TableReportModule {
|
||||
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,
|
||||
* and writing the skeleton for the HTML report.
|
||||
@ -151,7 +304,7 @@ public class ReportHTML implements TableReportModule {
|
||||
*/
|
||||
@Override
|
||||
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
|
||||
try {
|
||||
//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
|
||||
*/
|
||||
public void startDataType(String name, String comment) {
|
||||
String title = org.sleuthkit.autopsy.coreutils.FileUtil.escapeFileName(name);
|
||||
String title = dataTypeToFileName(name);
|
||||
try {
|
||||
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + title + getExtension()), "UTF-8"));
|
||||
} 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");
|
||||
|
||||
for (String dataType : dataTypes.keySet()) {
|
||||
String dataTypeEsc = org.sleuthkit.autopsy.coreutils.FileUtil.escapeFileName(dataType);
|
||||
nav.append("<li style=\"background: url('").append(dataType)
|
||||
.append(".png') left center no-repeat;\"><a href=\"")
|
||||
String dataTypeEsc = dataTypeToFileName(dataType);
|
||||
String iconFileName = useDataTypeIcon(dataType);
|
||||
nav.append("<li style=\"background: url('").append(iconFileName)
|
||||
.append("') left center no-repeat;\"><a href=\"")
|
||||
.append(dataTypeEsc).append(".html\" target=\"content\">")
|
||||
.append(dataType).append(" (").append(dataTypes.get(dataType))
|
||||
.append(")</a></li>\n");
|
||||
@ -668,145 +822,6 @@ public class ReportHTML implements TableReportModule {
|
||||
in.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) {
|
||||
logger.log(Level.SEVERE, "Failed to extract images for HTML report.", ex);
|
||||
|
BIN
Core/src/org/sleuthkit/autopsy/report/images/star.png
Normal file
BIN
Core/src/org/sleuthkit/autopsy/report/images/star.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 674 B |
@ -46,6 +46,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
||||
import org.sleuthkit.datamodel.ReadContentInputStream;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
|
||||
|
||||
/**
|
||||
@ -92,6 +93,11 @@ public final class ExifParserFileIngestModule extends IngestModuleAbstractFile {
|
||||
return IngestModuleAbstractFile.ProcessResult.OK;
|
||||
}
|
||||
|
||||
// skip known
|
||||
if (content.getKnown().equals(TskData.FileKnown.KNOWN)) {
|
||||
return IngestModuleAbstractFile.ProcessResult.OK;
|
||||
}
|
||||
|
||||
//skip unsupported
|
||||
if (! parsableFormat(content)) {
|
||||
return IngestModuleAbstractFile.ProcessResult.OK;
|
||||
|
@ -504,37 +504,42 @@
|
||||
when adding a document.
|
||||
-->
|
||||
|
||||
<!-- object id of the file -->
|
||||
<field name="id" type="string" indexed="true" stored="true" required="true" />
|
||||
|
||||
<!-- use image_id to easily search a specific image only -->
|
||||
<field name="image_id" type="string" indexed="true" stored="true" required="true" />
|
||||
<!-- The content field holds the text extracted by SolrCell -->
|
||||
<field name="image_id" type="string" indexed="true" stored="false" required="true" />
|
||||
|
||||
<!-- 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" />
|
||||
|
||||
<!-- 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="file_name" type="text_general" indexed="true" stored="true"/>
|
||||
<field name="ctime" type="tdate" indexed="true" stored="true"/>
|
||||
<field name="atime" type="tdate" indexed="true" stored="true"/>
|
||||
<field name="mtime" type="tdate" indexed="true" stored="true"/>
|
||||
<field name="crtime" type="tdate" indexed="true" stored="true"/>
|
||||
<!-- file chunk-specific fields (optional for others) -->
|
||||
<!-- for a parent file with no content, number of chunks are specified -->
|
||||
<field name="num_chunks" type="int" indexed="true" stored="true" required="false" />
|
||||
<!--<field name="strings" type="text_general" indexed="true" stored="true"/>-->
|
||||
|
||||
<field name="file_name" type="text_general" indexed="false" stored="true"/>
|
||||
<field name="ctime" type="tdate" indexed="false" stored="false"/>
|
||||
<field name="atime" type="tdate" indexed="false" stored="false"/>
|
||||
<field name="mtime" type="tdate" indexed="false" stored="false"/>
|
||||
<field name="crtime" type="tdate" indexed="false" stored="false"/>
|
||||
<!-- file chunk-specific fields (optional for others) -->
|
||||
<!-- 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
|
||||
SolrCell metadata when parsing rich documents such as Word, PDF.
|
||||
Some fields are multiValued only because Tika currently may return
|
||||
multiple values for them.
|
||||
-->
|
||||
<field name="title" type="text_general" indexed="true" stored="true" multiValued="true"/>
|
||||
<field name="subject" type="text_general" indexed="true" stored="true"/>
|
||||
<field name="description" type="text_general" indexed="true" stored="true"/>
|
||||
<field name="comments" type="text_general" indexed="true" stored="true"/>
|
||||
<field name="author" type="text_general" indexed="true" stored="true"/>
|
||||
<field name="keywords" type="text_general" indexed="true" stored="true"/>
|
||||
<field name="category" type="text_general" indexed="true" stored="true"/>
|
||||
<field name="content_type" type="string" indexed="true" stored="true" multiValued="true"/>
|
||||
<field name="last_modified" type="date" indexed="true" stored="true"/>
|
||||
<field name="links" type="string" 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="false" stored="false"/>
|
||||
<field name="description" type="text_general" indexed="false" stored="false"/>
|
||||
<field name="comments" type="text_general" indexed="false" stored="false"/>
|
||||
<field name="author" type="text_general" indexed="false" stored="false"/>
|
||||
<field name="keywords" type="text_general" indexed="false" stored="false"/>
|
||||
<field name="category" type="text_general" indexed="false" stored="false"/>
|
||||
<field name="content_type" type="string" indexed="false" stored="false" multiValued="true"/>
|
||||
<field name="last_modified" type="date" indexed="false" stored="false"/>
|
||||
<field name="links" type="string" indexed="false" stored="false" multiValued="true"/>
|
||||
|
||||
<!-- Tika places all metadata into a multivalued field named "meta" -->
|
||||
<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
|
||||
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)
|
||||
also be useful for Lucene based queries containing special characters-->
|
||||
<!-- populated via copyField -->
|
||||
<field name="content_ws" type="text_ws" indexed="true" stored="false" />
|
||||
|
||||
<!-- Uncommenting the following will create a "timestamp" field using
|
||||
@ -621,7 +627,7 @@
|
||||
<copyField source="content" dest="text"/>
|
||||
<copyField source="file_name" dest="text"/>
|
||||
<copyField source="meta" dest="text"/>
|
||||
<copyField source="strings" dest="text"/>
|
||||
<!--<copyField source="strings" dest="text"/>-->
|
||||
<copyField source="content" dest="content_ws"/>
|
||||
|
||||
<!-- Above, multiple source fields are copied to the [text] field.
|
||||
|
@ -120,12 +120,11 @@ public class AbstractFileTikaTextExtract implements AbstractFileExtract {
|
||||
|
||||
boolean success = false;
|
||||
Reader reader = null;
|
||||
|
||||
|
||||
final InputStream stream = new ReadContentInputStream(sourceFile);
|
||||
try {
|
||||
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
|
||||
ParseRequestTask parseTask = new ParseRequestTask(tika, stream, meta, sourceFile);
|
||||
final Future<?> future = tikaParseExecutor.submit(parseTask);
|
||||
@ -145,14 +144,16 @@ public class AbstractFileTikaTextExtract implements AbstractFileExtract {
|
||||
throw new IngesterException(msg);
|
||||
}
|
||||
|
||||
// get the reader with the results
|
||||
reader = parseTask.getReader();
|
||||
|
||||
if (reader == null) {
|
||||
//likely due to exception in parse()
|
||||
logger.log(Level.WARNING, "No reader available from Tika parse");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// break the results into chunks and index
|
||||
success = true;
|
||||
long readSize;
|
||||
long totalRead = 0;
|
||||
@ -180,8 +181,6 @@ public class AbstractFileTikaTextExtract implements AbstractFileExtract {
|
||||
//this is the last chunk
|
||||
eof = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//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
|
||||
* streaming
|
||||
* Runnable task that calls tika to parse the content using
|
||||
* the input stream. Provides reader for results.
|
||||
*/
|
||||
private static class ParseRequestTask implements Runnable {
|
||||
|
||||
|
@ -29,7 +29,8 @@ import org.sleuthkit.autopsy.keywordsearch.KeywordSearch.QueryType;
|
||||
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 {
|
||||
|
||||
@ -105,7 +106,8 @@ abstract class AbstractKeywordSearchPerformer extends javax.swing.JPanel impleme
|
||||
return;
|
||||
}
|
||||
man = new KeywordSearchQueryManager(keywords, Presentation.COLLAPSE);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
QueryType queryType = null;
|
||||
if (isLuceneQuerySelected()) {
|
||||
queryType = QueryType.WORD;
|
||||
|
@ -416,14 +416,16 @@ public class ExtractedContentViewer implements DataContentViewer {
|
||||
//because we are storing extracted text in chunks only
|
||||
//and the non-chunk stores meta-data only
|
||||
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) {
|
||||
//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());
|
||||
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>";
|
||||
return htmlMsg;
|
||||
|
@ -17,24 +17,34 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Representation of keyword query as input by user
|
||||
*/
|
||||
package org.sleuthkit.autopsy.keywordsearch;
|
||||
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
|
||||
/**
|
||||
* Representation of single keyword to search for
|
||||
*/
|
||||
public class Keyword {
|
||||
|
||||
private String query;
|
||||
private boolean isLiteral;
|
||||
private String keywordString; // keyword to search for
|
||||
private boolean isLiteral; // false if reg exp
|
||||
private BlackboardAttribute.ATTRIBUTE_TYPE keywordType = null;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param query Keyword to search for
|
||||
* @param isLiteral false if reg exp
|
||||
*/
|
||||
Keyword(String query, boolean isLiteral) {
|
||||
this.query = query;
|
||||
this.keywordString = query;
|
||||
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) {
|
||||
this(query, isLiteral);
|
||||
this.keywordType = keywordType;
|
||||
@ -48,8 +58,12 @@ public class Keyword {
|
||||
return this.keywordType;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return Keyword to search for
|
||||
*/
|
||||
String getQuery() {
|
||||
return query;
|
||||
return keywordString;
|
||||
}
|
||||
|
||||
boolean isLiteral() {
|
||||
@ -58,7 +72,7 @@ public class Keyword {
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (this.isLiteral != other.isLiteral) {
|
||||
@ -84,7 +98,7 @@ public class Keyword {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
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);
|
||||
return hash;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* 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.util.lookup.Lookups;
|
||||
import org.openide.util.lookup.ProxyLookup;
|
||||
import org.sleuthkit.autopsy.directorytree.TagAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
|
||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
@ -128,8 +128,6 @@ class KeywordSearchFilterNode extends FilterNode {
|
||||
Content content = this.getOriginal().getLookup().lookup(Content.class);
|
||||
actions.addAll(content.accept(new GetPopupActionsContentVisitor()));
|
||||
|
||||
//actions.add(new IndexContentFilesAction(nodeContent, "Index"));
|
||||
|
||||
return actions.toArray(new Action[actions.size()]);
|
||||
}
|
||||
|
||||
@ -137,33 +135,29 @@ class KeywordSearchFilterNode extends FilterNode {
|
||||
|
||||
@Override
|
||||
public List<Action> visit(File f) {
|
||||
List<Action> actions = new ArrayList<Action>();
|
||||
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;
|
||||
return getFileActions();
|
||||
}
|
||||
|
||||
@Override
|
||||
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 ExternalViewerAction("Open in External Viewer", getOriginal()));
|
||||
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(null); // creates a menu separator
|
||||
actions.add(new TagAction(getOriginal()));
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
return actions;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Action> defaultVisit(Content c) {
|
||||
return new ArrayList<Action>();
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
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 {
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
/**
|
||||
* Does this interface support multi-word queries?
|
||||
* @return
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
@ -24,6 +24,11 @@ import java.util.Map;
|
||||
import org.apache.solr.client.solrj.response.TermsResponse.Term;
|
||||
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 {
|
||||
|
||||
/**
|
||||
@ -51,7 +56,7 @@ public interface KeywordSearchQuery {
|
||||
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
|
||||
*/
|
||||
public void setField(String field);
|
||||
@ -75,13 +80,13 @@ public interface KeywordSearchQuery {
|
||||
public boolean isLiteral();
|
||||
|
||||
/**
|
||||
* return original query string
|
||||
* return original keyword/query string
|
||||
* @return the query String supplied originally
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public String getEscapedQueryString();
|
||||
|
@ -34,73 +34,99 @@ import org.sleuthkit.autopsy.datamodel.KeyValue;
|
||||
import org.sleuthkit.autopsy.keywordsearch.KeywordSearch.QueryType;
|
||||
|
||||
/**
|
||||
* Query manager responsible for running appropriate queries and displaying
|
||||
* results for single, multi keyword queries, with detailed or collapsed results
|
||||
* Responsible for running a keyword search query and displaying
|
||||
* the results.
|
||||
*/
|
||||
public class KeywordSearchQueryManager {
|
||||
|
||||
// how to display the results
|
||||
public enum Presentation {
|
||||
|
||||
COLLAPSE, DETAIL
|
||||
};
|
||||
private List<Keyword> queries;
|
||||
|
||||
private List<Keyword> keywords;
|
||||
private Presentation presentation;
|
||||
private List<KeywordSearchQuery> queryDelegates;
|
||||
private QueryType queryType;
|
||||
private static int resultWindowCount = 0; //keep track of unique window ids to display
|
||||
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) {
|
||||
this.queries = queries;
|
||||
this.keywords = queries;
|
||||
this.presentation = presentation;
|
||||
queryType = QueryType.REGEX;
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param query Keyword to search for
|
||||
* @param qt Query type
|
||||
* @param presentation Presentation Layout
|
||||
*/
|
||||
public KeywordSearchQueryManager(String query, QueryType qt, Presentation presentation) {
|
||||
queries = new ArrayList<Keyword>();
|
||||
queries.add(new Keyword(query, qt == QueryType.REGEX ? false : true));
|
||||
keywords = new ArrayList<Keyword>();
|
||||
keywords.add(new Keyword(query, qt == QueryType.REGEX ? false : true));
|
||||
this.presentation = presentation;
|
||||
queryType = qt;
|
||||
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) {
|
||||
queries = new ArrayList<Keyword>();
|
||||
queries.add(new Keyword(query, isLiteral));
|
||||
keywords = new ArrayList<Keyword>();
|
||||
keywords.add(new Keyword(query, isLiteral));
|
||||
this.presentation = presentation;
|
||||
queryType = isLiteral ? QueryType.WORD : QueryType.REGEX;
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize internal settings based on constructor arguments.
|
||||
* Create a list of queries to later run
|
||||
*/
|
||||
private void init() {
|
||||
queryDelegates = new ArrayList<KeywordSearchQuery>();
|
||||
for (Keyword query : queries) {
|
||||
KeywordSearchQuery del = null;
|
||||
for (Keyword keyword : keywords) {
|
||||
KeywordSearchQuery query = null;
|
||||
switch (queryType) {
|
||||
case WORD:
|
||||
del = new LuceneQuery(query);
|
||||
query = new LuceneQuery(keyword);
|
||||
break;
|
||||
case REGEX:
|
||||
if (query.isLiteral()) {
|
||||
del = new LuceneQuery(query);
|
||||
if (keyword.isLiteral()) {
|
||||
query = new LuceneQuery(keyword);
|
||||
} else {
|
||||
del = new TermComponentQuery(query);
|
||||
query = new TermComponentQuery(keyword);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
if (query.isLiteral()) {
|
||||
del.escape();
|
||||
if (query != null) {
|
||||
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() {
|
||||
//execute and present the query
|
||||
//delegate query to query objects and presentation child factories
|
||||
@ -109,10 +135,11 @@ public class KeywordSearchQueryManager {
|
||||
// q.execute();
|
||||
// }
|
||||
// } else {
|
||||
|
||||
//Collapsed view
|
||||
Collection<KeyValueQuery> things = new ArrayList<KeyValueQuery>();
|
||||
int queryID = 0;
|
||||
StringBuilder queryConcat = new StringBuilder();
|
||||
StringBuilder queryConcat = new StringBuilder(); // concatenation of all query strings
|
||||
for (KeywordSearchQuery q : queryDelegates) {
|
||||
Map<String, Object> kvs = new LinkedHashMap<String, Object>();
|
||||
final String queryStr = q.getQueryString();
|
||||
@ -129,7 +156,7 @@ public class KeywordSearchQueryManager {
|
||||
DataResultTopComponent searchResultWin = DataResultTopComponent.createInstance(windowTitle);
|
||||
if (things.size() > 0) {
|
||||
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);
|
||||
} else {
|
||||
@ -144,6 +171,10 @@ public class KeywordSearchQueryManager {
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* validate the queries before they are run
|
||||
* @return false if any are invalid
|
||||
*/
|
||||
public boolean validate() {
|
||||
boolean allValid = true;
|
||||
for (KeywordSearchQuery tcq : queryDelegates) {
|
||||
|
@ -42,11 +42,15 @@ import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
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 {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(LuceneQuery.class.getName());
|
||||
private String query; //original unescaped query
|
||||
private String queryEscaped;
|
||||
private String keywordString; //original unescaped query
|
||||
private String keywordStringEscaped;
|
||||
private boolean isEscaped;
|
||||
private Keyword keywordQuery = null;
|
||||
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);
|
||||
|
||||
/**
|
||||
* Constructor with query to process.
|
||||
* @param keywordQuery
|
||||
*/
|
||||
public LuceneQuery(Keyword keywordQuery) {
|
||||
this(keywordQuery.getQuery());
|
||||
this.keywordQuery = keywordQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with keyword string to process
|
||||
* @param queryStr Keyword to search for
|
||||
*/
|
||||
public LuceneQuery(String queryStr) {
|
||||
this.query = queryStr;
|
||||
this.queryEscaped = queryStr;
|
||||
this.keywordString = queryStr;
|
||||
this.keywordStringEscaped = queryStr;
|
||||
isEscaped = false;
|
||||
}
|
||||
|
||||
@ -84,7 +96,7 @@ public class LuceneQuery implements KeywordSearchQuery {
|
||||
|
||||
@Override
|
||||
public void escape() {
|
||||
queryEscaped = KeywordSearchUtil.escapeLuceneQuery(query);
|
||||
keywordStringEscaped = KeywordSearchUtil.escapeLuceneQuery(keywordString);
|
||||
isEscaped = true;
|
||||
}
|
||||
|
||||
@ -100,12 +112,12 @@ public class LuceneQuery implements KeywordSearchQuery {
|
||||
|
||||
@Override
|
||||
public String getEscapedQueryString() {
|
||||
return this.queryEscaped;
|
||||
return this.keywordStringEscaped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQueryString() {
|
||||
return this.query;
|
||||
return this.keywordString;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -117,7 +129,7 @@ public class LuceneQuery implements KeywordSearchQuery {
|
||||
public Map<String, List<ContentHit>> performQuery() throws NoOpenCoreException {
|
||||
Map<String, List<ContentHit>> results = new HashMap<String, List<ContentHit>>();
|
||||
//in case of single term literal query there is only 1 term
|
||||
results.put(query, performLuceneQuery());
|
||||
results.put(keywordString, performLuceneQuery());
|
||||
|
||||
return results;
|
||||
}
|
||||
@ -125,7 +137,7 @@ public class LuceneQuery implements KeywordSearchQuery {
|
||||
|
||||
@Override
|
||||
public boolean validate() {
|
||||
return query != null && !query.equals("");
|
||||
return keywordString != null && !keywordString.equals("");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -192,7 +204,7 @@ public class LuceneQuery implements KeywordSearchQuery {
|
||||
q.setShowDebugInfo(DEBUG); //debug
|
||||
|
||||
//set query, force quotes/grouping around all literal queries
|
||||
final String groupedQuery = KeywordSearchUtil.quoteQuery(queryEscaped);
|
||||
final String groupedQuery = KeywordSearchUtil.quoteQuery(keywordStringEscaped);
|
||||
String theQueryStr = groupedQuery;
|
||||
if (field != null) {
|
||||
//use the optional field
|
||||
@ -262,10 +274,10 @@ public class LuceneQuery implements KeywordSearchQuery {
|
||||
|
||||
|
||||
} 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;
|
||||
} 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -67,8 +67,8 @@ import org.apache.solr.client.solrj.impl.XMLResponseParser;
|
||||
*/
|
||||
public class Server {
|
||||
|
||||
// field names that are used in SOLR schema
|
||||
public static enum Schema {
|
||||
|
||||
ID {
|
||||
@Override
|
||||
public String toString() {
|
||||
@ -99,24 +99,28 @@ public class Server {
|
||||
return "file_name";
|
||||
}
|
||||
},
|
||||
// note that we no longer index this field
|
||||
CTIME {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ctime";
|
||||
}
|
||||
},
|
||||
// note that we no longer index this field
|
||||
ATIME {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "atime";
|
||||
}
|
||||
},
|
||||
// note that we no longer index this field
|
||||
MTIME {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "mtime";
|
||||
}
|
||||
},
|
||||
// note that we no longer index this field
|
||||
CRTIME {
|
||||
@Override
|
||||
public String toString() {
|
||||
@ -151,7 +155,7 @@ public class Server {
|
||||
static final int DEFAULT_SOLR_STOP_PORT = 34343;
|
||||
private int currentSolrServerPort = 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 {
|
||||
|
||||
@ -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
|
||||
* @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 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) {
|
||||
final SolrQuery q = new SolrQuery();
|
||||
q.setQuery("*:*");
|
||||
|
@ -41,6 +41,10 @@ import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
||||
import org.sleuthkit.datamodel.TskException;
|
||||
|
||||
|
||||
/**
|
||||
* Performs a regular expression query to the SOLR/Lucene instance.
|
||||
*/
|
||||
public class TermComponentQuery implements KeywordSearchQuery {
|
||||
|
||||
private static final int TERMS_UNLIMITED = -1;
|
||||
|
@ -58,6 +58,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
||||
import org.sleuthkit.datamodel.DerivedFile;
|
||||
import org.sleuthkit.datamodel.ReadContentInputStream;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
/**
|
||||
* 7Zip ingest module Extracts supported archives, adds extracted DerivedFiles,
|
||||
@ -165,6 +166,16 @@ public final class SevenZipIngestModule extends IngestModuleAbstractFile {
|
||||
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)) {
|
||||
//do not process dirs and files that are not supported
|
||||
return ProcessResult.OK;
|
||||
|
@ -4,20 +4,21 @@
|
||||
<property name="TSK_BUILD_TYPE">Release</property>
|
||||
|
||||
<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}"
|
||||
property="aiPath"
|
||||
property="ai-exe-path"
|
||||
value="${AI.path}"/>
|
||||
</target>
|
||||
|
||||
<target name="inputAIPath" unless="aiPath">
|
||||
<input addProperty="aiPath"
|
||||
<target name="inputAIPath" unless="ai-exe-path">
|
||||
<input addProperty="ai-exe-path"
|
||||
message="Enter the location of AdvancedInstaller.com"/>
|
||||
</target>
|
||||
|
||||
<target name="run-advanced-installer" depends="autoAIPath,inputAIPath">
|
||||
<fail unless="aiPath" message="Could not locate Advanced Installer."/>
|
||||
<copy file="${basedir}/installer_${app.name}/installer_${app.name}.aip" tofile="${nbdist.dir}/installer_${app.name}.aip"/>
|
||||
<fail unless="ai-exe-path" message="Could not locate Advanced Installer."/>
|
||||
<!-- 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">
|
||||
<attribute name="property" />
|
||||
<![CDATA[
|
||||
@ -28,87 +29,93 @@
|
||||
</scriptdef>
|
||||
<generateguid property="guid1" />
|
||||
<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 -->
|
||||
<echo>Product Code: ${guid1}</echo>
|
||||
<replaceregexp file="${proj-path}"
|
||||
<echo>Product Code: ${guid1}</echo>
|
||||
<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" Value="(\d{4}+:.)\w{8}+-\w{4}+-\w{4}+-\w{4}+-\w{12}+"
|
||||
replace="ProductCode" Value="\1${guid1}" />
|
||||
<echo>Product Version: ${app.version}</echo>
|
||||
<replaceregexp file="${proj-path}"
|
||||
|
||||
<replaceregexp file="${aip-path}"
|
||||
match="ProductVersion" Value="\d+\.{1}\d+\.{1}\d+"
|
||||
replace="ProductVersion" Value="${app.version}" />
|
||||
|
||||
<!-- Use Advanced Installer to configure files to add -->
|
||||
<echo message="Adding files to installer..."/>
|
||||
<exec executable="${aiPath}">
|
||||
<arg line="/edit ${proj-path} /AddFolder APPDIR ${inst-path}\bin"/>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /AddFolder APPDIR ${inst-path}\bin"/>
|
||||
</exec>
|
||||
<exec executable="${aiPath}">
|
||||
<arg line="/edit ${proj-path} /AddFolder APPDIR ${inst-path}\etc"/>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /AddFolder APPDIR ${inst-path}\etc"/>
|
||||
</exec>
|
||||
<exec executable="${aiPath}">
|
||||
<arg line="/edit ${proj-path} /AddFolder APPDIR ${inst-path}\gstreamer"/>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /AddFolder APPDIR ${inst-path}\gstreamer"/>
|
||||
</exec>
|
||||
<exec executable="${aiPath}">
|
||||
<arg line="/edit ${proj-path} /AddFolder APPDIR ${inst-path}\harness"/>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /AddFolder APPDIR ${inst-path}\harness"/>
|
||||
</exec>
|
||||
<exec executable="${aiPath}">
|
||||
<arg line="/edit ${proj-path} /AddFolder APPDIR ${inst-path}\java"/>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /AddFolder APPDIR ${inst-path}\java"/>
|
||||
</exec>
|
||||
<exec executable="${aiPath}">
|
||||
<arg line="/edit ${proj-path} /AddFolder APPDIR ${inst-path}\jre"/>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /AddFolder APPDIR ${inst-path}\jre"/>
|
||||
</exec>
|
||||
<exec executable="${aiPath}">
|
||||
<arg line="/edit ${proj-path} /AddFolder APPDIR ${inst-path}\platform"/>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /AddFolder APPDIR ${inst-path}\platform"/>
|
||||
</exec>
|
||||
<exec executable="${aiPath}">
|
||||
<arg line="/edit ${proj-path} /AddFolder APPDIR ${inst-path}\${app.name}"/>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /AddFolder APPDIR ${inst-path}\${app.name}"/>
|
||||
</exec>
|
||||
<exec executable="${aiPath}">
|
||||
<arg line="/edit ${proj-path} /AddFile APPDIR ${inst-path}\icon.ico"/>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /AddFile APPDIR ${inst-path}\icon.ico"/>
|
||||
</exec>
|
||||
<exec executable="${aiPath}">
|
||||
<arg line="/edit ${proj-path} /AddFile APPDIR ${inst-path}\KNOWN_ISSUES.txt"/>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /AddFile APPDIR ${inst-path}\KNOWN_ISSUES.txt"/>
|
||||
</exec>
|
||||
<exec executable="${aiPath}">
|
||||
<arg line="/edit ${proj-path} /AddFile APPDIR ${inst-path}\LICENSE-2.0.txt"/>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /AddFile APPDIR ${inst-path}\LICENSE-2.0.txt"/>
|
||||
</exec>
|
||||
<exec executable="${aiPath}">
|
||||
<arg line="/edit ${proj-path} /AddFile APPDIR ${inst-path}\NEWS.txt"/>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /AddFile APPDIR ${inst-path}\NEWS.txt"/>
|
||||
</exec>
|
||||
<exec executable="${aiPath}">
|
||||
<arg line="/edit ${proj-path} /AddFile APPDIR ${inst-path}\README.txt"/>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /AddFile APPDIR ${inst-path}\README.txt"/>
|
||||
</exec>
|
||||
|
||||
<!-- Need to find a way to deal with beta version -->
|
||||
<!--<echo message="Setting ${app.name} version to ${app.version}..."/>
|
||||
<exec executable="${aiPath}">
|
||||
<arg line="/edit ${proj-path} /SetVersion ${app.version}"/>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /SetVersion ${app.version}"/>
|
||||
</exec>-->
|
||||
|
||||
<echo message="Adding desktop/menu shortcuts..."/>
|
||||
<exec executable="${aiPath}">
|
||||
<arg line="/edit ${proj-path} /NewShortcut -name ${app.title} -dir DesktopFolder -target APPDIR\bin\${app.name}.exe -icon ${inst-path}\icon.ico"/>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /NewShortcut -name ${app.title} -dir DesktopFolder -target APPDIR\bin\${app.name}.exe -icon ${inst-path}\icon.ico"/>
|
||||
</exec>
|
||||
<exec executable="${aiPath}">
|
||||
<arg line="/edit ${proj-path} /NewShortcut -name ${app.title} -dir SHORTCUTDIR -target APPDIR\bin\${app.name}.exe -icon ${inst-path}\icon.ico"/>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /NewShortcut -name ${app.title} -dir SHORTCUTDIR -target APPDIR\bin\${app.name}.exe -icon ${inst-path}\icon.ico"/>
|
||||
</exec>
|
||||
|
||||
<echo message="Setting environment variables..."/>
|
||||
<exec executable="${aiPath}">
|
||||
<arg line="/edit ${proj-path} /NewEnvironment -name GSTREAMER_PATH -value [APPDIR]gstreamer\bin -install_operation CreateUpdate -behavior Append -system_variable"/>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /NewEnvironment -name GSTREAMER_PATH -value [APPDIR]gstreamer\bin -install_operation CreateUpdate -behavior Append -system_variable"/>
|
||||
</exec>
|
||||
<exec executable="${aiPath}">
|
||||
<arg line="/edit ${proj-path} /NewEnvironment -name GSTREAMER_PATH -value [APPDIR]gstreamer\lib\gstreamer-0.10 -install_operation CreateUpdate -behavior Append -system_variable"/>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<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 executable="${aiPath}">
|
||||
<arg line="/edit ${proj-path} /NewEnvironment -name PATH -value %GSTREAMER_PATH% -install_operation CreateUpdate -behavior Append -system_variable"/>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /NewEnvironment -name PATH -value %GSTREAMER_PATH% -install_operation CreateUpdate -behavior Append -system_variable"/>
|
||||
</exec>
|
||||
<exec executable="${aiPath}">
|
||||
<arg line="/build ${proj-path}"/>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/build ${aip-path}"/>
|
||||
</exec>
|
||||
<delete file="${proj-path}"/>
|
||||
<!--<delete file="${aip-path}"/>-->
|
||||
</target>
|
||||
|
||||
<!-- Makes an installer from the opened ZIP file -->
|
||||
<target name="build-installer-windows">
|
||||
<antcall target="run-advanced-installer" />
|
||||
<!--<delete dir="${nbdist.dir}/${app.name}-installer"/>-->
|
||||
|
@ -4,8 +4,6 @@
|
||||
any type of module. Information about specific types of modules should
|
||||
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.
|
||||
|
||||
\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.
|
||||
|
||||
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.
|
||||
|
||||
TODO: @@@ Add link to our wiki with Autopsy's versioning scheme
|
||||
|
||||
|
||||
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.
|
||||
|
||||
\subsection mod_dev_mod_other Other Links
|
||||
|
||||
|
@ -48,6 +48,7 @@ blackboard and with inbox messages to the user.
|
||||
\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.
|
||||
You can also refer to org.sleuthkit.autopsy.examples.SampleDataSourceIngestModule as an example module.
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
The same file-level module instance will be used for files in different images and even different cases if new cases are opened.
|
||||
|
@ -1,31 +1,51 @@
|
||||
/*! \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>
|
||||
<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.
|
||||
\image html viewer_image.jpg "Module Viewer Areas"
|
||||
|
||||
<ol>
|
||||
<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>
|
||||
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>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.
|
||||
|
||||
*/
|
||||
|
@ -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.
|
||||
- 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.
|
||||
- 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
|
||||
|
@ -820,18 +820,16 @@ def usage():
|
||||
return \
|
||||
"""
|
||||
USAGE:
|
||||
Run this script to generate a jdiff XML summary for every module
|
||||
in the current Autopsy source and in a previous source specified
|
||||
by the given tag. Then, compare the XML files to see which modules
|
||||
need updated version numbers. If the dry run tag is not given, the
|
||||
module numbers will be automatically updated.
|
||||
Compares the API of the current Autopsy source code with a previous
|
||||
tagged version. By default, it will detect the previous tag from
|
||||
the NEWS file and will not update the versions in the source code.
|
||||
|
||||
OPTIONAL FLAGS:
|
||||
-t --tag The tag name in git. Otherwise the NEWS file in source
|
||||
will be used to determine the previous tag.
|
||||
-t --tag Specify a previous tag to compare to.
|
||||
Otherwise the NEWS file will be used.
|
||||
|
||||
-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.
|
||||
|
||||
@ -904,6 +902,7 @@ def main():
|
||||
printt("Comparing jdiff outputs...")
|
||||
for module in similar_modules:
|
||||
module.set_ret(compare_xml(module, apiname_tag, apiname_cur))
|
||||
print("Refer to the jdiff-javadocs folder for more details")
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# 1) Do versioning
|
||||
|
Loading…
x
Reference in New Issue
Block a user