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:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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:
|
||||
// \ / : * ? " < > |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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());
|
||||
|
||||
56
Core/src/org/sleuthkit/autopsy/coreutils/ErrorInfo.java
Executable file
56
Core/src/org/sleuthkit/autopsy/coreutils/ErrorInfo.java
Executable 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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
224
Core/src/org/sleuthkit/autopsy/datamodel/Reports.java
Executable file
224
Core/src/org/sleuthkit/autopsy/datamodel/Reports.java
Executable 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
49
Core/src/org/sleuthkit/autopsy/externalresults/ExternalResultsParser.java
Executable file
49
Core/src/org/sleuthkit/autopsy/externalresults/ExternalResultsParser.java
Executable 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();
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
BIN
Core/src/org/sleuthkit/autopsy/images/report_16.png
Executable file
BIN
Core/src/org/sleuthkit/autopsy/images/report_16.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 631 B |
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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>() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
3
NEWS.txt
3
NEWS.txt
@@ -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:
|
||||
|
||||
@@ -56,8 +56,6 @@ abstract class Extract {
|
||||
void complete() {
|
||||
}
|
||||
|
||||
void stop() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a List of string error messages from the inheriting class
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user