1
0
mirror of https://github.com/elisspace/autopsy.git synced 2026-09-06 02:24:30 +00:00

Merge remote-tracking branch 'upstream/develop' into timingTest

This commit is contained in:
alexjacks92
2014-06-06 13:39:30 -04:00
47 changed files with 1973 additions and 195 deletions

View File

@@ -119,7 +119,13 @@ public class Case implements SleuthkitCase.ErrorObserver {
* closed, the "new value" will be null and the "old value" will be the
* instance of the Case object being closed.
*/
CURRENT_CASE;
CURRENT_CASE,
/**
* Name for property change events fired when a report is added to the
* case. The old value supplied by the event object is null and the new
* value is a reference to a Report object representing the new report.
*/
REPORT_ADDED;
};
private String name;
@@ -1164,4 +1170,27 @@ public class Case implements SleuthkitCase.ErrorObserver {
public void receiveError(String context, String errorMessage) {
MessageNotifyUtil.Notify.error(context, errorMessage);
}
/**
* Adds a report to the case.
*
* @param [in] localPath The path of the report file, must be in the case directory or one of its subdirectories.
* @param [in] sourceModuleName The name of the module that created the report.
* @param [in] reportName The report name, may be empty.
* @return A Report data transfer object (DTO) for the new row.
* @throws TskCoreException
*/
public void addReport(String localPath, String srcModuleName, String reportName) throws TskCoreException {
Report report = this.db.addReport(localPath, srcModuleName, reportName);
try {
Case.pcs.firePropertyChange(Events.REPORT_ADDED.toString(), null, report);
} catch (Exception ex) {
String errorMessage = String.format("A Case %s listener threw an exception", Events.REPORT_ADDED.toString());
logger.log(Level.SEVERE, errorMessage, ex);
}
}
public List<Report> getAllReports() throws TskCoreException {
return this.db.getAllReports();
}
}

View File

@@ -68,11 +68,17 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener{
/**
* Gets the base directory that the user typed on the base directory text field.
* Will add file separator if it was not added.
*
* @return baseDirectory the base directory from the case dir text field
*/
public String getCaseParentDir(){
return this.caseParentDirTextField.getText();
String parentDir = this.caseParentDirTextField.getText();
if (parentDir.endsWith(File.separator) == false) {
parentDir = parentDir + File.separator;
}
return parentDir;
}
public JTextField getCaseParentDirTextField(){
@@ -244,11 +250,11 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener{
*/
public void updateUI(DocumentEvent e) {
String caseName = this.caseNameTextField.getText();
String caseDir = this.caseParentDirTextField.getText();
String caseName = getCaseName();
String parentDir = getCaseParentDir();
if(!caseName.equals("") && !caseDir.equals("")){
caseDirTextField.setText( caseDir + File.separator + caseName);
if(!caseName.equals("") && !parentDir.equals("")){
caseDirTextField.setText( parentDir + caseName);
wizPanel.setIsFinish(true);
}
else{

View File

@@ -202,7 +202,7 @@ class NewCaseWizardPanel1 implements WizardDescriptor.ValidatingPanel<WizardDesc
public void validate() throws WizardValidationException {
String caseName = getComponent().getCaseName();
String caseParentDir = getComponent().getCaseParentDir();
String caseDirPath = caseParentDir + File.separator + caseName;
String caseDirPath = caseParentDir + caseName;
// check if case Name contain one of this following symbol:
// \ / : * ? " < > |

View File

@@ -158,7 +158,7 @@ public class FileManager implements Closeable {
*
* @param fileName file name the derived file
* @param localPath local path of the derived file, including the file
* name. The path is relative to the database path.
* name. The path is relative to the case folder.
* @param size size of the derived file in bytes
* @param ctime
* @param crtime

View File

@@ -11,6 +11,7 @@ Metadata.tableRowTitle.md5=MD5
Metadata.tableRowTitle.hashLookupResults=Hash Lookup Results
Metadata.tableRowTitle.internalid=Internal ID
Metadata.tableRowTitle.localPath=Local Path
Metadata.tableRowTitle.type=Type
Metadata.title=Metadata
Metadata.toolTip=Displays metadata about the file.
Metadata.nodeText.nonFilePassedIn=Non-file passed in

View File

@@ -1,16 +1,17 @@
Metadata.tableRowTitle.name=\u540D\u79F0
Metadata.tableRowTitle.size=\u30B5\u30A4\u30BA
Metadata.tableRowTitle.fileNameAlloc=\u30D5\u30A1\u30A4\u30EB\u30A2\u30ED\u30B1\u30FC\u30B7\u30E7\u30F3\u72B6\u614B
Metadata.tableRowTitle.metadataAlloc=\u30E1\u30BF\u30C7\u30FC\u30BF\u30A2\u30ED\u30B1\u30FC\u30B7\u30E7\u30F3\u72B6\u614B
Metadata.tableRowTitle.modified=\u4FEE\u6B63\u6E08\u307F
Metadata.tableRowTitle.accessed=\u30A2\u30AF\u30BB\u30B9\u6E08\u307F
Metadata.tableRowTitle.created=\u4F5C\u6210\u6E08\u307F
Metadata.tableRowTitle.changed=\u5909\u66F4\u6E08\u307F
Metadata.tableRowContent.md5notCalc=\u672A\u8A08\u7B97
Metadata.tableRowTitle.name=\u540d\u79f0
Metadata.tableRowTitle.size=\u30b5\u30a4\u30ba
Metadata.tableRowTitle.fileNameAlloc=\u30d5\u30a1\u30a4\u30eb\u30a2\u30ed\u30b1\u30fc\u30b7\u30e7\u30f3\u72b6\u614b
Metadata.tableRowTitle.metadataAlloc=\u30e1\u30bf\u30c7\u30fc\u30bf\u30a2\u30ed\u30b1\u30fc\u30b7\u30e7\u30f3\u72b6\u614b
Metadata.tableRowTitle.modified=\u4fee\u6b63\u6e08\u307f
Metadata.tableRowTitle.accessed=\u30a2\u30af\u30bb\u30b9\u6e08\u307f
Metadata.tableRowTitle.created=\u4f5c\u6210\u6e08\u307f
Metadata.tableRowTitle.changed=\u5909\u66f4\u6e08\u307f
Metadata.tableRowContent.md5notCalc=\u672a\u8a08\u7b97
Metadata.tableRowTitle.md5=MD5
Metadata.tableRowTitle.hashLookupResults=\u30CF\u30C3\u30B7\u30E5\u30EB\u30C3\u30AF\u30A2\u30C3\u30D7\u7D50\u679C
Metadata.tableRowTitle.internalid=\u5185\u90E8ID
Metadata.tableRowTitle.localPath=\u30ED\u30FC\u30AB\u30EB\u30D1\u30B9
Metadata.title=\u30E1\u30BF\u30C7\u30FC\u30BF
Metadata.toolTip=\u30D5\u30A1\u30A4\u30EB\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u8868\u793A\u3057\u307E\u3059\u3002
Metadata.nodeText.nonFilePassedIn=\u51E6\u7406\u4E2D\u306E\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u306F\u30D5\u30A1\u30A4\u30EB\u3067\u306F\u3042\u308A\u307E\u305B\u3093
Metadata.tableRowTitle.hashLookupResults=\u30cf\u30c3\u30b7\u30e5\u30eb\u30c3\u30af\u30a2\u30c3\u30d7\u7d50\u679c
Metadata.tableRowTitle.internalid=\u5185\u90e8ID
Metadata.tableRowTitle.localPath=\u30ed\u30fc\u30ab\u30eb\u30d1\u30b9
Metadata.tableRowTitle.type=Type
Metadata.title=\u30e1\u30bf\u30c7\u30fc\u30bf
Metadata.toolTip=\u30d5\u30a1\u30a4\u30eb\u306e\u30e1\u30bf\u30c7\u30fc\u30bf\u3092\u8868\u793a\u3057\u307e\u3059\u3002
Metadata.nodeText.nonFilePassedIn=\u51e6\u7406\u4e2d\u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306f\u30d5\u30a1\u30a4\u30eb\u3067\u306f\u3042\u308a\u307e\u305b\u3093

View File

@@ -24,7 +24,6 @@ import org.openide.nodes.Node;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.TskCoreException;
@@ -135,7 +134,8 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer
} catch (TskCoreException ex) {
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.name"), file.getParentPath() + "/" + file.getName());
}
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.type"), file.getType().getName());
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.size"), new Long(file.getSize()).toString() );
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.fileNameAlloc"), file.getDirFlagAsString());
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.metadataAlloc"), file.getMetaFlagsAsString());

View File

@@ -0,0 +1,56 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 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.coreutils;
/**
* Encapsulates an error message and an associated exception, if any.
*/
final public class ErrorInfo {
private final String errorSource;
private final String message;
private final Exception exception;
public ErrorInfo(String errorSource, String message) {
this.errorSource = errorSource;
this.message = message;
this.exception = null;
}
public ErrorInfo(String errorSource, String message, Exception exception) {
this.errorSource = errorSource;
this.message = message;
this.exception = exception;
}
public String getErrroSource() {
return this.errorSource;
}
public String getMessage() {
return this.message;
}
public boolean hasException() {
return exception != null;
}
public Exception getException() {
return this.exception;
}
}

View File

@@ -126,12 +126,12 @@ public class XMLUtil {
DocumentBuilder builder = builderFactory.newDocumentBuilder();
ret = builder.parse(new FileInputStream(xmlPath));
} catch (ParserConfigurationException e) {
Logger.getLogger(clazz.getName()).log(Level.SEVERE, "Error loading XML file: can't initialize parser.", e); //NON-NLS
Logger.getLogger(clazz.getName()).log(Level.SEVERE, "Error loading XML file " + xmlPath + " : can't initialize parser.", e); //NON-NLS
} catch (SAXException e) {
Logger.getLogger(clazz.getName()).log(Level.SEVERE, "Error loading XML file: can't parse XML.", e); //NON-NLS
Logger.getLogger(clazz.getName()).log(Level.SEVERE, "Error loading XML file " + xmlPath + " : can't parse XML.", e); //NON-NLS
} catch (IOException e) {
//error reading file
Logger.getLogger(clazz.getName()).log(Level.SEVERE, "Error loading XML file: can't read file.", e); //NON-NLS
Logger.getLogger(clazz.getName()).log(Level.SEVERE, "Error loading XML file " + xmlPath + " : can't read file.", e); //NON-NLS
}
return ret;
}
@@ -144,7 +144,6 @@ public class XMLUtil {
* @param xsdPath the full path to the file to validate against
*/
public static <T> Document loadDoc(Class<T> clazz, String xmlPath, String xsdPath) {
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
Document ret = loadDoc(clazz, xmlPath);
if (!XMLUtil.xmlIsValid(ret, clazz, xsdPath)) {
Logger.getLogger(clazz.getName()).log(Level.WARNING, "Error loading XML file: could not validate against [{0}], results may not be accurate", xsdPath); //NON-NLS

View File

@@ -113,7 +113,11 @@ abstract class AbstractContentChildren<T> extends Keys<T> {
}
/**
* Creates appropriate Node for each supported artifact category / grouping
* Gets a DisplayableItemNode for use as a subtree root node for the Autopsy
* tree view from each type of AutopsyVisitableItem visited. There are
* AutopsyVisitableItems for the Data Sources, Views, Results, and Reports
* subtrees, and for the subtrees of Results (e.g., Extracted Content,
* Hash Set Hits, etc.).
*/
static class CreateAutopsyNodeVisitor extends AutopsyItemVisitor.Default<AbstractNode> {
@@ -186,6 +190,11 @@ abstract class AbstractContentChildren<T> extends Keys<T> {
return new ResultsNode(r.getSleuthkitCase());
}
@Override
public AbstractNode visit(Reports reportsItem) {
return new Reports.ReportsListNode();
}
@Override
protected AbstractNode defaultVisit(AutopsyVisitableItem di) {
throw new UnsupportedOperationException(

View File

@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,6 @@
*/
package org.sleuthkit.autopsy.datamodel;
/**
*/
interface AutopsyItemVisitor<T> {
T visit(ExtractedContent ec);
@@ -59,7 +57,9 @@ package org.sleuthkit.autopsy.datamodel;
T visit(Views v);
T visit(Results r);
T visit(Reports reportsItem);
static abstract public class Default<T> implements AutopsyItemVisitor<T> {
protected abstract T defaultVisit(AutopsyVisitableItem ec);
@@ -157,5 +157,10 @@ package org.sleuthkit.autopsy.datamodel;
public T visit(Results r) {
return defaultVisit(r);
}
@Override
public T visit(Reports reportsItem) {
return defaultVisit(reportsItem);
}
}
}

View File

@@ -194,6 +194,12 @@ LocalFileNode.createSheet.noDescr.text=no description
LocalFileNode.getActions.viewInNewWin.text=View in New Window
LocalFileNode.getActions.openInExtViewer.text=Open in External Viewer
LocalFileNode.getActions.searchFilesSameMd5.text=Search for files with the same MD5 hash
OpenReportAction.actionDisplayName=Open Report
OpenReportAction.actionPerformed.MessageBoxTitle=Open Report Failure
OpenReportAction.actionPerformed.NoAssociatedEditorMessage=There is no associated editor for reports of this type or the associated application failed to launch.
OpenReportAction.actionPerformed.NoOpenInEditorSupportMessage=This platform (operating system) does not support opening a file in an editor this way.
OpenReportAction.actionPerformed.MissingReportFileMessage=The report file no longer exists.
OpenReportAction.actionPerformed.ReportFileOpenPermissionDeniedMessage=Permission to open the report file was denied.
RecentFiles.aut0DayFilter.displayName.text=Final Day
RecentFiles.aut1dayFilter.displayName.text=Final Day - 1
RecentFiles.aut2dayFilter.displayName.text=Final Day - 2
@@ -209,6 +215,16 @@ RecentFilesNode.createSheet.name.name=Name
RecentFilesNode.createSheet.name.displayName=Name
RecentFilesNode.createSheet.name.desc=no description
RecentFilesNode.name.text=Recent Files
ReportNode.sourceModuleNameProperty.name=Source Module Name
ReportNode.sourceModuleNameProperty.displayName=Source Module Name
ReportNode.sourceModuleNameProperty.desc=Name of the module that created the report
ReportNode.createdTimeProperty.name=Created Time
ReportNode.createdTimeProperty.displayName=Created Time
ReportNode.createdTimeProperty.desc=Time report was created
ReportNode.pathProperty.name=Report File Path
ReportNode.pathProperty.displayName=Report File Path
ReportNode.pathProperty.desc=Local path of the report file
ReportsListNode.displayName=Reports
ResultsNode.name.text=Results
ResultsNode.createSheet.name.name=Name
ResultsNode.createSheet.name.displayName=Name

View File

@@ -102,6 +102,10 @@ public interface DisplayableItemNodeVisitor<T> {
T visit(VirtualDirectoryNode ldn);
T visit(Reports.ReportsListNode reportsNode);
T visit(Reports.ReportNode reportNode);
/**
* Visitor with an implementable default behavior for all types. Override
* specific visit types to not use the default behavior.
@@ -302,5 +306,15 @@ public interface DisplayableItemNodeVisitor<T> {
public T visit(BlackboardArtifactTagNode node) {
return defaultVisit(node);
}
@Override
public T visit(Reports.ReportsListNode node) {
return defaultVisit(node);
}
@Override
public T visit(Reports.ReportNode node) {
return defaultVisit(node);
}
}
}

View File

@@ -0,0 +1,224 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 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.datamodel;
import java.awt.Desktop;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JOptionPane;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.Report;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Implements the Reports subtree of the Autopsy tree.
*/
public final class Reports implements AutopsyVisitableItem {
private static final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
@Override
public <T> T accept(AutopsyItemVisitor<T> visitor) {
// CreateAutopsyNodeVisitor.visit() constructs a ReportsListNode.
return visitor.visit(this);
}
/**
* The root node of the Reports subtree of the Autopsy tree.
*/
public static final class ReportsListNode extends DisplayableItemNode {
private static final String DISPLAY_NAME = NbBundle.getMessage(ReportsListNode.class, "ReportsListNode.displayName");
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/report_16.png"; //NON-NLS
public ReportsListNode() {
super(Children.create(new ReportNodeFactory(), true));
setName(DISPLAY_NAME);
setDisplayName(DISPLAY_NAME);
this.setIconBaseWithExtension(ICON_PATH);
}
@Override
public boolean isLeafTypeNode() {
return true;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
// - GetPopupActionsDisplayableItemNodeVisitor.visit() returns null.
// - GetPreferredActionsDisplayableItemNodeVisitor.visit() returns null.
// - IsLeafItemVisitor.visit() returns false.
// - ShowItemVisitor.visit() returns true.
return visitor.visit(this);
}
}
/**
* The child node factory that creates ReportNode children for a
* ReportsListNode.
*/
private static final class ReportNodeFactory extends ChildFactory<Report> {
ReportNodeFactory() {
Case.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (eventType.equals(Case.Events.REPORT_ADDED.toString())) {
ReportNodeFactory.this.refresh(true);
}
}
});
}
@Override
protected boolean createKeys(List<Report> keys) {
try {
keys.addAll(Case.getCurrentCase().getAllReports());
} catch (TskCoreException ex) {
Logger.getLogger(Reports.ReportNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get reports", ex); //NON-NLS
}
return true;
}
@Override
protected Node createNodeForKey(Report key) {
return new ReportNode(key);
}
}
/**
* A leaf node in the Reports subtree of the Autopsy tree, wraps a Report
* object.
*/
public static final class ReportNode extends DisplayableItemNode {
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/report_16.png"; //NON-NLS
private final Report report;
ReportNode(Report report) {
super(Children.LEAF, Lookups.fixed(report));
this.report = report;
super.setName(this.report.getSourceModuleName());
super.setDisplayName(this.report.getSourceModuleName());
this.setIconBaseWithExtension(ICON_PATH);
}
@Override
public boolean isLeafTypeNode() {
return true;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
// - GetPopupActionsDisplayableItemNodeVisitor.visit() calls getActions().
// - GetPreferredActionsDisplayableItemNodeVisitor.visit() calls getPreferredAction().
// - IsLeafItemVisitor.visit() returns true.
// - ShowItemVisitor.visit() returns true.
return visitor.visit(this);
}
@Override
protected Sheet createSheet() {
Sheet sheet = super.createSheet();
Sheet.Set propertiesSet = sheet.get(Sheet.PROPERTIES);
if (propertiesSet == null) {
propertiesSet = Sheet.createPropertiesSet();
sheet.put(propertiesSet);
}
propertiesSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ReportNode.sourceModuleNameProperty.name"),
NbBundle.getMessage(this.getClass(), "ReportNode.sourceModuleNameProperty.displayName"),
NbBundle.getMessage(this.getClass(), "ReportNode.sourceModuleNameProperty.desc"),
this.report.getSourceModuleName()));
propertiesSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ReportNode.createdTimeProperty.name"),
NbBundle.getMessage(this.getClass(), "ReportNode.createdTimeProperty.displayName"),
NbBundle.getMessage(this.getClass(), "ReportNode.createdTimeProperty.desc"),
dateFormatter.format(new java.util.Date(this.report.getCreatedTime() * 1000)).toString()));
propertiesSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ReportNode.pathProperty.name"),
NbBundle.getMessage(this.getClass(), "ReportNode.pathProperty.displayName"),
NbBundle.getMessage(this.getClass(), "ReportNode.pathProperty.desc"),
this.report.getPath()));
return sheet;
}
@Override
public Action[] getActions(boolean popup) {
List<Action> actions = new ArrayList<>();
actions.addAll(Arrays.asList(super.getActions(true)));
actions.add(new OpenReportAction());
return actions.toArray(new Action[actions.size()]);
}
@Override
public AbstractAction getPreferredAction() {
return new OpenReportAction();
}
private final class OpenReportAction extends AbstractAction {
private OpenReportAction() {
super(NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionDisplayName"));
}
@Override
public void actionPerformed(ActionEvent e) {
File file = new File(ReportNode.this.report.getPath());
try {
Desktop.getDesktop().open(file);
} catch (IOException ex) {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.NoAssociatedEditorMessage"),
NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.MessageBoxTitle"),
JOptionPane.ERROR_MESSAGE);
} catch (UnsupportedOperationException ex) {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.NoOpenInEditorSupportMessage"),
NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.MessageBoxTitle"),
JOptionPane.ERROR_MESSAGE);
} catch (IllegalArgumentException ex) {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.MissingReportFileMessage"),
NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.MessageBoxTitle"),
JOptionPane.ERROR_MESSAGE);
} catch (SecurityException ex) {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.ReportFileOpenPermissionDeniedMessage"),
NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.MessageBoxTitle"),
JOptionPane.ERROR_MESSAGE);
}
}
}
}
}

View File

@@ -66,6 +66,7 @@ import org.sleuthkit.autopsy.datamodel.RecentFilesFilterNode;
import org.sleuthkit.autopsy.datamodel.RecentFilesNode;
import org.sleuthkit.autopsy.datamodel.FileTypesNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits;
import org.sleuthkit.autopsy.datamodel.Reports;
import org.sleuthkit.autopsy.datamodel.Tags;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
@@ -307,6 +308,12 @@ public class DataResultFilterNode extends FilterNode {
return actions;
}
@Override
public List<Action> visit(Reports.ReportsListNode ditem) {
// The base class Action is "Collapse All", inappropriate.
return null;
}
@Override
protected List<Action> defaultVisit(DisplayableItemNode ditem) {
//preserve the default node's actions
@@ -522,6 +529,11 @@ public class DataResultFilterNode extends FilterNode {
return openChild(khmln);
}
@Override
public AbstractAction visit(Reports.ReportNode reportNode) {
return reportNode.getPreferredAction();
}
@Override
protected AbstractAction defaultVisit(DisplayableItemNode c) {
return null;

View File

@@ -74,6 +74,7 @@ import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskException;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.datamodel.ExtractedContent;
import org.sleuthkit.autopsy.datamodel.Reports;
/**
* Top component which displays something.
@@ -358,6 +359,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
items.add(new DataSources(tskCase));
items.add(new Views(tskCase));
items.add(new Results(tskCase));
items.add(new Reports());
contentChildren = new RootContentChildren(items);
Node root = new AbstractNode(contentChildren) {
/**

View File

@@ -2,3 +2,5 @@ SampleContentViewer.jLabel1.text=jLabel1
SampleIngestModuleFactory.moduleName=Sample Ingest Module
SampleIngestModuleFactory.moduleDescription=This module serves as a sample ingest module for software developers.
SampleIngestModuleIngestJobSettingsPanel.skipKnownFilesCheckBox.text=Skip Known Files (NSRL)
SampleExecutableIngestModuleFactory.moduleName=Sample Executable Ingest Module
SampleExecutableIngestModuleFactory.moduleDescription=This module serves as a sample executable ingest module for software developers.

View File

@@ -0,0 +1,379 @@
/*
* 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.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.ErrorInfo;
import org.sleuthkit.autopsy.coreutils.ExecUtil;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.externalresults.ExternalResults;
import org.sleuthkit.autopsy.externalresults.ExternalResultsImporter;
import org.sleuthkit.autopsy.externalresults.ExternalResultsXMLParser;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.autopsy.ingest.IngestMessage;
import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Sample data source ingest module that doesn't do much. Demonstrates use of
* utility classes: ExecUtils and the org.sleuthkit.autopsy.externalresults
* package.
*/
public class SampleExecutableDataSourceIngestModule implements DataSourceIngestModule {
private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter();
private static final String moduleName = SampleExecutableIngestModuleFactory.getModuleName();
private final String fileInCaseDatabase = "/WINDOWS/system32/ntmsapi.dll"; // Probably
private long jobId;
private String outputDirPath;
private String derivedFileInCaseDatabase;
@Override
public void startUp(IngestJobContext context) throws IngestModuleException {
jobId = context.getJobId();
if (refCounter.incrementAndGet(jobId) == 1) {
// Create an output directory for this job.
outputDirPath = Case.getCurrentCase().getModulesOutputDirAbsPath() + File.separator + moduleName; //NON-NLS
File outputDir = new File(outputDirPath);
if (outputDir.exists() == false) {
outputDir.mkdirs();
}
}
}
@Override
public ProcessResult process(Content dataSource, DataSourceIngestModuleProgress progressBar) {
if (refCounter.get(jobId) == 1) {
try {
// There will be two tasks: data source analysis and import of
// the results of the analysis.
progressBar.switchToDeterminate(2);
// Do the analysis. The following sample code could be used to
// run an executable. In this case the executable would take
// two command line arguments, the path to the data source to be
// analyzed and the path to a results file to be generated. The
// results file would be an an XML file (see org.sleuthkit.autopsy.externalresults.autopsy_external_results.xsd)
// with instructions for the import of blackboard artifacts,
// derived files, and reports generated by the analysis. In this
// sample ingest module, the generation of the analysis results is
// simulated.
String resultsFilePath = outputDirPath + File.separator + String.format("job_%d_results.xml", jobId);
boolean haveRealExecutable = false;
if (haveRealExecutable) {
String dataSourcePath = dataSource.getImage().getPaths()[0];
ExecUtil executor = new ExecUtil();
executor.execute("some.exe", dataSourcePath, resultsFilePath);
} else {
generateSimulatedResults(resultsFilePath);
}
progressBar.progress(1);
// Import the results of the analysis.
ExternalResultsXMLParser resultsParser = new ExternalResultsXMLParser(dataSource, resultsFilePath);
ExternalResults results = resultsParser.parse();
List<ErrorInfo> errors = resultsParser.getErrorInfo();
ExternalResultsImporter importer = new ExternalResultsImporter();
errors.addAll(importer.importResults(results));
for (ErrorInfo errorInfo : errors) {
IngestServices.getInstance().postMessage(IngestMessage.createErrorMessage(moduleName, "External Results Import Error", errorInfo.getMessage()));
}
progressBar.progress(2);
} catch (TskCoreException | InterruptedException | ParserConfigurationException | TransformerException | IOException ex) {
Logger logger = IngestServices.getInstance().getLogger(moduleName);
logger.log(Level.SEVERE, "Failed to simulate analysis and results import", ex); //NON-NLS
return ProcessResult.ERROR;
}
}
return ProcessResult.OK;
}
private void generateSimulatedResults(String resultsFilePath) throws ParserConfigurationException, IOException, TransformerConfigurationException, TransformerException {
List<String> derivedFilePaths = generateSimulatedDerivedFiles();
List<String> reportFilePaths = generateSimulatedReports();
generateSimulatedResultsFile(derivedFilePaths, reportFilePaths, resultsFilePath);
}
private List<String> generateSimulatedDerivedFiles() throws IOException {
List<String> filePaths = new ArrayList<>();
String fileContents = "This is a simulated derived file.";
for (int i = 0; i < 2; ++i) {
String fileName = String.format("job_%d_derived_file_%d.txt", jobId, i);
filePaths.add(generateFile(fileName, fileContents.getBytes()));
if (i == 0) {
this.derivedFileInCaseDatabase = this.fileInCaseDatabase + "/" + fileName;
}
}
return filePaths;
}
private List<String> generateSimulatedReports() throws IOException {
List<String> filePaths = new ArrayList<>();
String fileContents = "This is a simulated report.";
for (int i = 0; i < 2; ++i) {
String fileName = String.format("job_%d_report_%d.txt", jobId, i);
filePaths.add(generateFile(fileName, fileContents.getBytes()));
}
return filePaths;
}
private String generateFile(String fileName, byte[] fileContents) throws IOException {
String filePath = outputDirPath + File.separator + fileName;
File file = new File(filePath);
if (!file.exists()) {
file.createNewFile();
}
try (FileOutputStream fileStream = new FileOutputStream(file)) {
fileStream.write(fileContents);
fileStream.flush();
}
return filePath;
}
private void generateSimulatedResultsFile(List<String> derivedFilePaths, List<String> reportPaths, String resultsFilePath) throws ParserConfigurationException, TransformerConfigurationException, TransformerException {
// SAMPLE GENERATED BY THE CODE BELOW:
//
// <?xml version="1.0" encoding="UTF-8" standalone="no"?>
// <autopsy_results>
// <derived_files>
// <derived_file>
// <local_path>C:\cases\Small\ModuleOutput\Sample Executable Ingest Module\job_1_derived_file_0.txt</local_path>
// <parent_file>/WINDOWS/system32/ntmsapi.dll</parent_file>
// </derived_file>
// <derived_file>
// <local_path>C:\cases\Small\ModuleOutput\Sample Executable Ingest Module\job_1_derived_file_1.txt</local_path>
// <parent_file>/WINDOWS/system32/ntmsapi.dll/job_1_derived_file_0.txt</parent_file>
// </derived_file>
// </derived_files>
// <artifacts>
// <artifact type="TSK_INTERESTING_FILE_HIT">
// <source_file>/WINDOWS/system32/ntmsapi.dll</source_file>
// <attribute type="TSK_SET_NAME">
// <value>SampleInterestingFilesSet</value>
// <source_module>Sample Executable Ingest Module</source_module>
// </attribute>
// </artifact>
// <artifact type="SampleArtifactType">
// <source_file>/WINDOWS/system32/ntmsapi.dll/job_1_derived_file_0.txt</source_file>
// <attribute type="SampleArtifactAttributeType">
// <value type="text">One</value>
// </attribute>
// <attribute type="SampleArtifactAttributeType">
// <value type="int32">2</value>
// </attribute>
// <attribute type="SampleArtifactAttributeType">
// <value type="int64">3</value>
// </attribute>
// <attribute type="SampleArtifactAttributeType">
// <value type="double">4.0</value>
// </attribute>
// </artifact>
// </artifacts>
// <reports>
// <report>
// <local_path>C:\cases\Small\ModuleOutput\Sample Executable Ingest Module\job_1_report_0.txt</local_path>
// <source_module>Sample Executable Ingest Module</source_module>
// <report_name>Sample Report</report_name>
// </report>
// <report>
// <local_path>C:\cases\Small\ModuleOutput\Sample Executable Ingest Module\job_1_report_1.txt</local_path>
// <source_module>Sample Executable Ingest Module</source_module>
// </report>
// </reports>
// </autopsy_results>
// Create the XML DOM document and the root element.
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element rootElement = doc.createElement(ExternalResultsXMLParser.TagNames.ROOT_ELEM.toString());
doc.appendChild(rootElement);
// Add a derived files list element to the root element.
Element derivedFilesListElement = doc.createElement(ExternalResultsXMLParser.TagNames.DERIVED_FILES_LIST_ELEM.toString());
rootElement.appendChild(derivedFilesListElement);
// Add derived file elements to the derived files list element. Each
// file element gets required local path and parent file child elements.
// Note that the local path of the derived file must be to a location in
// the case directory or a subdirectory of the case directory and the
// parent file must be specified using the path format used in the case
// database, e.g., /WINDOWS/system32/ntmsapi.dll, where volume, file
// system, etc. are not in the path.
for (int i = 0; i < derivedFilePaths.size(); ++i) {
String filePath = derivedFilePaths.get(i);
Element derivedFileElement = doc.createElement(ExternalResultsXMLParser.TagNames.DERIVED_FILE_ELEM.toString());
derivedFilesListElement.appendChild(derivedFileElement);
Element localPathElement = doc.createElement(ExternalResultsXMLParser.TagNames.LOCAL_PATH_ELEM.toString());
localPathElement.setTextContent(filePath);
derivedFileElement.appendChild(localPathElement);
Element parentPathElement = doc.createElement(ExternalResultsXMLParser.TagNames.PARENT_FILE_ELEM.toString());
if (i == 0) {
parentPathElement.setTextContent(this.fileInCaseDatabase);
} else {
parentPathElement.setTextContent(this.derivedFileInCaseDatabase);
}
derivedFileElement.appendChild(parentPathElement);
}
// Add an artifacts list element to the root element.
Element artifactsListElement = doc.createElement(ExternalResultsXMLParser.TagNames.ARTIFACTS_LIST_ELEM.toString());
rootElement.appendChild(artifactsListElement);
// Add an artifact element to the artifacts list element with the required
// artifact type attribute. A standard artifact type is used as the type
// attribute of this artifact element.
Element artifactElement = doc.createElement(ExternalResultsXMLParser.TagNames.ARTIFACT_ELEM.toString());
artifactElement.setAttribute(ExternalResultsXMLParser.AttributeNames.TYPE_ATTR.toString(), ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getLabel());
artifactsListElement.appendChild(artifactElement);
// Add the required source file element to the artifact element. Note
// that source file must be either the local path of a derived file or a
// file in the case database.
Element fileElement = doc.createElement(ExternalResultsXMLParser.TagNames.SOURCE_FILE_ELEM.toString());
fileElement.setTextContent(this.fileInCaseDatabase);
artifactElement.appendChild(fileElement);
// Add an artifact attribute element to the artifact element. A standard
// artifact attribute type is used as the required type XML attribute of
// the artifact attribute element.
Element artifactAttrElement = doc.createElement(ExternalResultsXMLParser.TagNames.ATTRIBUTE_ELEM.toString());
artifactAttrElement.setAttribute(ExternalResultsXMLParser.AttributeNames.TYPE_ATTR.toString(), ATTRIBUTE_TYPE.TSK_SET_NAME.getLabel());
artifactElement.appendChild(artifactAttrElement);
// Add the required value element to the artifact attribute element,
// with an optional type XML attribute of ExternalXML.VALUE_TYPE_TEXT,
// which is the default.
Element artifactAttributeValueElement = doc.createElement(ExternalResultsXMLParser.TagNames.VALUE_ELEM.toString());
artifactAttributeValueElement.setTextContent("SampleInterestingFilesSet");
artifactAttrElement.appendChild(artifactAttributeValueElement);
// Add an optional source module element to the artifact attribute
// element.
Element artifactAttrSourceElement = doc.createElement(ExternalResultsXMLParser.TagNames.SOURCE_MODULE_ELEM.toString());
artifactAttrSourceElement.setTextContent(moduleName);
artifactAttrElement.appendChild(artifactAttrSourceElement);
// Add an artifact element with a user-defined type.
artifactElement = doc.createElement(ExternalResultsXMLParser.TagNames.ARTIFACT_ELEM.toString());
artifactElement.setAttribute(ExternalResultsXMLParser.AttributeNames.TYPE_ATTR.toString(), "SampleArtifactType");
artifactsListElement.appendChild(artifactElement);
// Add the required source file element.
fileElement = doc.createElement(ExternalResultsXMLParser.TagNames.SOURCE_FILE_ELEM.toString());
fileElement.setTextContent(this.derivedFileInCaseDatabase);
artifactElement.appendChild(fileElement);
// Add artifact attribute elements with user-defined types to the
// artifact element, adding value elements of assorted types.
for (int i = 0; i < 4; ++i) {
artifactAttrElement = doc.createElement(ExternalResultsXMLParser.TagNames.ATTRIBUTE_ELEM.toString());
artifactAttrElement.setAttribute(ExternalResultsXMLParser.AttributeNames.TYPE_ATTR.toString(), "SampleArtifactAttributeType");
artifactElement.appendChild(artifactAttrElement);
artifactAttributeValueElement = doc.createElement(ExternalResultsXMLParser.TagNames.VALUE_ELEM.toString());
switch (i) {
case 0:
artifactAttributeValueElement.setAttribute(ExternalResultsXMLParser.AttributeNames.TYPE_ATTR.toString(), ExternalResultsXMLParser.AttributeValues.VALUE_TYPE_TEXT.toString());
artifactAttributeValueElement.setTextContent("One");
break;
case 1:
artifactAttributeValueElement.setAttribute(ExternalResultsXMLParser.AttributeNames.TYPE_ATTR.toString(), ExternalResultsXMLParser.AttributeValues.VALUE_TYPE_INT32.toString());
artifactAttributeValueElement.setTextContent("2");
break;
case 2:
artifactAttributeValueElement.setAttribute(ExternalResultsXMLParser.AttributeNames.TYPE_ATTR.toString(), ExternalResultsXMLParser.AttributeValues.VALUE_TYPE_INT64.toString());
artifactAttributeValueElement.setTextContent("3");
break;
case 3:
artifactAttributeValueElement.setAttribute(ExternalResultsXMLParser.AttributeNames.TYPE_ATTR.toString(), ExternalResultsXMLParser.AttributeValues.VALUE_TYPE_DOUBLE.toString());
artifactAttributeValueElement.setTextContent("4.0");
break;
}
artifactAttrElement.appendChild(artifactAttributeValueElement);
}
// Add a reports list element to the root element.
Element reportsListElement = doc.createElement(ExternalResultsXMLParser.TagNames.REPORTS_LIST_ELEM.toString());
rootElement.appendChild(reportsListElement);
// Add report elements to the reports list element. Each report element
// gets required local path and source module child elements. There is
// also an optional report name element. Note that the local path of the
// report must be to a location in the case directory or a subdirectory
// of the case directory and the parent file must be specified using the
// path format used in the case database, e.g., /WINDOWS/system32/ntmsapi.dll,
// where volume, file system, etc. are not in the path.
for (int i = 0; i < reportPaths.size(); ++i) {
String reportPath = reportPaths.get(i);
Element reportElement = doc.createElement(ExternalResultsXMLParser.TagNames.REPORT_ELEM.toString());
reportsListElement.appendChild(reportElement);
Element reportPathElement = doc.createElement(ExternalResultsXMLParser.TagNames.LOCAL_PATH_ELEM.toString());
reportPathElement.setTextContent(reportPath);
reportElement.appendChild(reportPathElement);
Element reportSourceModuleElement = doc.createElement(ExternalResultsXMLParser.TagNames.SOURCE_MODULE_ELEM.toString());
reportSourceModuleElement.setTextContent(moduleName);
reportElement.appendChild(reportSourceModuleElement);
if (i == 0) {
Element reportNameElement = doc.createElement(ExternalResultsXMLParser.TagNames.REPORT_NAME_ELEM.toString());
reportNameElement.setTextContent("Sample Report");
reportElement.appendChild(reportNameElement);
}
}
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(resultsFilePath));
transformer.transform(source, result);
}
}

View File

@@ -0,0 +1,79 @@
/*
* Sample ingest module factory in the public domain.
* Feel free to use this as a template for your inget module factories.
*
* 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.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import static org.sleuthkit.autopsy.examples.SampleIngestModuleFactory.getModuleName;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
/**
* A factory that creates sample executable data source ingest modules.
*/
@ServiceProvider(service = IngestModuleFactory.class) // Sample is discarded at runtime
public class SampleExecutableIngestModuleFactory extends IngestModuleFactoryAdapter {
private static final String VERSION_NUMBER = "1.0.0";
// This class method allows the ingest module instances created by this
// factory to use the same display name that is provided to the Autopsy
// ingest framework by the factory.
static String getModuleName() {
return NbBundle.getMessage(SampleIngestModuleFactory.class, "SampleExecutableIngestModuleFactory.moduleName");
}
@Override
public String getModuleDisplayName() {
return getModuleName();
}
@Override
public String getModuleDescription() {
return NbBundle.getMessage(SampleIngestModuleFactory.class, "SampleExecutableIngestModuleFactory.moduleDescription");
}
@Override
public String getModuleVersionNumber() {
return VERSION_NUMBER;
}
@Override
public boolean isDataSourceIngestModuleFactory() {
return true;
}
@Override
public DataSourceIngestModule createDataSourceIngestModule(IngestModuleIngestJobSettings ingestOptions) {
return new SampleExecutableDataSourceIngestModule();
}
}

View File

@@ -79,21 +79,18 @@ class SampleFileIngestModule implements FileIngestModule {
// modules.
Case autopsyCase = Case.getCurrentCase();
SleuthkitCase sleuthkitCase = autopsyCase.getSleuthkitCase();
// See if the attribute type has already been defined.
try {
// See if the attribute type has already been defined.
attrId = sleuthkitCase.getAttrTypeID("ATTR_SAMPLE");
} catch (TskCoreException e) {
// If not, create the the attribute type.
try {
if (attrId == -1) {
attrId = sleuthkitCase.addAttrType("ATTR_SAMPLE", "Sample Attribute");
} catch (TskCoreException ex) {
IngestServices ingestServices = IngestServices.getInstance();
Logger logger = ingestServices.getLogger(SampleIngestModuleFactory.getModuleName());
logger.log(Level.SEVERE, "Failed to create blackboard attribute", ex);
attrId = -1;
throw new IngestModuleException(ex.getLocalizedMessage());
}
} catch (TskCoreException ex) {
IngestServices ingestServices = IngestServices.getInstance();
Logger logger = ingestServices.getLogger(SampleIngestModuleFactory.getModuleName());
logger.log(Level.SEVERE, "Failed to create blackboard attribute", ex);
attrId = -1;
throw new IngestModuleException(ex.getLocalizedMessage());
}
}
}

View File

@@ -0,0 +1,10 @@
# To change this template, choose Tools | Templates
# and open the template in the editor.
ExternalResultsIngestModule.moduleName.text=External Results Importer
ExternalResultsIngestModule.properties.text=ExternalResultsImporter
ExternalResultsIngestModule.moduleDesc.text=Parse command line tool output to create blackboard entries and add files to the database.
ExternalResultsIngestModule.startUp.exception.importdir=Import directory does not exist and was not able to be created.
ExternalResultsIngestModule.process.exception.datasourcepath=Error getting the data source path.
ExternalResultsIngestModule.process.exception.run=Error running the external command:
ExternalResultsIngestModule.process.shutdown.finished=Finished

View File

@@ -0,0 +1,201 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 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.externalresults;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.sleuthkit.datamodel.Content;
/**
*
*/
final public class ExternalResults {
private final Content dataSource;
private final List<Artifact> artifacts = new ArrayList<>();
private final List<Report> reports = new ArrayList<>();
private final List<DerivedFile> derivedFiles = new ArrayList<>();
ExternalResults(Content dataSource) {
this.dataSource = dataSource;
}
Content getDataSource() {
return this.dataSource;
}
Artifact addArtifact(String type, String sourceFilePath) {
if (type.isEmpty()) {
throw new IllegalArgumentException("type argument is empty");
}
if (sourceFilePath.isEmpty()) {
throw new IllegalArgumentException("source argument is empty");
}
Artifact artifact = new Artifact(type, sourceFilePath);
artifacts.add(artifact);
return artifact;
}
List<Artifact> getArtifacts() {
return Collections.unmodifiableList(artifacts);
}
void addReport(String localPath, String sourceModuleName, String reportName) {
if (localPath.isEmpty()) {
throw new IllegalArgumentException("localPath argument is empty");
}
if (sourceModuleName.isEmpty()) {
throw new IllegalArgumentException("sourceModuleName argument is empty");
}
Report report = new Report(localPath, sourceModuleName, reportName);
reports.add(report);
}
List<Report> getReports() {
return Collections.unmodifiableList(reports);
}
void addDerivedFile(String localPath, String parentPath) {
if (localPath.isEmpty()) {
throw new IllegalArgumentException("localPath argument is empty");
}
if (parentPath.isEmpty()) {
throw new IllegalArgumentException("parentPath argument is empty");
}
DerivedFile file = new DerivedFile(localPath, parentPath);
derivedFiles.add(file);
}
List<DerivedFile> getDerivedFiles() {
return Collections.unmodifiableList(derivedFiles);
}
static final class Artifact {
private final String type;
private final String sourceFilePath;
private final ArrayList<ArtifactAttribute> attributes = new ArrayList<>();
Artifact(String type, String sourceFilePath) {
this.type = type;
this.sourceFilePath = sourceFilePath;
}
String getType() {
return type;
}
String getSourceFilePath() {
return sourceFilePath;
}
void addAttribute(String type, String value, String valueType, String sourceModule) {
if (type.isEmpty()) {
throw new IllegalArgumentException("type argument is empty");
}
if (value.isEmpty()) {
throw new IllegalArgumentException("value argument is empty");
}
if (valueType.isEmpty()) {
throw new IllegalArgumentException("value type argument is empty");
}
attributes.add(new ArtifactAttribute(type, value, valueType, sourceModule));
}
List<ArtifactAttribute> getAttributes() {
return Collections.unmodifiableList(attributes);
}
}
static final class ArtifactAttribute {
private final String type;
private final String valueType;
private final String value;
private final String sourceModule;
private ArtifactAttribute(String type, String value, String valueType, String sourceModule) {
this.type = type;
this.value = value;
this.valueType = valueType;
this.sourceModule = sourceModule;
}
String getType() {
return type;
}
String getValue() {
return value;
}
String getValueType() {
return valueType;
}
String getSourceModule() {
return sourceModule;
}
}
static final class Report {
private final String localPath;
private final String sourceModuleName;
private final String reportName;
Report(String localPath, String sourceModuleName, String displayName) {
this.localPath = localPath;
this.sourceModuleName = sourceModuleName;
this.reportName = displayName;
}
String getLocalPath() {
return localPath;
}
String getSourceModuleName() {
return sourceModuleName;
}
String getReportName() {
return reportName;
}
}
static final class DerivedFile {
private final String localPath;
private final String parentPath;
DerivedFile(String localPath, String parentPath) {
this.localPath = localPath;
this.parentPath = parentPath;
}
String getLocalPath() {
return localPath;
}
String getParentPath() {
return parentPath;
}
}
}

View File

@@ -0,0 +1,263 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this localFile 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.externalresults;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.logging.Level;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.FileManager;
import org.sleuthkit.autopsy.coreutils.ErrorInfo;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DerivedFile;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Uses a standard representation of results data (e.g., artifacts, derived
* files, reports) to import results generated by a process external to Autopsy
* into Autopsy.
*/
public final class ExternalResultsImporter {
private static final Logger logger = Logger.getLogger(ExternalResultsImporter.class.getName());
private static final HashSet<Integer> standardArtifactTypeIds = new HashSet<>();
private final List<ErrorInfo> errors = new ArrayList<>();
static {
for (BlackboardArtifact.ARTIFACT_TYPE artifactType : BlackboardArtifact.ARTIFACT_TYPE.values()) {
standardArtifactTypeIds.add(artifactType.getTypeID());
}
}
/**
* Import results generated by a process external to Autopsy into Autopsy.
*
* @param results A standard representation of results data (e.g.,
* artifacts, derived files, reports)from the data source.
* @return A collection of error messages, possibly empty. The error
* messages are already logged but are provided to allow the caller to
* provide additional user feedback via the Autopsy user interface.
*/
public List<ErrorInfo> importResults(ExternalResults results) {
// Import files first, they may be artifactData sources.
importDerivedFiles(results);
importArtifacts(results);
importReports(results);
List<ErrorInfo> importErrors = new ArrayList(this.errors);
this.errors.clear();
return importErrors;
}
private void importDerivedFiles(ExternalResults results) {
FileManager fileManager = Case.getCurrentCase().getServices().getFileManager();
for (ExternalResults.DerivedFile fileData : results.getDerivedFiles()) {
String localPath = fileData.getLocalPath();
try {
File localFile = new File(localPath);
if (localFile.exists()) {
String relativePath = this.getPathRelativeToCaseFolder(localPath);
if (!relativePath.isEmpty()) {
String parentFilePath = fileData.getParentPath();
AbstractFile parentFile = findFileInCaseDatabase(parentFilePath);
if (parentFile != null) {
DerivedFile derivedFile = fileManager.addDerivedFile(localFile.getName(), relativePath, localFile.length(),
0, 0, 0, 0, // Do not currently have file times for derived files from external processes.
true, parentFile,
"", "", "", ""); // Not currently providing derivation info for derived files from external processes.
IngestServices.getInstance().fireModuleContentEvent(new ModuleContentEvent(derivedFile));
} else {
String errorMessage = String.format("Could not import derived file at %s, parent file %s not found", localPath, parentFilePath);
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage);
this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage));
}
}
} else {
String errorMessage = String.format("Could not import derived file at %s, file does not exist", localPath);
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage);
this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage));
}
} catch (TskCoreException ex) {
String errorMessage = String.format("Could not import derived file at %s, error querying/updating case database", localPath);
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage, ex);
this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage, ex));
}
}
}
private void importArtifacts(ExternalResults results) {
SleuthkitCase caseDb = Case.getCurrentCase().getSleuthkitCase();
for (ExternalResults.Artifact artifactData : results.getArtifacts()) {
try {
// Add the artifact to the case database.
int artifactTypeId = caseDb.getArtifactTypeID(artifactData.getType());
if (artifactTypeId == -1) {
artifactTypeId = caseDb.addArtifactType(artifactData.getType(), artifactData.getType());
}
Content sourceFile = findFileInCaseDatabase(artifactData.getSourceFilePath());
if (sourceFile != null) {
BlackboardArtifact artifact = sourceFile.newArtifact(artifactTypeId);
// Add the artifact's attributes to the case database.
Collection<BlackboardAttribute> attributes = new ArrayList<>();
for (ExternalResults.ArtifactAttribute attributeData : artifactData.getAttributes()) {
int attributeTypeId = caseDb.getAttrTypeID(attributeData.getType());
if (attributeTypeId == -1) {
attributeTypeId = caseDb.addAttrType(attributeData.getType(), attributeData.getType());
}
switch (attributeData.getValueType()) {
case "text": //NON-NLS
attributes.add(new BlackboardAttribute(attributeTypeId, attributeData.getSourceModule(), attributeData.getValue()));
break;
case "int32": //NON-NLS
int intValue = Integer.parseInt(attributeData.getValue());
attributes.add(new BlackboardAttribute(attributeTypeId, attributeData.getSourceModule(), intValue));
break;
case "int64": //NON-NLS
long longValue = Long.parseLong(attributeData.getValue());
attributes.add(new BlackboardAttribute(attributeTypeId, attributeData.getSourceModule(), longValue));
break;
case "double": //NON-NLS
double doubleValue = Double.parseDouble(attributeData.getValue());
attributes.add(new BlackboardAttribute(attributeTypeId, attributeData.getSourceModule(), doubleValue));
break;
default:
String errorMessage = String.format("Could not import %s attribute, value = %s, for %s artifact from %s, unrecognized attribute value type: %s",
attributeData.getType(), attributeData.getValue(),
artifactData.getType(), artifactData.getSourceFilePath(),
attributeData.getValueType());
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage);
this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage));
break;
}
}
artifact.addAttributes(attributes);
if (standardArtifactTypeIds.contains(artifactTypeId)) {
IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(this.getClass().getSimpleName(), BlackboardArtifact.ARTIFACT_TYPE.fromID(artifactTypeId)));
}
} else {
String errorMessage = String.format("Could not import %s artifact from %s, source file not found", artifactData.getType(), artifactData.getSourceFilePath());
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage);
this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage));
}
} catch (TskCoreException ex) {
String errorMessage = String.format("Could not import %s artifact from %s, error updating case database", artifactData.getType(), artifactData.getSourceFilePath());
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage, ex);
this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage, ex));
}
}
}
private void importReports(ExternalResults results) {
for (ExternalResults.Report report : results.getReports()) {
String reportPath = report.getLocalPath();
try {
File reportFile = new File(reportPath);
if (reportFile.exists()) {
Case.getCurrentCase().addReport(reportPath, report.getSourceModuleName(), report.getReportName());
} else {
String errorMessage = String.format("Could not import report at %s, file does not exist", reportPath);
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage);
this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage));
}
} catch (TskCoreException ex) {
String errorMessage = String.format("Could not import report at %s, error updating case database", reportPath);
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage, ex);
this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage, ex));
}
}
}
private AbstractFile findFileInCaseDatabase(String filePath) throws TskCoreException {
AbstractFile file = null;
// Split the path into the file name and the parent path.
String fileName = filePath;
String parentPath = "";
int charPos = filePath.lastIndexOf("/");
if (charPos >= 0) {
fileName = filePath.substring(charPos + 1);
parentPath = filePath.substring(0, charPos + 1);
}
// Find the file.
String condition = "name='" + fileName + "' AND parent_path='" + parentPath + "'"; //NON-NLS
List<AbstractFile> files = Case.getCurrentCase().getSleuthkitCase().findAllFilesWhere(condition);
if (!files.isEmpty()) {
file = files.get(0);
if (files.size() > 1) {
String errorMessage = String.format("Parent file path %s is ambiguous, using first file found", filePath);
this.recordError(errorMessage);
}
}
return file;
}
private String getPathRelativeToCaseFolder(String localPath) {
String relativePath = "";
String caseDirectoryPath = Case.getCurrentCase().getCaseDirectory();
Path path = Paths.get(localPath);
if (path.isAbsolute()) {
Path pathBase = Paths.get(caseDirectoryPath);
try {
Path pathRelative = pathBase.relativize(path);
relativePath = pathRelative.toString();
} catch (IllegalArgumentException ex) {
String errorMessage = String.format("Did not convert %s to relative path, not in a subdirectory of case directory %s",
localPath, caseDirectoryPath);
this.recordError(errorMessage, ex);
}
} else {
String errorMessage = String.format("Expected %s to be an absolute path to a file in a subdirectory of case directory %s",
localPath, caseDirectoryPath);
this.recordError(errorMessage);
}
return relativePath;
}
// private static boolean isStandardArtifactType(int artifactTypeId) {
// for (BlackboardArtifact.ARTIFACT_TYPE art : BlackboardArtifact.ARTIFACT_TYPE.values()) {
// if (art.getTypeID() == artifactTypeId) {
// return true;
// }
// }
// return false;
// }
//
private void recordError(String errorMessage) {
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage);
this.errors.add(new ErrorInfo(this.getClass().getName(), errorMessage));
}
private void recordError(String errorMessage, Exception ex) {
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage, ex);
this.errors.add(new ErrorInfo(this.getClass().getName(), errorMessage));
}
}

View File

@@ -0,0 +1,49 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 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.externalresults;
import java.util.List;
import org.sleuthkit.autopsy.coreutils.ErrorInfo;
/**
* Interface for parsers that convert some representation of results data (e.g.,
* artifacts, derived files, reports) generated by a process external to Autopsy
* into a form ready for import into Autopsy.
*/
public interface ExternalResultsParser {
/**
* Converts some representation of results data generated by a process
* external to Autopsy and supplied to the parser via its constructor into a
* form ready for import into Autopsy.
*
* @return External results data in a form ready for import into Autopsy.
*/
ExternalResults parse();
/**
* Gets error information describing any errors encountered while parsing
* the input results representation.
*
* @return A collection of error messages, possibly empty. The error
* messages are already logged but are provided to allow the caller to
* provide additional user feedback via the Autopsy user interface.
*/
List<ErrorInfo> getErrorInfo();
}

View File

@@ -0,0 +1,343 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 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.externalresults;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.coreutils.ErrorInfo;
import org.sleuthkit.autopsy.coreutils.XMLUtil;
import org.sleuthkit.datamodel.Content;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* Parses an XML representation of of results data (e.g., artifacts, derived
* files, reports) generated by a process external to Autopsy.
*/
public final class ExternalResultsXMLParser implements ExternalResultsParser {
private static final Logger logger = Logger.getLogger(ExternalResultsXMLParser.class.getName());
private static final String XSD_FILE = "autopsy_external_results.xsd"; //NON-NLS
private final Content dataSource;
private final String resultsFilePath;
private ExternalResults resultsData;
private List<ErrorInfo> errors = new ArrayList<>();
/**
* Tag names for an external results XML file.
*/
public enum TagNames {
ROOT_ELEM("autopsy_results"), //NON-NLS
DERIVED_FILES_LIST_ELEM("derived_files"), //NON-NLS
DERIVED_FILE_ELEM("derived_file"), //NON-NLS
LOCAL_PATH_ELEM("local_path"), //NON-NLS
PARENT_FILE_ELEM("parent_file"), //NON-NLS
ARTIFACTS_LIST_ELEM("artifacts"), //NON-NLS
ARTIFACT_ELEM("artifact"), //NON-NLS
SOURCE_FILE_ELEM("source_file"), //NON-NLS
ATTRIBUTE_ELEM("attribute"), //NON-NLS
VALUE_ELEM("value"), //NON-NLS
SOURCE_MODULE_ELEM("source_module"), //NON-NLS
REPORTS_LIST_ELEM("reports"), //NON-NLS
REPORT_ELEM("report"), //NON-NLS
REPORT_NAME_ELEM("report_name"); //NON-NLS
private final String text;
private TagNames(final String text) {
this.text = text;
}
@Override
public String toString() {
return this.text;
}
}
/**
* Attribute names for an external results XML file.
*/
public enum AttributeNames {
TYPE_ATTR("type"); //NON-NLS
private final String text;
private AttributeNames(final String text) {
this.text = text;
}
@Override
public String toString() {
return this.text;
}
}
/**
* Attribute values for an external results XML file.
*/
public enum AttributeValues {
VALUE_TYPE_TEXT("text"), //NON-NLS
VALUE_TYPE_INT32("int32"), //NON-NLS
VALUE_TYPE_INT64("int64"), //NON-NLS
VALUE_TYPE_DOUBLE("double"); //NON-NLS
private final String text;
private AttributeValues(final String text) {
this.text = text;
}
@Override
public String toString() {
return this.text;
}
}
/**
* Constructor.
*
* @param importFilePath Full path of the results file to be parsed.
*/
public ExternalResultsXMLParser(Content dataSource, String resultsFilePath) {
this.dataSource = dataSource;
this.resultsFilePath = resultsFilePath;
}
@Override
public ExternalResults parse() {
this.errors.clear();
this.resultsData = new ExternalResults(dataSource);
try {
// Note that XMLUtil.loadDoc() logs a warning if the file does not
// conform to the XSD, but still returns a Document object. Until
// this behavior is improved, validation is still required. If
// XMLUtil.loadDoc() does return null, it failed to load the
// document and it logged the error.
final Document doc = XMLUtil.loadDoc(ExternalResultsXMLParser.class, this.resultsFilePath, XSD_FILE);
if (doc != null) {
final Element rootElem = doc.getDocumentElement();
if (rootElem != null && rootElem.getNodeName().equals(TagNames.ROOT_ELEM.toString())) {
parseDerivedFiles(rootElem);
parseArtifacts(rootElem);
parseReports(rootElem);
} else {
String errorMessage = String.format("Did not find %s root element of %s", TagNames.ROOT_ELEM.toString(), this.resultsFilePath);
recordError(errorMessage);
}
}
} catch (Exception ex) {
String errorMessage = String.format("Error parsing %s", this.resultsFilePath);
recordError(errorMessage, ex);
}
return this.resultsData;
}
@Override
public List<ErrorInfo> getErrorInfo() {
return new ArrayList<>(this.errors);
}
private void parseDerivedFiles(Element rootElement) {
// Get the derived file lists.
NodeList derivedFilesListNodes = rootElement.getElementsByTagName(TagNames.DERIVED_FILES_LIST_ELEM.toString());
for (int i = 0; i < derivedFilesListNodes.getLength(); ++i) {
Element derivedFilesListElem = (Element) derivedFilesListNodes.item(i);
// Get the derived files.
NodeList derivedFileNodes = derivedFilesListElem.getElementsByTagName(TagNames.DERIVED_FILE_ELEM.toString());
for (int j = 0; j < derivedFileNodes.getLength(); ++j) {
Element derivedFileElem = (Element) derivedFileNodes.item(j);
// Get the local path of the derived file.
String path = getChildElementContent(derivedFileElem, TagNames.LOCAL_PATH_ELEM.toString(), true);
if (path.isEmpty()) {
continue;
}
// Get the parent file of the derived file.
String parentFile = getChildElementContent((Element) derivedFileNodes.item(j), TagNames.PARENT_FILE_ELEM.toString(), true);
if (parentFile.isEmpty()) {
continue;
}
this.resultsData.addDerivedFile(path, parentFile);
}
}
}
private void parseArtifacts(final Element root) {
// Get the artifact lists.
NodeList artifactsListNodes = root.getElementsByTagName(TagNames.ARTIFACTS_LIST_ELEM.toString());
for (int i = 0; i < artifactsListNodes.getLength(); ++i) {
Element artifactsListElem = (Element) artifactsListNodes.item(i);
// Get the artifacts.
NodeList artifactNodes = artifactsListElem.getElementsByTagName(TagNames.ARTIFACT_ELEM.toString());
for (int j = 0; j < artifactNodes.getLength(); ++j) {
Element artifactElem = (Element) artifactNodes.item(j);
// Get the artifact type.
final String type = getElementAttributeValue(artifactElem, AttributeNames.TYPE_ATTR.toString());
if (!type.isEmpty()) {
// Get the source file of the artifact and the attributes,
// if any.
final String sourceFilePath = this.getChildElementContent((Element) artifactElem, TagNames.SOURCE_FILE_ELEM.toString(), true);
if (!sourceFilePath.isEmpty()) {
ExternalResults.Artifact artifact = this.resultsData.addArtifact(type, sourceFilePath);
parseArtifactAttributes(artifactElem, artifact);
}
}
}
}
}
private void parseArtifactAttributes(final Element artifactElem, ExternalResults.Artifact artifact) {
// Get the artifact attributes.
NodeList attributeNodesList = artifactElem.getElementsByTagName(TagNames.ATTRIBUTE_ELEM.toString());
for (int i = 0; i < attributeNodesList.getLength(); ++i) {
Element attributeElem = (Element) attributeNodesList.item(i);
final String type = getElementAttributeValue(attributeElem, AttributeNames.TYPE_ATTR.toString());
if (type.isEmpty()) {
continue;
}
// Get the value of the artifact attribute.
Element valueElem = this.getChildElement(attributeElem, TagNames.VALUE_ELEM.toString());
if (valueElem == null) {
continue;
}
final String value = valueElem.getTextContent();
if (value.isEmpty()) {
String errorMessage = String.format("Found %s element that has no content in %s",
TagNames.VALUE_ELEM.toString(), this.resultsFilePath);
recordError(errorMessage);
continue;
}
// Get the value type.
String valueType = parseArtifactAttributeValueType(valueElem);
if (valueType.isEmpty()) {
continue;
}
// Get the optional source module.
String sourceModule = this.getChildElementContent(attributeElem, TagNames.SOURCE_MODULE_ELEM.toString(), false);
// Add the attribute to the artifact.
artifact.addAttribute(type, value, valueType, sourceModule);
}
}
private String parseArtifactAttributeValueType(Element valueElem) {
String valueType = valueElem.getAttribute(AttributeNames.TYPE_ATTR.toString());
if (valueType.isEmpty()) {
// Default to text.
valueType = AttributeValues.VALUE_TYPE_TEXT.toString();
} else if (!valueType.equals(AttributeValues.VALUE_TYPE_TEXT.toString())
&& !valueType.equals(AttributeValues.VALUE_TYPE_DOUBLE.toString())
&& !valueType.equals(AttributeValues.VALUE_TYPE_INT32.toString())
&& !valueType.equals(AttributeValues.VALUE_TYPE_INT64.toString())) {
String errorMessage = String.format("Found unrecognized value %s for %s attribute of %s element",
valueType,
AttributeNames.TYPE_ATTR.toString(),
TagNames.VALUE_ELEM.toString());
this.recordError(errorMessage);
valueType = "";
}
return valueType;
}
private void parseReports(Element root) {
// Get the report lists.
NodeList reportsListNodes = root.getElementsByTagName(TagNames.REPORTS_LIST_ELEM.toString());
for (int i = 0; i < reportsListNodes.getLength(); ++i) {
Element reportsListElem = (Element) reportsListNodes.item(i);
// Get the reports.
NodeList reportNodes = reportsListElem.getElementsByTagName(TagNames.REPORT_ELEM.toString());
for (int j = 0; j < reportNodes.getLength(); ++j) {
Element reportElem = (Element) reportNodes.item(j);
// Get the local path.
String path = getChildElementContent(reportElem, TagNames.LOCAL_PATH_ELEM.toString(), true);
if (path.isEmpty()) {
continue;
}
// Get the source module.
String sourceModule = getChildElementContent(reportElem, TagNames.SOURCE_MODULE_ELEM.toString(), true);
if (path.isEmpty()) {
continue;
}
// Get the optional report name.
String reportName = getChildElementContent(reportElem, TagNames.REPORT_NAME_ELEM.toString(), false);
this.resultsData.addReport(path, sourceModule, reportName);
}
}
}
private String getElementAttributeValue(Element element, String attributeName) {
final String attributeValue = element.getAttribute(attributeName);
if (attributeValue.isEmpty()) {
logger.log(Level.SEVERE, "Found {0} element missing {1} attribute in {2}", new Object[]{
element.getTagName(),
attributeName,
this.resultsFilePath});
}
return attributeValue;
}
private String getChildElementContent(Element parentElement, String childElementTagName, boolean required) {
String content = "";
Element childElement = this.getChildElement(parentElement, childElementTagName);
if (childElement != null) {
content = childElement.getTextContent();
if (content.isEmpty()) {
String errorMessage = String.format("Found %s element with %s child element that has no content in %s",
parentElement.getTagName(),
childElementTagName,
this.resultsFilePath);
this.recordError(errorMessage);
}
} else if (required) {
String errorMessage = String.format("Found %s element missing %s child element in %s",
parentElement.getTagName(),
childElementTagName,
this.resultsFilePath);
this.recordError(errorMessage);
}
return content;
}
private Element getChildElement(Element parentElement, String childElementTagName) {
Element childElem = null;
NodeList childNodes = parentElement.getElementsByTagName(childElementTagName);
if (childNodes.getLength() > 0) {
childElem = (Element) childNodes.item(0);
if (childNodes.getLength() > 1) {
String errorMessage = String.format("Found multiple %s child elements for %s element in %s, ignoring all but first occurrence",
childElementTagName,
parentElement.getTagName(),
this.resultsFilePath);
this.recordError(errorMessage);
}
}
return childElem;
}
private void recordError(String errorMessage) {
ExternalResultsXMLParser.logger.log(Level.SEVERE, errorMessage);
this.errors.add(new ErrorInfo(this.getClass().getSimpleName(), errorMessage));
}
private void recordError(String errorMessage, Exception ex) {
ExternalResultsXMLParser.logger.log(Level.SEVERE, errorMessage, ex);
this.errors.add(new ErrorInfo(this.getClass().getSimpleName(), errorMessage, ex));
}
}

View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="autopsy_results">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="1">
<xs:element minOccurs="0" maxOccurs="1" name="data_source" type="xs:string" />
<xs:element minOccurs="0" maxOccurs="unbounded" name="derived_files">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="derived_file">
<xs:complexType>
<xs:sequence>
<xs:element name="local_path" type="xs:string" />
<xs:element minOccurs="0" name="parent_file" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element minOccurs="0" maxOccurs="unbounded" name="artifacts">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="artifact">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="source_file" type="xs:string" />
<xs:element minOccurs="0" maxOccurs="unbounded" name="attribute">
<xs:complexType>
<xs:sequence>
<xs:element name="value">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="type" type="xs:string" use="optional" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="source_module" type="xs:string" />
</xs:sequence>
<xs:attribute name="type" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="type" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element minOccurs="0" maxOccurs="unbounded" name="reports">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="report">
<xs:complexType>
<xs:sequence>
<xs:element name="local_path" type="xs:string" />
<xs:element name="source_module" type="xs:string" />
<xs:element minOccurs="0" maxOccurs="1" name="report_name" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 B

View File

@@ -31,9 +31,8 @@ public interface DataSourceIngestModule extends IngestModule {
* and shutDown().
*
* @param dataSource The data source to process.
* @param statusHelper A status helper to be used to report progress and
* detect ingest job cancellation.
* @param progressBar A progress bar to be used to report progress.
* @return A result code indicating success or failure of the processing.
*/
ProcessResult process(Content dataSource, DataSourceIngestModuleProgress statusHelper);
ProcessResult process(Content dataSource, DataSourceIngestModuleProgress progressBar);
}

View File

@@ -60,7 +60,7 @@ public final class IngestJobContext {
*
* @param files The files to be processed by the file ingest pipeline.
*/
public void addFiles(List<AbstractFile> files) {
public void scheduleFiles(List<AbstractFile> files) {
for (AbstractFile file : files) {
try {
FileIngestTaskScheduler.getInstance().scheduleTask(ingestJob, file);

View File

@@ -66,8 +66,9 @@ final class IngestModuleFactoryLoader {
}
}
// Kick out the sample modules factory.
// Kick out the sample module factories.
moduleFactoriesByClass.remove("org.sleuthkit.autopsy.examples.SampleIngestModuleFactory");
moduleFactoriesByClass.remove("org.sleuthkit.autopsy.examples.SampleExecutableIngestModuleFactory");
// Do the core ingest module ordering hack described above.
ArrayList<String> coreModuleOrdering = new ArrayList<String>() {

View File

@@ -70,9 +70,9 @@ public final class SevenZipIngestModule implements FileIngestModule {
private static final Logger logger = Logger.getLogger(SevenZipIngestModule.class.getName());
private IngestServices services = IngestServices.getInstance();
static final String[] SUPPORTED_EXTENSIONS = {"zip", "rar", "arj", "7z", "7zip", "gzip", "gz", "bzip2", "tar", "tgz",}; // "iso"}; NON-NLS
private String unpackDir; //relative to the case, to store in db
private String unpackDirPath; //absolute, to extract to
private FileManager fileManager;
private String moduleDirRelative; //relative to the case, to store in db
private String moduleDirAbsolute; //absolute, to extract to
//encryption type strings
private static final String ENCRYPTION_FILE_LEVEL = NbBundle.getMessage(SevenZipIngestModule.class,
"SevenZipIngestModule.encryptionFileLevel");
@@ -103,22 +103,21 @@ public final class SevenZipIngestModule implements FileIngestModule {
final Case currentCase = Case.getCurrentCase();
unpackDir = Case.getModulesOutputDirRelPath() + File.separator + ArchiveFileExtractorModuleFactory.getModuleName();
unpackDirPath = currentCase.getModulesOutputDirAbsPath() + File.separator + ArchiveFileExtractorModuleFactory.getModuleName();
moduleDirRelative = Case.getModulesOutputDirRelPath() + File.separator + ArchiveFileExtractorModuleFactory.getModuleName();
moduleDirAbsolute = currentCase.getModulesOutputDirAbsPath() + File.separator + ArchiveFileExtractorModuleFactory.getModuleName();
fileManager = currentCase.getServices().getFileManager();
File unpackDirPathFile = new File(unpackDirPath);
File unpackDirPathFile = new File(moduleDirAbsolute);
if (!unpackDirPathFile.exists()) {
try {
unpackDirPathFile.mkdirs();
} catch (SecurityException e) {
logger.log(Level.SEVERE, "Error initializing output dir: " + unpackDirPath, e); //NON-NLS
logger.log(Level.SEVERE, "Error initializing output dir: " + moduleDirAbsolute, e); //NON-NLS
String msg = NbBundle.getMessage(this.getClass(),
"SevenZipIngestModule.init.errInitModule.msg", ArchiveFileExtractorModuleFactory.getModuleName());
String details = NbBundle.getMessage(this.getClass(),
"SevenZipIngestModule.init.errInitModule.details",
unpackDirPath, e.getMessage());
moduleDirAbsolute, e.getMessage());
services.postMessage(IngestMessage.createErrorMessage(ArchiveFileExtractorModuleFactory.getModuleName(), msg, details));
throw e;
}
@@ -177,8 +176,10 @@ public final class SevenZipIngestModule implements FileIngestModule {
List<AbstractFile> unpackedFiles = unpack(abstractFile);
if (!unpackedFiles.isEmpty()) {
sendNewFilesEvent(abstractFile, unpackedFiles);
context.addFiles(unpackedFiles);
//currently sending a single event for all new files
services.fireModuleContentEvent(new ModuleContentEvent(abstractFile));
context.scheduleFiles(unpackedFiles);
}
return ProcessResult.OK;
@@ -190,10 +191,6 @@ public final class SevenZipIngestModule implements FileIngestModule {
refCounter.decrementAndGet(jobId);
}
private void sendNewFilesEvent(AbstractFile archive, List<AbstractFile> unpackedFiles) {
//currently sending a single event for all new files
services.fireModuleContentEvent(new ModuleContentEvent(archive));
}
/**
* Get local relative path to the unpacked archive root
@@ -212,7 +209,7 @@ public final class SevenZipIngestModule implements FileIngestModule {
* @return
*/
private String getLocalRootAbsPath(String localRootRelPath) {
return unpackDirPath + File.separator + localRootRelPath;
return moduleDirAbsolute + File.separator + localRootRelPath;
}
/**
@@ -315,8 +312,8 @@ public final class SevenZipIngestModule implements FileIngestModule {
final ISimpleInArchive simpleInArchive = inArchive.getSimpleInterface();
//setup the archive local root folder
final String uniqueFileName = getUniqueName(archiveFile);
final String localRootAbsPath = getLocalRootAbsPath(uniqueFileName);
final String uniqueArchiveFileName = getUniqueName(archiveFile);
final String localRootAbsPath = getLocalRootAbsPath(uniqueArchiveFileName);
final File localRoot = new File(localRootAbsPath);
if (!localRoot.exists()) {
try {
@@ -329,15 +326,16 @@ public final class SevenZipIngestModule implements FileIngestModule {
}
//initialize tree hierarchy to keep track of unpacked file structure
UnpackedTree uTree = new UnpackedTree(unpackDir + "/" + uniqueFileName, archiveFile, fileManager);
UnpackedTree unpackedTree = new UnpackedTree(moduleDirRelative + "/" + uniqueArchiveFileName, archiveFile);
long freeDiskSpace = services.getFreeDiskSpace();
//unpack and process every item in archive
int itemNumber = 0;
for (ISimpleInArchiveItem item : simpleInArchive.getArchiveItems()) {
String extractedPath = item.getPath();
if (extractedPath == null || extractedPath.isEmpty()) {
String pathInArchive = item.getPath();
if (pathInArchive == null || pathInArchive.isEmpty()) {
//some formats (.tar.gz) may not be handled correctly -- file in archive has no name/path
//handle this for .tar.gz and tgz but assuming the child is tar,
//otherwise, unpack using itemNumber as name
@@ -360,18 +358,18 @@ public final class SevenZipIngestModule implements FileIngestModule {
}
if (useName == null) {
extractedPath = "/" + archName + "/" + Integer.toString(itemNumber);
pathInArchive = "/" + archName + "/" + Integer.toString(itemNumber);
} else {
extractedPath = "/" + useName;
pathInArchive = "/" + useName;
}
String msg = NbBundle.getMessage(this.getClass(), "SevenZipIngestModule.unpack.unknownPath.msg",
archiveFile.getName(), extractedPath);
archiveFile.getName(), pathInArchive);
logger.log(Level.WARNING, msg);
}
++itemNumber;
logger.log(Level.INFO, "Extracted item path: {0}", extractedPath); //NON-NLS
logger.log(Level.INFO, "Extracted item path: {0}", pathInArchive); //NON-NLS
//check if possible zip bomb
if (isZipBombArchiveItemCheck(archiveFile.getName(), item)) {
@@ -379,9 +377,9 @@ public final class SevenZipIngestModule implements FileIngestModule {
}
//find this node in the hierarchy, create if needed
UnpackedTree.Data uNode = uTree.find(extractedPath);
UnpackedTree.UnpackedNode unpackedNode = unpackedTree.addNode(pathInArchive);
String fileName = uNode.getFileName();
String fileName = unpackedNode.getFileName();
//update progress bar
progress.progress(archiveFile.getName() + ": " + fileName, processedItems);
@@ -394,7 +392,7 @@ public final class SevenZipIngestModule implements FileIngestModule {
final boolean isDir = item.isFolder();
if (isEncrypted) {
logger.log(Level.WARNING, "Skipping encrypted file in archive: {0}", extractedPath); //NON-NLS
logger.log(Level.WARNING, "Skipping encrypted file in archive: {0}", pathInArchive); //NON-NLS
hasEncrypted = true;
continue;
} else {
@@ -423,9 +421,11 @@ public final class SevenZipIngestModule implements FileIngestModule {
}
}
final String localFileRelPath = uniqueFileName + File.separator + extractedPath;
final String uniqueExtractedName = uniqueArchiveFileName + File.separator + (item.getItemIndex() / 1000) + File.separator + item.getItemIndex() + new File(pathInArchive).getName();
//final String localRelPath = unpackDir + File.separator + localFileRelPath;
final String localAbsPath = unpackDirPath + File.separator + localFileRelPath;
final String localRelPath = moduleDirRelative + File.separator + uniqueExtractedName;
final String localAbsPath = moduleDirAbsolute + File.separator + uniqueExtractedName;
//create local dirs and empty files before extracted
File localFile = new java.io.File(localAbsPath);
@@ -443,10 +443,15 @@ public final class SevenZipIngestModule implements FileIngestModule {
}
}
} catch (SecurityException e) {
logger.log(Level.SEVERE, "Error setting up output path for unpacked file: {0}", extractedPath); //NON-NLS
logger.log(Level.SEVERE, "Error setting up output path for unpacked file: {0}", pathInArchive); //NON-NLS
//TODO consider bail out / msg to the user
}
}
// skip the rest of this loop if we couldn't create the file
if (localFile.exists() == false) {
continue;
}
final Date createTime = item.getCreationTime();
final Date accessTime = item.getLastAccessTime();
@@ -456,8 +461,8 @@ public final class SevenZipIngestModule implements FileIngestModule {
final long accesstime = accessTime == null ? 0L : accessTime.getTime() / 1000;
//record derived data in unode, to be traversed later after unpacking the archive
uNode.addDerivedInfo(size, !isDir,
0L, createtime, accesstime, modtime);
unpackedNode.addDerivedInfo(size, !isDir,
0L, createtime, accesstime, modtime, localRelPath);
//unpack locally if a file
if (!isDir) {
@@ -477,11 +482,13 @@ public final class SevenZipIngestModule implements FileIngestModule {
//update units for progress bar
++processedItems;
} //for every item in archive
}
// add them to the DB. We wait until the end so that we have the metadata on all of the
// intermediate nodes since the order is not guaranteed
try {
uTree.createDerivedFiles();
unpackedFiles = uTree.getAllFileObjects();
unpackedTree.addDerivedFilesToCase();
unpackedFiles = unpackedTree.getAllFileObjects();
//check if children are archives, update archive depth tracking
for (AbstractFile unpackedFile : unpackedFiles) {
@@ -658,7 +665,7 @@ public final class SevenZipIngestModule implements FileIngestModule {
}
/**
* Representation of local directory tree of unpacked archive. Used to track
* Representation of the files in the archive. Used to track
* of local tree file hierarchy, archive depth, and files created to easily
* and reliably get parent AbstractFile for unpacked file. So that we don't
* have to depend on type of traversal of unpacked files handed to us by
@@ -666,27 +673,30 @@ public final class SevenZipIngestModule implements FileIngestModule {
*/
private class UnpackedTree {
final String localPathRoot;
final Data root; //dummy root to hold children
final FileManager fileManager;
final UnpackedNode rootNode;
UnpackedTree(String localPathRoot, AbstractFile archiveRoot, FileManager fileManager) {
this.localPathRoot = localPathRoot;
this.fileManager = fileManager;
this.root = new Data();
this.root.setFile(archiveRoot);
this.root.setFileName(archiveRoot.getName());
this.root.localRelPath = localPathRoot;
/**
*
* @param localPathRoot Path in module output folder that files will be saved to
* @param archiveFile Archive file being extracted
* @param fileManager
*/
UnpackedTree(String localPathRoot, AbstractFile archiveFile) {
this.rootNode = new UnpackedNode();
this.rootNode.setFile(archiveFile);
this.rootNode.setFileName(archiveFile.getName());
this.rootNode.localRelPath = localPathRoot;
}
/**
* Tokenizes filePath passed in and traverses the dir structure,
* creating data nodes on the path way as needed
* Creates a node in the tree at the given path. Makes intermediate
* nodes if needed. If a node already exists at that path, it is
* returned.
*
* @param filePath file path with 1 or more tokens separated by /
* @return child node for the last file token in the filePath
*/
Data find(String filePath) {
UnpackedNode addNode(String filePath) {
String[] toks = filePath.split("[\\/\\\\]");
List<String> tokens = new ArrayList<>();
for (int i = 0; i < toks.length; ++i) {
@@ -694,28 +704,31 @@ public final class SevenZipIngestModule implements FileIngestModule {
tokens.add(toks[i]);
}
}
return find(root, tokens);
return addNode(rootNode, tokens);
}
/**
* recursive method that traverses the path
* recursive method that traverses the path
*
* @param tokenPath
* @return
*/
private Data find(Data parent, List<String> tokenPath) {
//base case
private UnpackedNode addNode(UnpackedNode parent, List<String> tokenPath) {
// we found all of the tokens
if (tokenPath.isEmpty()) {
return parent;
}
String childName = tokenPath.remove(0); //step towards base case
Data child = parent.getChild(childName);
// get the next name in the path and look it up
String childName = tokenPath.remove(0);
UnpackedNode child = parent.getChild(childName);
// create new node
if (child == null) {
child = new Data(childName, parent);
child = new UnpackedNode(childName, parent);
}
return find(child, tokenPath);
// go down one more level
return addNode(child, tokenPath);
}
/**
@@ -726,7 +739,7 @@ public final class SevenZipIngestModule implements FileIngestModule {
*/
List<AbstractFile> getRootFileObjects() {
List<AbstractFile> ret = new ArrayList<>();
for (Data child : root.children) {
for (UnpackedNode child : rootNode.children) {
ret.add(child.getFile());
}
return ret;
@@ -740,15 +753,15 @@ public final class SevenZipIngestModule implements FileIngestModule {
*/
List<AbstractFile> getAllFileObjects() {
List<AbstractFile> ret = new ArrayList<>();
for (Data child : root.children) {
for (UnpackedNode child : rootNode.children) {
getAllFileObjectsRec(ret, child);
}
return ret;
}
private void getAllFileObjectsRec(List<AbstractFile> list, Data parent) {
private void getAllFileObjectsRec(List<AbstractFile> list, UnpackedNode parent) {
list.add(parent.getFile());
for (Data child : parent.children) {
for (UnpackedNode child : parent.children) {
getAllFileObjectsRec(list, child);
}
}
@@ -757,27 +770,22 @@ public final class SevenZipIngestModule implements FileIngestModule {
* Traverse the tree top-down after unzipping is done and create derived
* files for the entire hierarchy
*/
void createDerivedFiles() throws TskCoreException {
for (Data child : root.children) {
createDerivedFilesRec(child);
void addDerivedFilesToCase() throws TskCoreException {
final FileManager fileManager = Case.getCurrentCase().getServices().getFileManager();
for (UnpackedNode child : rootNode.children) {
addDerivedFilesToCaseRec(child, fileManager);
}
}
private void createDerivedFilesRec(Data node) throws TskCoreException {
private void addDerivedFilesToCaseRec(UnpackedNode node, FileManager fileManager) throws TskCoreException {
final String fileName = node.getFileName();
final String localRelPath = node.getLocalRelPath();
final long size = node.getSize();
final boolean isFile = node.isIsFile();
final AbstractFile parent = node.getParent().getFile();
try {
DerivedFile df = fileManager.addDerivedFile(fileName, localRelPath, size,
DerivedFile df = fileManager.addDerivedFile(fileName, node.getLocalRelPath(), node.getSize(),
node.getCtime(), node.getCrtime(), node.getAtime(), node.getMtime(),
isFile, parent, "", ArchiveFileExtractorModuleFactory.getModuleName(), "", "");
node.isIsFile(), node.getParent().getFile(), "", ArchiveFileExtractorModuleFactory.getModuleName(), "", "");
node.setFile(df);
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error adding a derived file to db:" + fileName, ex); //NON-NLS
throw new TskCoreException(
@@ -786,31 +794,35 @@ public final class SevenZipIngestModule implements FileIngestModule {
}
//recurse
for (Data child : node.children) {
createDerivedFilesRec(child);
for (UnpackedNode child : node.children) {
addDerivedFilesToCaseRec(child, fileManager);
}
}
private class Data {
/**
* A node in the unpacked tree that represents a file or folder.
*/
private class UnpackedNode {
private String fileName;
private AbstractFile file;
private List<Data> children = new ArrayList<>();
private String localRelPath;
private List<UnpackedNode> children = new ArrayList<>();
private String localRelPath = "";
private long size;
private long ctime, crtime, atime, mtime;
private boolean isFile;
private Data parent;
private UnpackedNode parent;
//root constructor
Data() {
UnpackedNode() {
}
//child node constructor
Data(String fileName, Data parent) {
UnpackedNode(String fileName, UnpackedNode parent) {
this.fileName = fileName;
this.parent = parent;
this.localRelPath = parent.localRelPath + File.separator + fileName;
//this.localRelPath = parent.localRelPath + File.separator + fileName;
//new child derived file will be set by unpack() method
parent.children.add(this);
@@ -836,19 +848,20 @@ public final class SevenZipIngestModule implements FileIngestModule {
this.fileName = fileName;
}
Data getParent() {
UnpackedNode getParent() {
return parent;
}
void addDerivedInfo(long size,
boolean isFile,
long ctime, long crtime, long atime, long mtime) {
long ctime, long crtime, long atime, long mtime, String relLocalPath) {
this.size = size;
this.isFile = isFile;
this.ctime = ctime;
this.crtime = crtime;
this.atime = atime;
this.mtime = mtime;
this.localRelPath = relLocalPath;
}
void setFile(AbstractFile file) {
@@ -861,9 +874,9 @@ public final class SevenZipIngestModule implements FileIngestModule {
* @param childFileName
* @return
*/
Data getChild(String childFileName) {
Data ret = null;
for (Data child : children) {
UnpackedNode getChild(String childFileName) {
UnpackedNode ret = null;
for (UnpackedNode child : children) {
if (child.fileName.equals(childFileName)) {
ret = child;
break;

View File

@@ -2,7 +2,7 @@
*
* Autopsy Forensic Browser
*
* Copyright 2012 Basis Technology Corp.
* Copyright 2012-2014 Basis Technology Corp.
*
* Copyright 2012 42six Solutions.
* Contact: aebadirad <at> 42six <dot> com
@@ -25,8 +25,6 @@ package org.sleuthkit.autopsy.report;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JPanel;
@@ -151,11 +149,17 @@ import org.sleuthkit.datamodel.*;
logger.log(Level.WARNING, "Could not write the temp body file report.", ex); //NON-NLS
} finally {
try {
out.flush();
out.close();
if (out != null) {
out.flush();
out.close();
Case.getCurrentCase().addReport(reportPath, "TSK Body File", "");
}
} catch (IOException ex) {
logger.log(Level.WARNING, "Could not flush and close the BufferedWriter.", ex); //NON-NLS
}
} catch (TskCoreException ex) {
String errorMessage = String.format("Error adding %s to case as a report", reportPath); //NON-NLS
logger.log(Level.SEVERE, errorMessage, ex);
}
}
progressPanel.complete();
} catch(TskCoreException ex) {

View File

@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Copyright 2013-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,9 +26,11 @@ import java.util.logging.Level;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.TskCoreException;
class ReportExcel implements TableReportModule {
private static final Logger logger = Logger.getLogger(ReportExcel.class.getName());
@@ -110,8 +112,12 @@ import org.sleuthkit.autopsy.coreutils.Logger;
try {
out = new FileOutputStream(reportPath);
wb.write(out);
Case.getCurrentCase().addReport(reportPath, "Excel Report", "");
} catch (IOException ex) {
logger.log(Level.SEVERE, "Failed to write Excel report.", ex); //NON-NLS
} catch (TskCoreException ex) {
String errorMessage = String.format("Error adding %s to case as a report", reportPath); //NON-NLS
logger.log(Level.SEVERE, errorMessage, ex);
} finally {
if (out != null) {
try {

View File

@@ -2,7 +2,7 @@
*
* Autopsy Forensic Browser
*
* Copyright 2012 Basis Technology Corp.
* Copyright 2012-2014 Basis Technology Corp.
*
* Copyright 2012 42six Solutions.
* Contact: aebadirad <at> 42six <dot> com
@@ -32,6 +32,8 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -801,8 +803,9 @@ import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
*/
private void writeIndex() {
Writer indexOut = null;
String indexFilePath = path + "index.html";
try {
indexOut = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + "index.html"), "UTF-8")); //NON-NLS
indexOut = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(indexFilePath), "UTF-8")); //NON-NLS
StringBuilder index = new StringBuilder();
index.append("<head>\n<title>").append( //NON-NLS
NbBundle.getMessage(this.getClass(), "ReportHTML.writeIndex.title", currentCase.getName())).append(
@@ -818,8 +821,12 @@ import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
index.append("</frameset>\n"); //NON-NLS
index.append("</html>"); //NON-NLS
indexOut.write(index.toString());
Case.getCurrentCase().addReport(indexFilePath, "HTML Report", "");
} catch (IOException ex) {
logger.log(Level.SEVERE, "Error creating Writer for index.html: {0}", ex); //NON-NLS
} catch (TskCoreException ex) {
String errorMessage = String.format("Error adding %s to case as a report", indexFilePath); //NON-NLS
logger.log(Level.SEVERE, errorMessage, ex);
} finally {
try {
if(indexOut != null) {

View File

@@ -256,11 +256,13 @@ class ReportKML implements GeneralReportModule {
FileOutputStream writer = new FileOutputStream(reportPath);
outputter.output(kmlDocument, writer);
writer.close();
Case.getCurrentCase().addReport(reportPath, "KML Report", "");
} catch (IOException ex) {
logger.log(Level.WARNING, "Could not write the KML file.", ex); //NON-NLS
} catch (TskCoreException ex) {
String errorMessage = String.format("Error adding %s to case as a report", reportPath); //NON-NLS
logger.log(Level.SEVERE, errorMessage, ex);
}
} catch (IOException ex) {
logger.log(Level.WARNING, "Could not write the KML report.", ex); //NON-NLS
}

View File

@@ -1136,6 +1136,7 @@ public class Timeline extends CallableSystemAction implements Presenter.Toolbar,
logger.log(Level.SEVERE, "Could not clsoe writer after creating mactime file, encountered error ", ex); //NON-NLS
}
}
execUtil.stop();
}
return macfile;

View File

@@ -36,7 +36,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.Hash;
import org.sleuthkit.datamodel.HashUtility;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
@@ -50,7 +50,6 @@ public class HashDbIngestModule implements FileIngestModule {
private static final Logger logger = Logger.getLogger(HashDbIngestModule.class.getName());
private static final int MAX_COMMENT_SIZE = 500;
private final IngestServices services = IngestServices.getInstance();
private final Hash hasher = new Hash();
private final SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase();
private final HashDbManager hashDbManager = HashDbManager.getInstance();
private final HashLookupModuleSettings settings;
@@ -159,7 +158,7 @@ public class HashDbIngestModule implements FileIngestModule {
if (md5Hash == null || md5Hash.isEmpty()) {
try {
long calcstart = System.currentTimeMillis();
md5Hash = hasher.calculateMd5(file);
md5Hash = HashUtility.calculateMd5(file);
long delta = (System.currentTimeMillis() - calcstart);
totals.totalCalctime.addAndGet(delta);

View File

@@ -1,3 +1,6 @@
---------------- VERSION 3.0.10 --------------
Bug Fixes:
- Fixed 64-bit CRT dlls. No other logic changes.
---------------- VERSION 3.0.9 --------------
Bug Fixes:

View File

@@ -56,8 +56,6 @@ abstract class Extract {
void complete() {
}
void stop() {
}
/**
* Returns a List of string error messages from the inheriting class

View File

@@ -65,7 +65,6 @@ class ExtractIE extends Extract {
private String PASCO_LIB_PATH;
private String JAVA_PATH;
private static final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
private ExecUtil execPasco;
private Content dataSource;
private IngestJobContext context;
@@ -357,11 +356,11 @@ class ExtractIE extends Extract {
boolean success = true;
Writer writer = null;
ExecUtil execPasco = new ExecUtil();
try {
final String outputFileFullPath = moduleTempResultsDir + File.separator + outputFileName;
logger.log(Level.INFO, "Writing pasco results to: {0}", outputFileFullPath); //NON-NLS
writer = new FileWriter(outputFileFullPath);
execPasco = new ExecUtil();
execPasco.execute(writer, JAVA_PATH,
"-cp", PASCO_LIB_PATH, //NON-NLS
"isi.pasco2.Main", "-T", "history", indexFilePath ); //NON-NLS
@@ -382,6 +381,7 @@ class ExtractIE extends Extract {
logger.log(Level.WARNING, "Error closing writer stream after for Pasco result", ex); //NON-NLS
}
}
execPasco.stop();
}
return success;
}
@@ -515,12 +515,4 @@ class ExtractIE extends Extract {
}
fileScanner.close();
}
@Override
public void stop() {
if (execPasco != null) {
execPasco.stop();
execPasco = null;
}
}
}

View File

@@ -63,7 +63,7 @@ class ExtractRegistry extends Extract {
private boolean rrFound = false; // true if we found the Autopsy-specific version of regripper
private boolean rrFullFound = false; // true if we found the full version of regripper
final private static String MODULE_VERSION = "1.0";
private ExecUtil execRR;
private Content dataSource;
private IngestJobContext context;
@@ -300,6 +300,7 @@ class ExtractRegistry extends Extract {
if (!autopsyType.isEmpty() && rrFound) {
// TODO - add error messages
Writer writer = null;
ExecUtil execRR = null;
try {
regOutputFiles.autopsyPlugins = outFilePathBase + "-autopsy.txt"; //NON-NLS
logger.log(Level.INFO, "Writing RegRipper results to: " + regOutputFiles.autopsyPlugins); //NON-NLS
@@ -325,12 +326,16 @@ class ExtractRegistry extends Extract {
logger.log(Level.SEVERE, "Error closing output writer after running RegRipper", ex); //NON-NLS
}
}
if (execRR != null) {
execRR.stop();
}
}
}
// run the full set of rr modules
if (!fullType.isEmpty() && rrFullFound) {
Writer writer = null;
ExecUtil execRR = null;
try {
regOutputFiles.fullPlugins = outFilePathBase + "-full.txt"; //NON-NLS
logger.log(Level.INFO, "Writing Full RegRipper results to: " + regOutputFiles.fullPlugins); //NON-NLS
@@ -356,6 +361,9 @@ class ExtractRegistry extends Extract {
logger.log(Level.SEVERE, "Error closing output writer after running RegRipper full", ex); //NON-NLS
}
}
if (execRR != null) {
execRR.stop();
}
}
}
@@ -578,11 +586,4 @@ class ExtractRegistry extends Extract {
analyzeRegistryFiles();
}
@Override
public void stop() {
if (execRR != null) {
execRR.stop();
execRR = null;
}
}
}

View File

@@ -162,7 +162,6 @@ public final class RAImageIngestModule implements DataSourceIngestModule {
services.postMessage(inboxMsg);
if (context.isJobCancelled()) {
stop();
return ProcessResult.OK;
}
@@ -180,16 +179,7 @@ public final class RAImageIngestModule implements DataSourceIngestModule {
return ProcessResult.OK;
}
private void stop() {
for (Extract extracter : extracters) {
try {
extracter.stop();
} catch (Exception ex) {
logger.log(Level.SEVERE, "Exception during stop() of " + extracter.getName(), ex); //NON-NLS
}
}
logger.log(Level.INFO, "Recent Activity processes has been shutdown."); //NON-NLS
}
/**
* Get the temp path for a specific sub-module in recent activity. Will

View File

@@ -374,9 +374,4 @@ class SearchEngineURLQueryAnalyzer extends Extract {
public void complete() {
logger.info("Search Engine URL Query Analyzer has completed."); //NON-NLS
}
@Override
public void stop() {
logger.info("Attempted to stop Search Engine URL Query Analyzer, but operation is not supported; skipping..."); //NON-NLS
}
}

View File

@@ -223,7 +223,7 @@ class ScalpelCarverIngestModule implements FileIngestModule {
}
// reschedule carved files
context.addFiles(new ArrayList<AbstractFile>(carvedFiles));
context.scheduleFiles(new ArrayList<AbstractFile>(carvedFiles));
return ProcessResult.OK;
}

View File

@@ -1,5 +1,5 @@
#Updated by build script
#Sat, 03 May 2014 22:45:39 -0400
#Mon, 28 Apr 2014 01:45:18 -0400
LBL_splash_window_title=Starting Autopsy
SPLASH_HEIGHT=288
SPLASH_WIDTH=538

View File

@@ -1,5 +1,5 @@
#Updated by build script
#Sat, 03 May 2014 22:45:39 -0400
#Mon, 28 Apr 2014 01:45:18 -0400
CTL_MainWindow_Title=Autopsy 3.1.0_Beta
CTL_MainWindow_Title_No_Project=Autopsy 3.1.0_Beta

View File

@@ -289,7 +289,7 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
services.fireModuleContentEvent(new ModuleContentEvent(derived));
}
}
context.addFiles(derivedFiles);
context.scheduleFiles(derivedFiles);
services.fireModuleDataEvent(new ModuleDataEvent(EmailParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG));
}